diff --git a/Serval.sln b/Serval.sln
index c850094d..b0db17fb 100644
--- a/Serval.sln
+++ b/Serval.sln
@@ -52,7 +52,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Serval.E2ETests", "tests\Se
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Serval.DataFiles.Tests", "tests\Serval.DataFiles.Tests\Serval.DataFiles.Tests.csproj", "{63E4D71B-11BE-4D68-A876-5B1B5F0A4C88}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SIL.DataAccess.Tests", "tests\SIL.DataAccess.Tests\SIL.DataAccess.Tests.csproj", "{71151518-8774-44D0-8E69-D77FA447BEFA}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SIL.DataAccess.Tests", "tests\SIL.DataAccess.Tests\SIL.DataAccess.Tests.csproj", "{71151518-8774-44D0-8E69-D77FA447BEFA}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Serval.Shared.Tests", "tests\Serval.Shared.Tests\Serval.Shared.Tests.csproj", "{0E220C65-AA88-450E-AFB2-844E49060B3F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -120,6 +122,10 @@ Global
{71151518-8774-44D0-8E69-D77FA447BEFA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{71151518-8774-44D0-8E69-D77FA447BEFA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{71151518-8774-44D0-8E69-D77FA447BEFA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0E220C65-AA88-450E-AFB2-844E49060B3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0E220C65-AA88-450E-AFB2-844E49060B3F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0E220C65-AA88-450E-AFB2-844E49060B3F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0E220C65-AA88-450E-AFB2-844E49060B3F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -140,6 +146,7 @@ Global
{1F020042-D7B8-4541-9691-26ECFD1FFC73} = {66246A1C-8D45-40FB-A660-C58577122CA7}
{63E4D71B-11BE-4D68-A876-5B1B5F0A4C88} = {66246A1C-8D45-40FB-A660-C58577122CA7}
{71151518-8774-44D0-8E69-D77FA447BEFA} = {66246A1C-8D45-40FB-A660-C58577122CA7}
+ {0E220C65-AA88-450E-AFB2-844E49060B3F} = {66246A1C-8D45-40FB-A660-C58577122CA7}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9F18C25E-E140-43C3-B177-D562E1628370}
diff --git a/src/Serval.ApiServer/Templates/Client.Class.ProcessResponse.liquid b/src/Serval.ApiServer/Templates/Client.Class.ProcessResponse.liquid
new file mode 100644
index 00000000..603ac78a
--- /dev/null
+++ b/src/Serval.ApiServer/Templates/Client.Class.ProcessResponse.liquid
@@ -0,0 +1,72 @@
+{% if response.HasType -%}
+{% if response.IsFile -%}
+{% if response.IsSuccess -%}
+var responseStream_ = response_.Content == null ? System.IO.Stream.Null : await response_.Content.ReadAsStreamAsync().ConfigureAwait(false);
+var fileResponse_ = new FileResponse(status_, headers_, responseStream_, {% if InjectHttpClient or DisposeHttpClient == false %}null{% else %}client_{% endif %}, response_);
+disposeClient_ = false; disposeResponse_ = false; // response and client are disposed by FileResponse
+return fileResponse_;
+{% else -%}
+var objectResponse_ = await ReadObjectResponseAsync<{{ response.Type }}>(response_, headers_, cancellationToken).ConfigureAwait(false);
+throw new {{ ExceptionClass }}<{{ response.Type }}>("{{ response.ExceptionDescription }}", status_, objectResponse_.Text, headers_, objectResponse_.Object, null);
+{% endif -%}
+{% elsif response.IsPlainText or operation.Produces == "text/plain" -%}
+var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
+var result_ = ({{ response.Type }})System.Convert.ChangeType(responseData_, typeof({{ response.Type }}));
+{% if response.IsSuccess -%}
+{% if operation.WrapResponse -%}
+return new {{ ResponseClass }}<{{ operation.UnwrappedResultType }}>(status_, headers_, result_);
+{% else -%}
+return result_;
+{% endif -%}
+{% else -%}
+throw new {{ ExceptionClass }}<{{ response.Type }}>("{{ response.ExceptionDescription }}", status_, responseData_, headers_, result_, null);
+{% endif -%}
+{% else -%}
+var objectResponse_ = await ReadObjectResponseAsync<{{ response.Type }}>(response_, headers_, cancellationToken).ConfigureAwait(false);
+{% if response.IsNullable == false -%}
+if (objectResponse_.Object == null)
+{
+ throw new {{ ExceptionClass }}("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
+}
+{% endif -%}
+{% if response.IsSuccess -%}
+{% if operation.WrapResponse -%}
+return new {{ ResponseClass }}<{{ operation.UnwrappedResultType }}>(status_, headers_, objectResponse_.Object);
+{% else -%}
+return objectResponse_.Object;
+{% endif -%}
+{% endif -%}
+{% if response.IsSuccess == false -%}
+{% if response.InheritsExceptionSchema -%}
+var responseObject_ = objectResponse_.Object != null ? objectResponse_.Object : new {{ response.Type }}();
+responseObject_.Data.Add("HttpStatus", status_.ToString());
+responseObject_.Data.Add("HttpHeaders", headers_);
+responseObject_.Data.Add("HttpResponse", objectResponse_.Text);
+{% if WrapDtoExceptions -%}
+throw new {{ ExceptionClass }}("{{ response.ExceptionDescription }}", status_, objectResponse_.Text, headers_, responseObject_);
+{% else -%}
+throw responseObject_;
+{% endif -%}
+{% else -%}
+throw new {{ ExceptionClass }}<{{ response.Type }}>("{{ response.ExceptionDescription }}", status_, objectResponse_.Text, headers_, objectResponse_.Object, null);
+{% endif -%}
+{% endif -%}
+{% endif -%}
+{% elsif response.IsSuccess -%}
+{% if operation.HasResultType -%}
+{% if operation.WrapResponse -%}
+return new {{ ResponseClass }}<{{ operation.UnwrappedResultType }}>(status_, headers_, {{ operation.UnwrappedResultDefaultValue }});
+{% else -%}
+return {{ operation.UnwrappedResultDefaultValue }};
+{% endif -%}
+{% else -%}
+{% if operation.WrapResponse -%}
+return new {{ ResponseClass }}(status_, headers_);
+{% else -%}
+return;
+{% endif -%}
+{% endif -%}
+{% else -%}{% comment %} implied: `if !response.HasType` so just read it as text {% endcomment %}
+string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
+throw new {{ ExceptionClass }}("{{ response.ExceptionDescription }}", status_, responseText_, headers_, null);
+{% endif %}
\ No newline at end of file
diff --git a/src/Serval.ApiServer/nswag.json b/src/Serval.ApiServer/nswag.json
index a81c442e..615e17bf 100644
--- a/src/Serval.ApiServer/nswag.json
+++ b/src/Serval.ApiServer/nswag.json
@@ -4,6 +4,7 @@
"documentGenerator": {
"aspNetCoreToOpenApi": {
"project": "Serval.ApiServer.csproj",
+ "documentName": "v1",
"msBuildProjectExtensionsPath": null,
"configuration": null,
"runtime": null,
@@ -12,52 +13,9 @@
"msBuildOutputPath": null,
"verbose": true,
"workingDirectory": null,
- "requireParametersWithoutDefault": false,
- "apiGroupNames": null,
- "defaultPropertyNameHandling": "Default",
- "defaultReferenceTypeNullHandling": "Null",
- "defaultDictionaryValueReferenceTypeNullHandling": "NotNull",
- "defaultResponseReferenceTypeNullHandling": "NotNull",
- "generateOriginalParameterNames": true,
- "defaultEnumHandling": "Integer",
- "flattenInheritanceHierarchy": false,
- "generateKnownTypes": true,
- "generateEnumMappingDescription": false,
- "generateXmlObjects": false,
- "generateAbstractProperties": false,
- "generateAbstractSchemas": true,
- "ignoreObsoleteProperties": false,
- "allowReferencesWithProperties": false,
- "useXmlDocumentation": true,
- "resolveExternalXmlDocumentation": true,
- "excludedTypeNames": [],
- "serviceHost": null,
- "serviceBasePath": null,
- "serviceSchemes": [],
- "infoTitle": "My Title",
- "infoDescription": null,
- "infoVersion": "1.0.0",
- "documentTemplate": null,
- "documentProcessorTypes": [],
- "operationProcessorTypes": [],
- "typeNameGeneratorType": null,
- "schemaNameGeneratorType": null,
- "contractResolverType": null,
- "serializerSettingsType": null,
- "useDocumentProvider": true,
- "documentName": "v1",
"aspNetCoreEnvironment": "Development",
- "createWebHostBuilderMethod": null,
- "startupType": null,
- "allowNullableBodyParameters": true,
- "useHttpAttributeNameAsOperationId": false,
"output": null,
- "outputType": "Swagger2",
- "newLineBehavior": "Auto",
- "assemblyPaths": [],
- "assemblyConfig": null,
- "referencePaths": [],
- "useNuGetCache": false
+ "newLineBehavior": "Auto"
}
},
"codeGenerators": {
@@ -65,7 +23,9 @@
"clientBaseClass": null,
"configurationClass": null,
"generateClientClasses": true,
+ "suppressClientClassesOutput": false,
"generateClientInterfaces": true,
+ "suppressClientInterfacesOutput": false,
"clientBaseInterface": null,
"injectHttpClient": true,
"disposeHttpClient": true,
@@ -83,6 +43,8 @@
"exposeJsonSerializerSettings": false,
"clientClassAccessModifier": "public",
"typeAccessModifier": "public",
+ "propertySetterAccessModifier": "",
+ "generateNativeRecords": false,
"generateContractsOutput": false,
"contractsNamespace": null,
"contractsOutputFilePath": null,
@@ -138,10 +100,7 @@
"generateDtoTypes": true,
"generateOptionalPropertiesAsNullable": false,
"generateNullableReferenceTypes": true,
- "templateDirectory": null,
- "typeNameGeneratorType": null,
- "propertyNameGeneratorType": null,
- "enumNameGeneratorType": null,
+ "templateDirectory": "Templates",
"serviceHost": null,
"serviceSchemes": null,
"output": "../Serval.Client/Client.g.cs",
diff --git a/src/Serval.Client/Client.g.cs b/src/Serval.Client/Client.g.cs
index 8d5808c2..65b76d18 100644
--- a/src/Serval.Client/Client.g.cs
+++ b/src/Serval.Client/Client.g.cs
@@ -1382,7 +1382,7 @@ public partial interface ITranslationEnginesClient
///
}
///
/// The translation engine configuration (see above)
- /// The translation engine was created successfully
+ /// The new translation engine
/// A server side error occurred.
System.Threading.Tasks.Task CreateAsync(TranslationEngineConfig engineConfig, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
@@ -1400,7 +1400,7 @@ public partial interface ITranslationEnginesClient
/// Delete a translation engine
///
/// The translation engine id
- /// The engine was successfully deleted
+ /// The engine was successfully deleted.
/// A server side error occurred.
System.Threading.Tasks.Task DeleteAsync(string id, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
@@ -1446,7 +1446,7 @@ public partial interface ITranslationEnginesClient
///
/// The translation engine id
/// The segment pair
- /// The engine was trained successfully
+ /// The engine was trained successfully.
/// A server side error occurred.
System.Threading.Tasks.Task TrainSegmentAsync(string id, SegmentPair segmentPair, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
@@ -1473,7 +1473,7 @@ public partial interface ITranslationEnginesClient
///
/// The translation engine id
/// The corpus configuration (see remarks)
- /// The corpus was added successfully
+ /// The added corpus
/// A server side error occurred.
System.Threading.Tasks.Task AddCorpusAsync(string id, TranslationCorpusConfig corpusConfig, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
@@ -1491,8 +1491,8 @@ public partial interface ITranslationEnginesClient
/// Update a corpus with a new set of files
///
///
- /// See posting a new corpus for details of use. Will completely replace corpus' file associations.
- ///
Will not affect jobs already queued or running. Will not affect existing pretranslations until new build is complete.
+ /// See posting a new corpus for details of use. Will completely replace corpus' file associations.
+ ///
Will not affect jobs already queued or running. Will not affect existing pretranslations until new build is complete.
///
/// The translation engine id
/// The corpus id
@@ -1520,7 +1520,7 @@ public partial interface ITranslationEnginesClient
///
/// The translation engine id
/// The corpus id
- /// The data file was deleted successfully
+ /// The data file was deleted successfully.
/// A server side error occurred.
System.Threading.Tasks.Task DeleteCorpusAsync(string id, string corpusId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
@@ -1545,6 +1545,41 @@ public partial interface ITranslationEnginesClient
/// A server side error occurred.
System.Threading.Tasks.Task> GetAllPretranslationsAsync(string id, string corpusId, string? textId = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
+ /// A cancellation token that can be used by other objects or threads to receive notice of cancellation.
+ ///
+ /// Get all pretranslations for the specified text in a corpus of a translation engine
+ ///
+ ///
+ /// Pretranslations are arranged in a list of dictionaries with the following fields per pretranslation:
+ ///
* **TextId**: The TextId of the SourceFile defined when the corpus was created.
+ ///
* **Refs** (a list of strings): A list of references including:
+ ///
* The references defined in the SourceFile per line, if any.
+ ///
* An auto-generated reference of `[TextId]:[lineNumber]`, 1 indexed.
+ ///
* **Translation**: the text of the pretranslation
+ ///
+ /// The translation engine id
+ /// The corpus id
+ /// The text id
+ /// The pretranslations
+ /// A server side error occurred.
+ System.Threading.Tasks.Task> GetPretranslationsByTextIdAsync(string id, string corpusId, string textId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
+
+ /// A cancellation token that can be used by other objects or threads to receive notice of cancellation.
+ ///
+ /// Get a pretranslated Scripture book in USFM format.
+ ///
+ ///
+ /// If the USFM book exists in the target corpus, then the pretranslated text will be inserted into any empty
+ ///
segments in the the target book and returned. If the USFM book does not exist in the target corpus, then the
+ ///
pretranslated text will be inserted into an empty template created from the source USFM book and returned.
+ ///
+ /// The translation engine id
+ /// The corpus id
+ /// The text id
+ /// The book in USFM format
+ /// A server side error occurred.
+ System.Threading.Tasks.Task GetPretranslatedUsfmAsync(string id, string corpusId, string textId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
+
/// A cancellation token that can be used by other objects or threads to receive notice of cancellation.
///
/// Get all build jobs for a translation engine
@@ -1576,7 +1611,7 @@ public partial interface ITranslationEnginesClient
///
/// The translation engine id
/// The build config (see remarks)
- /// The build job was started successfully
+ /// The new build job
/// A server side error occurred.
System.Threading.Tasks.Task StartBuildAsync(string id, TranslationBuildConfig buildConfig, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
@@ -1619,7 +1654,7 @@ public partial interface ITranslationEnginesClient
/// Cancel the current build job (whether pending or active) for a translation engine
///
/// The translation engine id
- /// The build job was cancelled successfully
+ /// The build job was cancelled successfully.
/// A server side error occurred.
System.Threading.Tasks.Task CancelBuildAsync(string id, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
@@ -1724,19 +1759,19 @@ public string BaseUrl
if (status_ == 401)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The client is not authenticated", status_, responseText_, headers_, null);
+ throw new ServalApiException("The client is not authenticated.", status_, responseText_, headers_, null);
}
else
if (status_ == 403)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The authenticated client cannot perform the operation", status_, responseText_, headers_, null);
+ throw new ServalApiException("The authenticated client cannot perform the operation.", status_, responseText_, headers_, null);
}
else
if (status_ == 503)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details. ", status_, responseText_, headers_, null);
+ throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details.", status_, responseText_, headers_, null);
}
else
{
@@ -1790,7 +1825,7 @@ public string BaseUrl
///
}
///
/// The translation engine configuration (see above)
- /// The translation engine was created successfully
+ /// The new translation engine
/// A server side error occurred.
public virtual async System.Threading.Tasks.Task CreateAsync(TranslationEngineConfig engineConfig, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
{
@@ -1851,31 +1886,25 @@ public string BaseUrl
if (status_ == 400)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("Bad request. Is the engine type correct?", status_, responseText_, headers_, null);
+ throw new ServalApiException("Bad request. Is the engine type correct?", status_, responseText_, headers_, null);
}
else
if (status_ == 401)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The client is not authenticated", status_, responseText_, headers_, null);
+ throw new ServalApiException("The client is not authenticated.", status_, responseText_, headers_, null);
}
else
if (status_ == 403)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The authenticated client cannot perform the operation or does not own the translation engine", status_, responseText_, headers_, null);
- }
- else
- if (status_ == 422)
- {
- string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The engine was specified incorrectly. Did you use the same language for the source and target?", status_, responseText_, headers_, null);
+ throw new ServalApiException("The authenticated client cannot perform the operation or does not own the translation engine.", status_, responseText_, headers_, null);
}
else
if (status_ == 503)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details. ", status_, responseText_, headers_, null);
+ throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details.", status_, responseText_, headers_, null);
}
else
{
@@ -1960,25 +1989,25 @@ public string BaseUrl
if (status_ == 401)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The client is not authenticated", status_, responseText_, headers_, null);
+ throw new ServalApiException("The client is not authenticated.", status_, responseText_, headers_, null);
}
else
if (status_ == 403)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The authenticated client cannot perform the operation or does not own the translation engine", status_, responseText_, headers_, null);
+ throw new ServalApiException("The authenticated client cannot perform the operation or does not own the translation engine.", status_, responseText_, headers_, null);
}
else
if (status_ == 404)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The engine does not exist", status_, responseText_, headers_, null);
+ throw new ServalApiException("The engine does not exist.", status_, responseText_, headers_, null);
}
else
if (status_ == 503)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details. ", status_, responseText_, headers_, null);
+ throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details.", status_, responseText_, headers_, null);
}
else
{
@@ -2005,7 +2034,7 @@ public string BaseUrl
/// Delete a translation engine
///
/// The translation engine id
- /// The engine was successfully deleted
+ /// The engine was successfully deleted.
/// A server side error occurred.
public virtual async System.Threading.Tasks.Task DeleteAsync(string id, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
{
@@ -2057,25 +2086,25 @@ public string BaseUrl
if (status_ == 401)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The client is not authenticated", status_, responseText_, headers_, null);
+ throw new ServalApiException("The client is not authenticated.", status_, responseText_, headers_, null);
}
else
if (status_ == 403)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The authenticated client cannot perform the operation or does not own the translation engine", status_, responseText_, headers_, null);
+ throw new ServalApiException("The authenticated client cannot perform the operation or does not own the translation engine.", status_, responseText_, headers_, null);
}
else
if (status_ == 404)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The engine does not exist and therefore cannot be deleted", status_, responseText_, headers_, null);
+ throw new ServalApiException("The engine does not exist and therefore cannot be deleted.", status_, responseText_, headers_, null);
}
else
if (status_ == 503)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details. ", status_, responseText_, headers_, null);
+ throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details.", status_, responseText_, headers_, null);
}
else
{
@@ -2175,37 +2204,37 @@ public string BaseUrl
if (status_ == 401)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The client is not authenticated", status_, responseText_, headers_, null);
+ throw new ServalApiException("The client is not authenticated.", status_, responseText_, headers_, null);
}
else
if (status_ == 403)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The authenticated client cannot perform the operation or does not own the translation engine", status_, responseText_, headers_, null);
+ throw new ServalApiException("The authenticated client cannot perform the operation or does not own the translation engine.", status_, responseText_, headers_, null);
}
else
if (status_ == 404)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The engine does not exist", status_, responseText_, headers_, null);
+ throw new ServalApiException("The engine does not exist.", status_, responseText_, headers_, null);
}
else
if (status_ == 405)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The method is not supported", status_, responseText_, headers_, null);
+ throw new ServalApiException("The method is not supported.", status_, responseText_, headers_, null);
}
else
if (status_ == 409)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The engine needs to be built before it can translate segments", status_, responseText_, headers_, null);
+ throw new ServalApiException("The engine needs to be built before it can translate segments.", status_, responseText_, headers_, null);
}
else
if (status_ == 503)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details. ", status_, responseText_, headers_, null);
+ throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details.", status_, responseText_, headers_, null);
}
else
{
@@ -2310,37 +2339,37 @@ public string BaseUrl
if (status_ == 401)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The client is not authenticated", status_, responseText_, headers_, null);
+ throw new ServalApiException("The client is not authenticated.", status_, responseText_, headers_, null);
}
else
if (status_ == 403)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The authenticated client cannot perform the operation or does not own the translation engine", status_, responseText_, headers_, null);
+ throw new ServalApiException("The authenticated client cannot perform the operation or does not own the translation engine.", status_, responseText_, headers_, null);
}
else
if (status_ == 404)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The engine does not exist", status_, responseText_, headers_, null);
+ throw new ServalApiException("The engine does not exist.", status_, responseText_, headers_, null);
}
else
if (status_ == 405)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The method is not supported", status_, responseText_, headers_, null);
+ throw new ServalApiException("The method is not supported.", status_, responseText_, headers_, null);
}
else
if (status_ == 409)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The engine needs to be built before it can translate segments", status_, responseText_, headers_, null);
+ throw new ServalApiException("The engine needs to be built before it can translate segments.", status_, responseText_, headers_, null);
}
else
if (status_ == 503)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details. ", status_, responseText_, headers_, null);
+ throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details.", status_, responseText_, headers_, null);
}
else
{
@@ -2440,37 +2469,37 @@ public string BaseUrl
if (status_ == 401)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The client is not authenticated", status_, responseText_, headers_, null);
+ throw new ServalApiException("The client is not authenticated.", status_, responseText_, headers_, null);
}
else
if (status_ == 403)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The authenticated client cannot perform the operation or does not own the translation engine", status_, responseText_, headers_, null);
+ throw new ServalApiException("The authenticated client cannot perform the operation or does not own the translation engine.", status_, responseText_, headers_, null);
}
else
if (status_ == 404)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The engine does not exist", status_, responseText_, headers_, null);
+ throw new ServalApiException("The engine does not exist.", status_, responseText_, headers_, null);
}
else
if (status_ == 405)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The method is not supported", status_, responseText_, headers_, null);
+ throw new ServalApiException("The method is not supported.", status_, responseText_, headers_, null);
}
else
if (status_ == 409)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The engine needs to be built first", status_, responseText_, headers_, null);
+ throw new ServalApiException("The engine needs to be built first.", status_, responseText_, headers_, null);
}
else
if (status_ == 503)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details. ", status_, responseText_, headers_, null);
+ throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details.", status_, responseText_, headers_, null);
}
else
{
@@ -2503,7 +2532,7 @@ public string BaseUrl
///
/// The translation engine id
/// The segment pair
- /// The engine was trained successfully
+ /// The engine was trained successfully.
/// A server side error occurred.
public virtual async System.Threading.Tasks.Task TrainSegmentAsync(string id, SegmentPair segmentPair, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
{
@@ -2569,37 +2598,37 @@ public string BaseUrl
if (status_ == 401)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The client is not authenticated", status_, responseText_, headers_, null);
+ throw new ServalApiException("The client is not authenticated.", status_, responseText_, headers_, null);
}
else
if (status_ == 403)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The authenticated client cannot perform the operation or does not own the translation engine", status_, responseText_, headers_, null);
+ throw new ServalApiException("The authenticated client cannot perform the operation or does not own the translation engine.", status_, responseText_, headers_, null);
}
else
if (status_ == 404)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The engine does not exist", status_, responseText_, headers_, null);
+ throw new ServalApiException("The engine does not exist.", status_, responseText_, headers_, null);
}
else
if (status_ == 405)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The method is not supported", status_, responseText_, headers_, null);
+ throw new ServalApiException("The method is not supported.", status_, responseText_, headers_, null);
}
else
if (status_ == 409)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The engine needs to be built first", status_, responseText_, headers_, null);
+ throw new ServalApiException("The engine needs to be built first.", status_, responseText_, headers_, null);
}
else
if (status_ == 503)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details. ", status_, responseText_, headers_, null);
+ throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details.", status_, responseText_, headers_, null);
}
else
{
@@ -2644,7 +2673,7 @@ public string BaseUrl
///
/// The translation engine id
/// The corpus configuration (see remarks)
- /// The corpus was added successfully
+ /// The added corpus
/// A server side error occurred.
public virtual async System.Threading.Tasks.Task AddCorpusAsync(string id, TranslationCorpusConfig corpusConfig, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
{
@@ -2716,31 +2745,25 @@ public string BaseUrl
if (status_ == 401)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The client is not authenticated", status_, responseText_, headers_, null);
+ throw new ServalApiException("The client is not authenticated.", status_, responseText_, headers_, null);
}
else
if (status_ == 403)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The authenticated client cannot perform the operation or does not own the translation engine", status_, responseText_, headers_, null);
+ throw new ServalApiException("The authenticated client cannot perform the operation or does not own the translation engine.", status_, responseText_, headers_, null);
}
else
if (status_ == 404)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The engine does not exist", status_, responseText_, headers_, null);
- }
- else
- if (status_ == 422)
- {
- string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The engine was specified incorrectly. Did you use the same language for the source and target?", status_, responseText_, headers_, null);
+ throw new ServalApiException("The engine does not exist.", status_, responseText_, headers_, null);
}
else
if (status_ == 503)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details. ", status_, responseText_, headers_, null);
+ throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details.", status_, responseText_, headers_, null);
}
else
{
@@ -2871,8 +2894,8 @@ public string BaseUrl
/// Update a corpus with a new set of files
///
///
- /// See posting a new corpus for details of use. Will completely replace corpus' file associations.
- ///
Will not affect jobs already queued or running. Will not affect existing pretranslations until new build is complete.
+ /// See posting a new corpus for details of use. Will completely replace corpus' file associations.
+ ///
Will not affect jobs already queued or running. Will not affect existing pretranslations until new build is complete.
///
/// The translation engine id
/// The corpus id
@@ -2953,25 +2976,25 @@ public string BaseUrl
if (status_ == 401)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The client is not authenticated", status_, responseText_, headers_, null);
+ throw new ServalApiException("The client is not authenticated.", status_, responseText_, headers_, null);
}
else
if (status_ == 403)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The authenticated client cannot perform the operation or does not own the translation engine", status_, responseText_, headers_, null);
+ throw new ServalApiException("The authenticated client cannot perform the operation or does not own the translation engine.", status_, responseText_, headers_, null);
}
else
if (status_ == 404)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The engine or corpus does not exist", status_, responseText_, headers_, null);
+ throw new ServalApiException("The engine or corpus does not exist.", status_, responseText_, headers_, null);
}
else
if (status_ == 503)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details. ", status_, responseText_, headers_, null);
+ throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details.", status_, responseText_, headers_, null);
}
else
{
@@ -3062,25 +3085,25 @@ public string BaseUrl
if (status_ == 401)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The client is not authenticated", status_, responseText_, headers_, null);
+ throw new ServalApiException("The client is not authenticated.", status_, responseText_, headers_, null);
}
else
if (status_ == 403)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The authenticated client cannot perform the operation or does not own the translation engine", status_, responseText_, headers_, null);
+ throw new ServalApiException("The authenticated client cannot perform the operation or does not own the translation engine.", status_, responseText_, headers_, null);
}
else
if (status_ == 404)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The engine or corpus does not exist", status_, responseText_, headers_, null);
+ throw new ServalApiException("The engine or corpus does not exist.", status_, responseText_, headers_, null);
}
else
if (status_ == 503)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details. ", status_, responseText_, headers_, null);
+ throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details.", status_, responseText_, headers_, null);
}
else
{
@@ -3111,7 +3134,7 @@ public string BaseUrl
///
/// The translation engine id
/// The corpus id
- /// The data file was deleted successfully
+ /// The data file was deleted successfully.
/// A server side error occurred.
public virtual async System.Threading.Tasks.Task DeleteCorpusAsync(string id, string corpusId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
{
@@ -3168,25 +3191,25 @@ public string BaseUrl
if (status_ == 401)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The client is not authenticated", status_, responseText_, headers_, null);
+ throw new ServalApiException("The client is not authenticated.", status_, responseText_, headers_, null);
}
else
if (status_ == 403)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The authenticated client cannot perform the operation or does not own the translation engine", status_, responseText_, headers_, null);
+ throw new ServalApiException("The authenticated client cannot perform the operation or does not own the translation engine.", status_, responseText_, headers_, null);
}
else
if (status_ == 404)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The engine or corpus does not exist", status_, responseText_, headers_, null);
+ throw new ServalApiException("The engine or corpus does not exist.", status_, responseText_, headers_, null);
}
else
if (status_ == 503)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details. ", status_, responseText_, headers_, null);
+ throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details.", status_, responseText_, headers_, null);
}
else
{
@@ -3293,6 +3316,271 @@ public string BaseUrl
}
else
if (status_ == 401)
+ {
+ string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
+ throw new ServalApiException("The client is not authenticated.", status_, responseText_, headers_, null);
+ }
+ else
+ if (status_ == 403)
+ {
+ string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
+ throw new ServalApiException("The authenticated client cannot perform the operation or does not own the translation engine.", status_, responseText_, headers_, null);
+ }
+ else
+ if (status_ == 404)
+ {
+ string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
+ throw new ServalApiException("The engine or corpus does not exist.", status_, responseText_, headers_, null);
+ }
+ else
+ if (status_ == 409)
+ {
+ string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
+ throw new ServalApiException("The engine needs to be built first.", status_, responseText_, headers_, null);
+ }
+ else
+ if (status_ == 503)
+ {
+ string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
+ throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details.", status_, responseText_, headers_, null);
+ }
+ else
+ {
+ var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
+ throw new ServalApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
+ }
+ }
+ finally
+ {
+ if (disposeResponse_)
+ response_.Dispose();
+ }
+ }
+ }
+ finally
+ {
+ if (disposeClient_)
+ client_.Dispose();
+ }
+ }
+
+ /// A cancellation token that can be used by other objects or threads to receive notice of cancellation.
+ ///
+ /// Get all pretranslations for the specified text in a corpus of a translation engine
+ ///
+ ///
+ /// Pretranslations are arranged in a list of dictionaries with the following fields per pretranslation:
+ ///
* **TextId**: The TextId of the SourceFile defined when the corpus was created.
+ ///
* **Refs** (a list of strings): A list of references including:
+ ///
* The references defined in the SourceFile per line, if any.
+ ///
* An auto-generated reference of `[TextId]:[lineNumber]`, 1 indexed.
+ ///
* **Translation**: the text of the pretranslation
+ ///
+ /// The translation engine id
+ /// The corpus id
+ /// The text id
+ /// The pretranslations
+ /// A server side error occurred.
+ public virtual async System.Threading.Tasks.Task> GetPretranslationsByTextIdAsync(string id, string corpusId, string textId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
+ {
+ if (id == null)
+ throw new System.ArgumentNullException("id");
+
+ if (corpusId == null)
+ throw new System.ArgumentNullException("corpusId");
+
+ if (textId == null)
+ throw new System.ArgumentNullException("textId");
+
+ var client_ = _httpClient;
+ var disposeClient_ = false;
+ try
+ {
+ using (var request_ = new System.Net.Http.HttpRequestMessage())
+ {
+ request_.Method = new System.Net.Http.HttpMethod("GET");
+ request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json"));
+
+ var urlBuilder_ = new System.Text.StringBuilder();
+ if (!string.IsNullOrEmpty(BaseUrl)) urlBuilder_.Append(BaseUrl);
+ // Operation Path: "translation/engines/{id}/corpora/{corpusId}/pretranslations/{textId}"
+ urlBuilder_.Append("translation/engines/");
+ urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(id, System.Globalization.CultureInfo.InvariantCulture)));
+ urlBuilder_.Append("/corpora/");
+ urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(corpusId, System.Globalization.CultureInfo.InvariantCulture)));
+ urlBuilder_.Append("/pretranslations/");
+ urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(textId, System.Globalization.CultureInfo.InvariantCulture)));
+
+ PrepareRequest(client_, request_, urlBuilder_);
+
+ var url_ = urlBuilder_.ToString();
+ request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
+
+ PrepareRequest(client_, request_, url_);
+
+ var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
+ var disposeResponse_ = true;
+ try
+ {
+ var headers_ = new System.Collections.Generic.Dictionary>();
+ foreach (var item_ in response_.Headers)
+ headers_[item_.Key] = item_.Value;
+ if (response_.Content != null && response_.Content.Headers != null)
+ {
+ foreach (var item_ in response_.Content.Headers)
+ headers_[item_.Key] = item_.Value;
+ }
+
+ ProcessResponse(client_, response_);
+
+ var status_ = (int)response_.StatusCode;
+ if (status_ == 200)
+ {
+ var objectResponse_ = await ReadObjectResponseAsync>(response_, headers_, cancellationToken).ConfigureAwait(false);
+ if (objectResponse_.Object == null)
+ {
+ throw new ServalApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
+ }
+ return objectResponse_.Object;
+ }
+ else
+ if (status_ == 401)
+ {
+ string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
+ throw new ServalApiException("The client is not authenticated.", status_, responseText_, headers_, null);
+ }
+ else
+ if (status_ == 403)
+ {
+ string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
+ throw new ServalApiException("The authenticated client cannot perform the operation or does not own the translation engine.", status_, responseText_, headers_, null);
+ }
+ else
+ if (status_ == 404)
+ {
+ string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
+ throw new ServalApiException("The engine or corpus does not exist.", status_, responseText_, headers_, null);
+ }
+ else
+ if (status_ == 409)
+ {
+ string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
+ throw new ServalApiException("The engine needs to be built first.", status_, responseText_, headers_, null);
+ }
+ else
+ if (status_ == 503)
+ {
+ string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
+ throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details.", status_, responseText_, headers_, null);
+ }
+ else
+ {
+ var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
+ throw new ServalApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
+ }
+ }
+ finally
+ {
+ if (disposeResponse_)
+ response_.Dispose();
+ }
+ }
+ }
+ finally
+ {
+ if (disposeClient_)
+ client_.Dispose();
+ }
+ }
+
+ /// A cancellation token that can be used by other objects or threads to receive notice of cancellation.
+ ///
+ /// Get a pretranslated Scripture book in USFM format.
+ ///
+ ///
+ /// If the USFM book exists in the target corpus, then the pretranslated text will be inserted into any empty
+ ///
segments in the the target book and returned. If the USFM book does not exist in the target corpus, then the
+ ///
pretranslated text will be inserted into an empty template created from the source USFM book and returned.
+ ///
+ /// The translation engine id
+ /// The corpus id
+ /// The text id
+ /// The book in USFM format
+ /// A server side error occurred.
+ public virtual async System.Threading.Tasks.Task GetPretranslatedUsfmAsync(string id, string corpusId, string textId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
+ {
+ if (id == null)
+ throw new System.ArgumentNullException("id");
+
+ if (corpusId == null)
+ throw new System.ArgumentNullException("corpusId");
+
+ if (textId == null)
+ throw new System.ArgumentNullException("textId");
+
+ var client_ = _httpClient;
+ var disposeClient_ = false;
+ try
+ {
+ using (var request_ = new System.Net.Http.HttpRequestMessage())
+ {
+ request_.Method = new System.Net.Http.HttpMethod("GET");
+ request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain"));
+
+ var urlBuilder_ = new System.Text.StringBuilder();
+ if (!string.IsNullOrEmpty(BaseUrl)) urlBuilder_.Append(BaseUrl);
+ // Operation Path: "translation/engines/{id}/corpora/{corpusId}/pretranslations/{textId}/usfm"
+ urlBuilder_.Append("translation/engines/");
+ urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(id, System.Globalization.CultureInfo.InvariantCulture)));
+ urlBuilder_.Append("/corpora/");
+ urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(corpusId, System.Globalization.CultureInfo.InvariantCulture)));
+ urlBuilder_.Append("/pretranslations/");
+ urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(textId, System.Globalization.CultureInfo.InvariantCulture)));
+ urlBuilder_.Append("/usfm");
+
+ PrepareRequest(client_, request_, urlBuilder_);
+
+ var url_ = urlBuilder_.ToString();
+ request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
+
+ PrepareRequest(client_, request_, url_);
+
+ var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
+ var disposeResponse_ = true;
+ try
+ {
+ var headers_ = new System.Collections.Generic.Dictionary>();
+ foreach (var item_ in response_.Headers)
+ headers_[item_.Key] = item_.Value;
+ if (response_.Content != null && response_.Content.Headers != null)
+ {
+ foreach (var item_ in response_.Content.Headers)
+ headers_[item_.Key] = item_.Value;
+ }
+
+ ProcessResponse(client_, response_);
+
+ var status_ = (int)response_.StatusCode;
+ if (status_ == 200)
+ {
+ var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
+ var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string));
+ return result_;
+ }
+ else
+ if (status_ == 204)
+ {
+ string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
+ throw new ServalApiException("The specified book does not exist in the source or target corpus.", status_, responseText_, headers_, null);
+ }
+ else
+ if (status_ == 400)
+ {
+ string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
+ throw new ServalApiException("The corpus is not a valid Scripture corpus.", status_, responseText_, headers_, null);
+ }
+ else
+ if (status_ == 401)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ServalApiException("The client is not authenticated", status_, responseText_, headers_, null);
@@ -3301,25 +3589,25 @@ public string BaseUrl
if (status_ == 403)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The authenticated client cannot perform the operation or does not own the translation engine", status_, responseText_, headers_, null);
+ throw new ServalApiException("The authenticated client cannot perform the operation or does not own the translation engine.", status_, responseText_, headers_, null);
}
else
if (status_ == 404)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The engine or corpus does not exist", status_, responseText_, headers_, null);
+ throw new ServalApiException("The engine or corpus does not exist.", status_, responseText_, headers_, null);
}
else
if (status_ == 409)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The engine needs to be built first", status_, responseText_, headers_, null);
+ throw new ServalApiException("The engine needs to be built first.", status_, responseText_, headers_, null);
}
else
if (status_ == 503)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details. ", status_, responseText_, headers_, null);
+ throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details.", status_, responseText_, headers_, null);
}
else
{
@@ -3405,25 +3693,25 @@ public string BaseUrl
if (status_ == 401)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The client is not authenticated", status_, responseText_, headers_, null);
+ throw new ServalApiException("The client is not authenticated.", status_, responseText_, headers_, null);
}
else
if (status_ == 403)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The authenticated client cannot perform the operation or does not own the translation engine", status_, responseText_, headers_, null);
+ throw new ServalApiException("The authenticated client cannot perform the operation or does not own the translation engine.", status_, responseText_, headers_, null);
}
else
if (status_ == 404)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The engine does not exist", status_, responseText_, headers_, null);
+ throw new ServalApiException("The engine does not exist.", status_, responseText_, headers_, null);
}
else
if (status_ == 503)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details. ", status_, responseText_, headers_, null);
+ throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details.", status_, responseText_, headers_, null);
}
else
{
@@ -3467,7 +3755,7 @@ public string BaseUrl
///
/// The translation engine id
/// The build config (see remarks)
- /// The build job was started successfully
+ /// The new build job
/// A server side error occurred.
public virtual async System.Threading.Tasks.Task StartBuildAsync(string id, TranslationBuildConfig buildConfig, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
{
@@ -3533,31 +3821,31 @@ public string BaseUrl
if (status_ == 400)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("A corpus id is invalid", status_, responseText_, headers_, null);
+ throw new ServalApiException("A corpus id is invalid.", status_, responseText_, headers_, null);
}
else
if (status_ == 401)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The client is not authenticated", status_, responseText_, headers_, null);
+ throw new ServalApiException("The client is not authenticated.", status_, responseText_, headers_, null);
}
else
if (status_ == 403)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The authenticated client does not own the translation engine", status_, responseText_, headers_, null);
+ throw new ServalApiException("The authenticated client does not own the translation engine.", status_, responseText_, headers_, null);
}
else
if (status_ == 404)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The engine does not exist", status_, responseText_, headers_, null);
+ throw new ServalApiException("The engine does not exist.", status_, responseText_, headers_, null);
}
else
if (status_ == 409)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("There is already an active or pending build or a build in the process of being canceled", status_, responseText_, headers_, null);
+ throw new ServalApiException("There is already an active or pending build or a build in the process of being canceled.", status_, responseText_, headers_, null);
}
else
if (status_ == 503)
@@ -3668,40 +3956,34 @@ public string BaseUrl
return objectResponse_.Object;
}
else
- if (status_ == 400)
- {
- string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("Bad request", status_, responseText_, headers_, null);
- }
- else
if (status_ == 401)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The client is not authenticated", status_, responseText_, headers_, null);
+ throw new ServalApiException("The client is not authenticated.", status_, responseText_, headers_, null);
}
else
if (status_ == 403)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The authenticated client does not own the translation engine", status_, responseText_, headers_, null);
+ throw new ServalApiException("The authenticated client does not own the translation engine.", status_, responseText_, headers_, null);
}
else
if (status_ == 404)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The engine or build does not exist", status_, responseText_, headers_, null);
+ throw new ServalApiException("The engine or build does not exist.", status_, responseText_, headers_, null);
}
else
if (status_ == 408)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The long polling request timed out. This is expected behavior if you\'re using long-polling with the minRevision strategy specified in the docs", status_, responseText_, headers_, null);
+ throw new ServalApiException("The long polling request timed out. This is expected behavior if you\'re using long-polling with the minRevision strategy specified in the docs.", status_, responseText_, headers_, null);
}
else
if (status_ == 503)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details. ", status_, responseText_, headers_, null);
+ throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details.", status_, responseText_, headers_, null);
}
else
{
@@ -3797,7 +4079,7 @@ public string BaseUrl
if (status_ == 204)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("There is no build currently running", status_, responseText_, headers_, null);
+ throw new ServalApiException("There is no build currently running.", status_, responseText_, headers_, null);
}
else
if (status_ == 400)
@@ -3809,31 +4091,31 @@ public string BaseUrl
if (status_ == 401)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The client is not authenticated", status_, responseText_, headers_, null);
+ throw new ServalApiException("The client is not authenticated.", status_, responseText_, headers_, null);
}
else
if (status_ == 403)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The authenticated client does not own the translation engine", status_, responseText_, headers_, null);
+ throw new ServalApiException("The authenticated client does not own the translation engine.", status_, responseText_, headers_, null);
}
else
if (status_ == 404)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The engine does not exist", status_, responseText_, headers_, null);
+ throw new ServalApiException("The engine does not exist.", status_, responseText_, headers_, null);
}
else
if (status_ == 408)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The long polling request timed out. This is expected behavior if you\'re using long-polling with the minRevision strategy specified in the docs", status_, responseText_, headers_, null);
+ throw new ServalApiException("The long polling request timed out. This is expected behavior if you\'re using long-polling with the minRevision strategy specified in the docs.", status_, responseText_, headers_, null);
}
else
if (status_ == 503)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details. ", status_, responseText_, headers_, null);
+ throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details.", status_, responseText_, headers_, null);
}
else
{
@@ -3860,7 +4142,7 @@ public string BaseUrl
/// Cancel the current build job (whether pending or active) for a translation engine
///
/// The translation engine id
- /// The build job was cancelled successfully
+ /// The build job was cancelled successfully.
/// A server side error occurred.
public virtual async System.Threading.Tasks.Task CancelBuildAsync(string id, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
{
@@ -3911,34 +4193,39 @@ public string BaseUrl
return;
}
else
+ if (status_ == 204)
+ {
+ return;
+ }
+ else
if (status_ == 401)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The client is not authenticated", status_, responseText_, headers_, null);
+ throw new ServalApiException("The client is not authenticated.", status_, responseText_, headers_, null);
}
else
if (status_ == 403)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The authenticated client does not own the translation engine", status_, responseText_, headers_, null);
+ throw new ServalApiException("The authenticated client does not own the translation engine.", status_, responseText_, headers_, null);
}
else
if (status_ == 404)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The engine does not exist or there is no active build ", status_, responseText_, headers_, null);
+ throw new ServalApiException("The engine does not exist.", status_, responseText_, headers_, null);
}
else
if (status_ == 405)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("The translation engine does not support cancelling builds", status_, responseText_, headers_, null);
+ throw new ServalApiException("The translation engine does not support cancelling builds.", status_, responseText_, headers_, null);
}
else
if (status_ == 503)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
- throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details. ", status_, responseText_, headers_, null);
+ throw new ServalApiException("A necessary service is currently unavailable. Check `/health` for more details.", status_, responseText_, headers_, null);
}
else
{
@@ -4073,7 +4360,7 @@ private string ConvertToString(object? value, System.Globalization.CultureInfo c
}
[System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.2.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")]
- public partial interface ITranslationClient
+ public partial interface ITranslationEngineTypesClient
{
/// A cancellation token that can be used by other objects or threads to receive notice of cancellation.
@@ -4111,7 +4398,7 @@ public partial interface ITranslationClient
}
[System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.2.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")]
- public partial class TranslationClient : ITranslationClient
+ public partial class TranslationEngineTypesClient : ITranslationEngineTypesClient
{
#pragma warning disable 8618 // Set by constructor via BaseUrl property
private string _baseUrl;
@@ -4119,7 +4406,7 @@ public partial class TranslationClient : ITranslationClient
private System.Net.Http.HttpClient _httpClient;
private static System.Lazy _settings = new System.Lazy(CreateSerializerSettings, true);
- public TranslationClient(System.Net.Http.HttpClient httpClient)
+ public TranslationEngineTypesClient(System.Net.Http.HttpClient httpClient)
{
BaseUrl = "/api/v1";
_httpClient = httpClient;
diff --git a/src/Serval.Client/Serval.Client.csproj b/src/Serval.Client/Serval.Client.csproj
index 9a932015..76996f38 100644
--- a/src/Serval.Client/Serval.Client.csproj
+++ b/src/Serval.Client/Serval.Client.csproj
@@ -5,6 +5,7 @@
1.2.0
Client classes for Serval.
Serval.Client
+ 8618
diff --git a/src/Serval.DataFiles/Consumers/GetDataFileConsumer.cs b/src/Serval.DataFiles/Consumers/GetDataFileConsumer.cs
index a83f46d0..a1ffe589 100644
--- a/src/Serval.DataFiles/Consumers/GetDataFileConsumer.cs
+++ b/src/Serval.DataFiles/Consumers/GetDataFileConsumer.cs
@@ -11,19 +11,13 @@ public GetDataFileConsumer(IDataFileService dataFileService)
public async Task Consume(ConsumeContext context)
{
- DataFile? dataFile = await _dataFileService.GetAsync(
- context.Message.DataFileId,
- context.Message.Owner,
- context.CancellationToken
- );
- if (dataFile is null)
+ try
{
- await context.RespondAsync(
- new DataFileNotFound { DataFileId = context.Message.DataFileId, Owner = context.Message.Owner }
+ DataFile dataFile = await _dataFileService.GetAsync(
+ context.Message.DataFileId,
+ context.Message.Owner,
+ context.CancellationToken
);
- }
- else
- {
await context.RespondAsync(
new DataFileResult
{
@@ -34,5 +28,11 @@ await context.RespondAsync(
}
);
}
+ catch (EntityNotFoundException)
+ {
+ await context.RespondAsync(
+ new DataFileNotFound { DataFileId = context.Message.DataFileId, Owner = context.Message.Owner }
+ );
+ }
}
}
diff --git a/src/Serval.DataFiles/Controllers/DataFilesController.cs b/src/Serval.DataFiles/Controllers/DataFilesController.cs
index d9691c8f..ce60456e 100644
--- a/src/Serval.DataFiles/Controllers/DataFilesController.cs
+++ b/src/Serval.DataFiles/Controllers/DataFilesController.cs
@@ -56,12 +56,8 @@ public async Task> GetAllAsync(CancellationToken cancel
[ProducesResponseType(typeof(void), StatusCodes.Status503ServiceUnavailable)]
public async Task> GetAsync([NotNull] string id, CancellationToken cancellationToken)
{
- DataFile? dataFile = await _dataFileService.GetAsync(id, cancellationToken);
- if (dataFile == null)
- return NotFound();
- if (!await AuthorizeIsOwnerAsync(dataFile))
- return Forbid();
-
+ DataFile dataFile = await _dataFileService.GetAsync(id, cancellationToken);
+ await AuthorizeAsync(dataFile);
return Ok(Map(dataFile));
}
@@ -155,16 +151,9 @@ CancellationToken cancellationToken
[ProducesResponseType(typeof(void), StatusCodes.Status503ServiceUnavailable)]
public async Task DownloadAsync([NotNull] string id, CancellationToken cancellationToken)
{
- DataFile? dataFile = await _dataFileService.GetAsync(id, cancellationToken);
- if (dataFile == null)
- return NotFound();
- if (!await AuthorizeIsOwnerAsync(dataFile))
- return Forbid();
-
- Stream? stream = await _dataFileService.ReadAsync(id, cancellationToken);
- if (stream == null)
- return NotFound();
-
+ DataFile dataFile = await _dataFileService.GetAsync(id, cancellationToken);
+ await AuthorizeAsync(dataFile);
+ Stream stream = await _dataFileService.ReadAsync(id, cancellationToken);
return File(stream, "application/octet-stream", dataFile.Name);
}
@@ -195,16 +184,11 @@ public async Task> UpdateAsync(
CancellationToken cancellationToken
)
{
- DataFile? dataFile = await _dataFileService.GetAsync(id, cancellationToken);
- if (dataFile == null)
- return NotFound();
- if (!await AuthorizeIsOwnerAsync(dataFile))
- return Forbid();
+ await AuthorizeAsync(id, cancellationToken);
+ DataFile dataFile;
using (Stream stream = file.OpenReadStream())
dataFile = await _dataFileService.UpdateAsync(id, stream, cancellationToken);
- if (dataFile is null)
- return NotFound();
var dto = Map(dataFile);
return Ok(dto);
@@ -234,18 +218,17 @@ CancellationToken cancellationToken
[ProducesResponseType(typeof(void), StatusCodes.Status503ServiceUnavailable)]
public async Task DeleteAsync([NotNull] string id, CancellationToken cancellationToken)
{
- DataFile? dataFile = await _dataFileService.GetAsync(id, cancellationToken);
- if (dataFile == null)
- return NotFound();
- if (!await AuthorizeIsOwnerAsync(dataFile))
- return Forbid();
-
- if (!await _dataFileService.DeleteAsync(id, cancellationToken))
- return NotFound();
-
+ await AuthorizeAsync(id, cancellationToken);
+ await _dataFileService.DeleteAsync(id, cancellationToken);
return Ok();
}
+ private async Task AuthorizeAsync(string id, CancellationToken cancellationToken)
+ {
+ DataFile dataFile = await _dataFileService.GetAsync(id, cancellationToken);
+ await AuthorizeAsync(dataFile);
+ }
+
private DataFileDto Map(DataFile source)
{
return new DataFileDto
diff --git a/src/Serval.DataFiles/Services/DataFileService.cs b/src/Serval.DataFiles/Services/DataFileService.cs
index 4cebcd97..d46d7ab1 100644
--- a/src/Serval.DataFiles/Services/DataFileService.cs
+++ b/src/Serval.DataFiles/Services/DataFileService.cs
@@ -26,9 +26,12 @@ IFileSystem fileSystem
_fileSystem.CreateDirectory(_options.CurrentValue.FilesDirectory);
}
- public Task GetAsync(string id, string owner, CancellationToken cancellationToken = default)
+ public async Task GetAsync(string id, string owner, CancellationToken cancellationToken = default)
{
- return Entities.GetAsync(f => f.Id == id && f.Owner == owner, cancellationToken);
+ DataFile? dataFile = await Entities.GetAsync(f => f.Id == id && f.Owner == owner, cancellationToken);
+ if (dataFile is null)
+ throw new EntityNotFoundException($"Could not find the DataFile '{id}' with owner '{owner}'.");
+ return dataFile;
}
public async Task> GetAllAsync(string owner, CancellationToken cancellationToken = default)
@@ -53,16 +56,16 @@ public async Task CreateAsync(DataFile dataFile, Stream stream, CancellationToke
}
}
- public async Task ReadAsync(string id, CancellationToken cancellationToken = default)
+ public async Task ReadAsync(string id, CancellationToken cancellationToken = default)
{
DataFile? dataFile = await GetAsync(id, cancellationToken);
if (dataFile is null)
- return null;
+ throw new EntityNotFoundException($"Could not find the DataFile '{id}'.");
string path = GetDataFilePath(dataFile.Filename);
return _fileSystem.OpenRead(path);
}
- public async Task UpdateAsync(string id, Stream stream, CancellationToken cancellationToken = default)
+ public async Task UpdateAsync(string id, Stream stream, CancellationToken cancellationToken = default)
{
string filename = Path.GetRandomFileName();
string path = GetDataFilePath(filename);
@@ -81,7 +84,7 @@ public async Task CreateAsync(DataFile dataFile, Stream stream, CancellationToke
);
if (originalDataFile is null)
{
- deleteFile = true;
+ throw new EntityNotFoundException($"Could not find the DataFile '{id}'.");
}
else
{
@@ -91,7 +94,7 @@ await _deletedFiles.InsertAsync(
);
}
await _dataAccessContext.CommitTransactionAsync(cancellationToken);
- return originalDataFile is null ? null : await GetAsync(id, cancellationToken);
+ return await GetAsync(id, cancellationToken);
}
catch
{
@@ -105,21 +108,18 @@ await _deletedFiles.InsertAsync(
}
}
- public override async Task DeleteAsync(string id, CancellationToken cancellationToken = default)
+ public override async Task DeleteAsync(string id, CancellationToken cancellationToken = default)
{
- // return true if the deletion was successful, false if the file did not exist or was already deleted.
await _dataAccessContext.BeginTransactionAsync(cancellationToken);
DataFile? dataFile = await Entities.DeleteAsync(id, cancellationToken);
- if (dataFile is not null)
- {
- await _deletedFiles.InsertAsync(
- new DeletedFile { Filename = dataFile.Filename, DeletedAt = DateTime.UtcNow },
- cancellationToken
- );
- }
+ if (dataFile is null)
+ throw new EntityNotFoundException($"Could not find the DataFile '{id}'.");
+ await _deletedFiles.InsertAsync(
+ new DeletedFile { Filename = dataFile.Filename, DeletedAt = DateTime.UtcNow },
+ cancellationToken
+ );
await _mediator.Publish(new DataFileDeleted { DataFileId = id }, cancellationToken);
await _dataAccessContext.CommitTransactionAsync(CancellationToken.None);
- return dataFile is not null;
}
private string GetDataFilePath(string filename)
diff --git a/src/Serval.DataFiles/Services/IDataFileService.cs b/src/Serval.DataFiles/Services/IDataFileService.cs
index 83ff01b9..b10d8f25 100644
--- a/src/Serval.DataFiles/Services/IDataFileService.cs
+++ b/src/Serval.DataFiles/Services/IDataFileService.cs
@@ -3,10 +3,10 @@
public interface IDataFileService
{
Task> GetAllAsync(string owner, CancellationToken cancellationToken = default);
- Task GetAsync(string id, CancellationToken cancellationToken = default);
- Task GetAsync(string id, string owner, CancellationToken cancellationToken = default);
+ Task GetAsync(string id, CancellationToken cancellationToken = default);
+ Task GetAsync(string id, string owner, CancellationToken cancellationToken = default);
Task CreateAsync(DataFile dataFile, Stream stream, CancellationToken cancellationToken = default);
- Task ReadAsync(string id, CancellationToken cancellationToken = default);
- Task UpdateAsync(string id, Stream stream, CancellationToken cancellationToken = default);
- Task DeleteAsync(string id, CancellationToken cancellationToken = default);
+ Task ReadAsync(string id, CancellationToken cancellationToken = default);
+ Task UpdateAsync(string id, Stream stream, CancellationToken cancellationToken = default);
+ Task DeleteAsync(string id, CancellationToken cancellationToken = default);
}
diff --git a/src/Serval.DataFiles/Usings.cs b/src/Serval.DataFiles/Usings.cs
index a10d6a20..0d81ccb1 100644
--- a/src/Serval.DataFiles/Usings.cs
+++ b/src/Serval.DataFiles/Usings.cs
@@ -23,4 +23,5 @@
global using Serval.Shared.Controllers;
global using Serval.Shared.Models;
global using Serval.Shared.Services;
+global using Serval.Shared.Utils;
global using SIL.DataAccess;
diff --git a/src/Serval.Shared/Configuration/IServiceCollectionExtensions.cs b/src/Serval.Shared/Configuration/IServiceCollectionExtensions.cs
index 6902f510..2671ac40 100644
--- a/src/Serval.Shared/Configuration/IServiceCollectionExtensions.cs
+++ b/src/Serval.Shared/Configuration/IServiceCollectionExtensions.cs
@@ -5,6 +5,7 @@ public static class IServiceCollectionExtensions
public static IServalBuilder AddServal(this IServiceCollection services, IConfiguration? configuration = null)
{
services.AddTransient();
+ services.AddTransient();
return new ServalBuilder(services, configuration);
}
}
diff --git a/src/Serval.Shared/Controllers/BadRequestExceptionFilter.cs b/src/Serval.Shared/Controllers/BadRequestExceptionFilter.cs
new file mode 100644
index 00000000..076e2065
--- /dev/null
+++ b/src/Serval.Shared/Controllers/BadRequestExceptionFilter.cs
@@ -0,0 +1,13 @@
+namespace Serval.Shared.Controllers;
+
+public class BadRequestExceptionFilter : ExceptionFilterAttribute
+{
+ public override void OnException(ExceptionContext context)
+ {
+ if (context.Exception is InvalidOperationException)
+ {
+ context.Result = new BadRequestObjectResult(context.Exception.Message);
+ context.ExceptionHandled = true;
+ }
+ }
+}
diff --git a/src/Serval.Shared/Controllers/ErrorResultFilter.cs b/src/Serval.Shared/Controllers/ErrorResultFilter.cs
index 3c6bfa03..31e2a271 100644
--- a/src/Serval.Shared/Controllers/ErrorResultFilter.cs
+++ b/src/Serval.Shared/Controllers/ErrorResultFilter.cs
@@ -1,6 +1,3 @@
-using System.Diagnostics;
-using System.Text.Json;
-
namespace Serval.Shared.Controllers
{
public class ErrorResultFilter : IAlwaysRunResultFilter
diff --git a/src/Serval.Shared/Controllers/ForbiddenExceptionFilter.cs b/src/Serval.Shared/Controllers/ForbiddenExceptionFilter.cs
new file mode 100644
index 00000000..b80e621e
--- /dev/null
+++ b/src/Serval.Shared/Controllers/ForbiddenExceptionFilter.cs
@@ -0,0 +1,13 @@
+namespace Serval.Shared.Controllers;
+
+public class ForbiddenExceptionFilter : ExceptionFilterAttribute
+{
+ public override void OnException(ExceptionContext context)
+ {
+ if (context.Exception is ForbiddenException)
+ {
+ context.Result = new ForbidResult();
+ context.ExceptionHandled = true;
+ }
+ }
+}
diff --git a/src/Serval.Shared/Controllers/NotFoundExceptionFilter.cs b/src/Serval.Shared/Controllers/NotFoundExceptionFilter.cs
new file mode 100644
index 00000000..53f5b332
--- /dev/null
+++ b/src/Serval.Shared/Controllers/NotFoundExceptionFilter.cs
@@ -0,0 +1,15 @@
+using Serval.Shared.Utils;
+
+namespace Serval.Shared.Controllers;
+
+public class NotFoundExceptionFilter : ExceptionFilterAttribute
+{
+ public override void OnException(ExceptionContext context)
+ {
+ if (context.Exception is EntityNotFoundException)
+ {
+ context.Result = new NotFoundResult();
+ context.ExceptionHandled = true;
+ }
+ }
+}
diff --git a/src/Serval.Shared/Controllers/ServalControllerBase.cs b/src/Serval.Shared/Controllers/ServalControllerBase.cs
index bebcdf29..34e75bb6 100644
--- a/src/Serval.Shared/Controllers/ServalControllerBase.cs
+++ b/src/Serval.Shared/Controllers/ServalControllerBase.cs
@@ -7,6 +7,9 @@
[TypeFilter(typeof(ServiceUnavailableExceptionFilter))]
[TypeFilter(typeof(ErrorResultFilter))]
[TypeFilter(typeof(AbortedRpcExceptionFilter))]
+[TypeFilter(typeof(NotFoundExceptionFilter))]
+[TypeFilter(typeof(ForbiddenExceptionFilter))]
+[TypeFilter(typeof(BadRequestExceptionFilter))]
public abstract class ServalControllerBase : Controller
{
private readonly IAuthorizationService _authService;
@@ -18,9 +21,10 @@ protected ServalControllerBase(IAuthorizationService authService)
protected string Owner => User.Identity!.Name!;
- protected async Task AuthorizeIsOwnerAsync(IOwnedEntity ownedEntity)
+ protected async Task AuthorizeAsync(IOwnedEntity ownedEntity)
{
AuthorizationResult result = await _authService.AuthorizeAsync(User, ownedEntity, "IsOwner");
- return result.Succeeded;
+ if (!result.Succeeded)
+ throw new ForbiddenException();
}
}
diff --git a/src/Serval.Shared/Serval.Shared.csproj b/src/Serval.Shared/Serval.Shared.csproj
index 59b805ed..8c6ecf97 100644
--- a/src/Serval.Shared/Serval.Shared.csproj
+++ b/src/Serval.Shared/Serval.Shared.csproj
@@ -15,10 +15,12 @@
+
+
diff --git a/src/Serval.Shared/Services/EntityServiceBase.cs b/src/Serval.Shared/Services/EntityServiceBase.cs
index abcff427..6970a80c 100644
--- a/src/Serval.Shared/Services/EntityServiceBase.cs
+++ b/src/Serval.Shared/Services/EntityServiceBase.cs
@@ -10,9 +10,12 @@ protected EntityServiceBase(IRepository entities)
protected IRepository Entities { get; }
- public Task GetAsync(string id, CancellationToken cancellationToken = default)
+ public async Task GetAsync(string id, CancellationToken cancellationToken = default)
{
- return Entities.GetAsync(id, cancellationToken);
+ T? entity = await Entities.GetAsync(id, cancellationToken);
+ if (entity is null)
+ throw new EntityNotFoundException($"Could not find the {typeof(T).Name} '{id}'.");
+ return entity;
}
public virtual Task CreateAsync(T entity, CancellationToken cancellationToken = default)
@@ -20,8 +23,10 @@ public virtual Task CreateAsync(T entity, CancellationToken cancellationToken =
return Entities.InsertAsync(entity, cancellationToken);
}
- public virtual async Task DeleteAsync(string id, CancellationToken cancellationToken = default)
+ public virtual async Task DeleteAsync(string id, CancellationToken cancellationToken = default)
{
- return await Entities.DeleteAsync(id, cancellationToken) is not null;
+ T? entity = await Entities.DeleteAsync(id, cancellationToken);
+ if (entity is null)
+ throw new EntityNotFoundException($"Could not find the {typeof(T).Name} '{id}'.");
}
}
diff --git a/src/Serval.Shared/Services/FileSystem.cs b/src/Serval.Shared/Services/FileSystem.cs
index d7683d0a..00b96a5c 100644
--- a/src/Serval.Shared/Services/FileSystem.cs
+++ b/src/Serval.Shared/Services/FileSystem.cs
@@ -22,4 +22,9 @@ public Stream OpenRead(string path)
{
return File.OpenRead(path);
}
+
+ public IZipContainer OpenZipFile(string path)
+ {
+ return new ZipContainer(path);
+ }
}
diff --git a/src/Serval.Shared/Services/IFileSystem.cs b/src/Serval.Shared/Services/IFileSystem.cs
index 429609b1..55d93f5a 100644
--- a/src/Serval.Shared/Services/IFileSystem.cs
+++ b/src/Serval.Shared/Services/IFileSystem.cs
@@ -6,4 +6,5 @@ public interface IFileSystem
void CreateDirectory(string path);
Stream OpenWrite(string path);
Stream OpenRead(string path);
+ IZipContainer OpenZipFile(string path);
}
diff --git a/src/Serval.Shared/Services/IScriptureDataFileService.cs b/src/Serval.Shared/Services/IScriptureDataFileService.cs
new file mode 100644
index 00000000..92fe96d9
--- /dev/null
+++ b/src/Serval.Shared/Services/IScriptureDataFileService.cs
@@ -0,0 +1,7 @@
+namespace Serval.Shared.Services;
+
+public interface IScriptureDataFileService
+{
+ ParatextProjectSettings GetParatextProjectSettings(string filename);
+ Task ReadParatextProjectBookAsync(string filename, string book);
+}
diff --git a/src/Serval.Shared/Services/IZipContainer.cs b/src/Serval.Shared/Services/IZipContainer.cs
new file mode 100644
index 00000000..7c0beac1
--- /dev/null
+++ b/src/Serval.Shared/Services/IZipContainer.cs
@@ -0,0 +1,8 @@
+namespace Serval.Shared.Services;
+
+public interface IZipContainer : IDisposable
+{
+ bool EntryExists(string name);
+ Stream OpenEntry(string name);
+ IEnumerable Entries { get; }
+}
diff --git a/src/Serval.Shared/Services/ScriptureDataFileService.cs b/src/Serval.Shared/Services/ScriptureDataFileService.cs
new file mode 100644
index 00000000..1a5a9753
--- /dev/null
+++ b/src/Serval.Shared/Services/ScriptureDataFileService.cs
@@ -0,0 +1,36 @@
+namespace Serval.Shared.Services;
+
+public class ScriptureDataFileService(IFileSystem fileSystem, IOptionsMonitor dataFileOptions)
+ : IScriptureDataFileService
+{
+ private readonly IFileSystem _fileSystem = fileSystem;
+ private readonly IOptionsMonitor _dataFileOptions = dataFileOptions;
+
+ public ParatextProjectSettings GetParatextProjectSettings(string filename)
+ {
+ using IZipContainer container = _fileSystem.OpenZipFile(GetFilePath(filename));
+ return ParseProjectSettings(container);
+ }
+
+ public async Task ReadParatextProjectBookAsync(string filename, string book)
+ {
+ using IZipContainer container = _fileSystem.OpenZipFile(GetFilePath(filename));
+ ParatextProjectSettings settings = ParseProjectSettings(container);
+ string entryName = settings.GetBookFileName(book);
+ if (!container.EntryExists(entryName))
+ return null;
+ using StreamReader reader = new(container.OpenEntry(entryName));
+ return await reader.ReadToEndAsync();
+ }
+
+ private string GetFilePath(string filename)
+ {
+ return Path.Combine(_dataFileOptions.CurrentValue.FilesDirectory, filename);
+ }
+
+ private static ParatextProjectSettings ParseProjectSettings(IZipContainer container)
+ {
+ ZipParatextProjectSettingsParser settingsParser = new(container);
+ return settingsParser.Parse();
+ }
+}
diff --git a/src/Serval.Shared/Services/ZipContainer.cs b/src/Serval.Shared/Services/ZipContainer.cs
new file mode 100644
index 00000000..e7c0eff0
--- /dev/null
+++ b/src/Serval.Shared/Services/ZipContainer.cs
@@ -0,0 +1,34 @@
+using System.IO.Compression;
+using SIL.ObjectModel;
+
+namespace Serval.Shared.Services;
+
+public class ZipContainer : DisposableBase, IZipContainer
+{
+ private readonly ZipArchive _archive;
+
+ public ZipContainer(string fileName)
+ {
+ _archive = ZipFile.OpenRead(fileName);
+ }
+
+ public IEnumerable Entries => _archive.Entries.Select(e => e.FullName);
+
+ public bool EntryExists(string name)
+ {
+ return _archive.GetEntry(name) is not null;
+ }
+
+ public Stream OpenEntry(string name)
+ {
+ ZipArchiveEntry? entry = _archive.GetEntry(name);
+ if (entry is null)
+ throw new ArgumentException("The specified entry does not exist.", nameof(name));
+ return entry.Open();
+ }
+
+ protected override void DisposeManagedResources()
+ {
+ _archive.Dispose();
+ }
+}
diff --git a/src/Serval.Shared/Services/ZipParatextProjectSettingsParser.cs b/src/Serval.Shared/Services/ZipParatextProjectSettingsParser.cs
new file mode 100644
index 00000000..85fb255c
--- /dev/null
+++ b/src/Serval.Shared/Services/ZipParatextProjectSettingsParser.cs
@@ -0,0 +1,21 @@
+namespace Serval.Shared.Services;
+
+public class ZipParatextProjectSettingsParser(IZipContainer projectContainer) : ZipParatextProjectSettingsParserBase
+{
+ private readonly IZipContainer _projectContainer = projectContainer;
+
+ protected override bool Exists(string fileName)
+ {
+ return _projectContainer.EntryExists(fileName);
+ }
+
+ protected override string? Find(string extension)
+ {
+ return _projectContainer.Entries.FirstOrDefault(e => e.EndsWith(extension));
+ }
+
+ protected override Stream Open(string fileName)
+ {
+ return _projectContainer.OpenEntry(fileName);
+ }
+}
diff --git a/src/Serval.Shared/Usings.cs b/src/Serval.Shared/Usings.cs
index 05799fbf..fec5ec1b 100644
--- a/src/Serval.Shared/Usings.cs
+++ b/src/Serval.Shared/Usings.cs
@@ -1,4 +1,4 @@
-global using System.Text;
+global using System.Diagnostics;
global using System.Text.Json;
global using System.Text.Json.Serialization;
global using Grpc.Core;
@@ -7,9 +7,11 @@
global using Microsoft.AspNetCore.Mvc;
global using Microsoft.AspNetCore.Mvc.Filters;
global using Microsoft.Extensions.Configuration;
-global using Microsoft.Extensions.Diagnostics.HealthChecks;
global using Microsoft.Extensions.Logging;
+global using Microsoft.Extensions.Options;
global using Serval.Shared.Configuration;
global using Serval.Shared.Models;
global using Serval.Shared.Services;
+global using Serval.Shared.Utils;
global using SIL.DataAccess;
+global using SIL.Machine.Corpora;
diff --git a/src/Serval.Shared/Utils/EntityNotFoundException.cs b/src/Serval.Shared/Utils/EntityNotFoundException.cs
new file mode 100644
index 00000000..1c576bfb
--- /dev/null
+++ b/src/Serval.Shared/Utils/EntityNotFoundException.cs
@@ -0,0 +1,12 @@
+namespace Serval.Shared.Utils;
+
+public class EntityNotFoundException : Exception
+{
+ public EntityNotFoundException() { }
+
+ public EntityNotFoundException(string? message)
+ : base(message) { }
+
+ public EntityNotFoundException(string? message, Exception? innerException)
+ : base(message, innerException) { }
+}
diff --git a/src/Serval.Shared/Utils/ForbiddenException.cs b/src/Serval.Shared/Utils/ForbiddenException.cs
new file mode 100644
index 00000000..058689c4
--- /dev/null
+++ b/src/Serval.Shared/Utils/ForbiddenException.cs
@@ -0,0 +1,12 @@
+namespace Serval.Shared.Utils;
+
+public class ForbiddenException : Exception
+{
+ public ForbiddenException() { }
+
+ public ForbiddenException(string? message)
+ : base(message) { }
+
+ public ForbiddenException(string? message, Exception? innerException)
+ : base(message, innerException) { }
+}
diff --git a/src/Serval.Shared/Utils/TupleExtensions.cs b/src/Serval.Shared/Utils/TupleExtensions.cs
deleted file mode 100644
index fa4f1a5f..00000000
--- a/src/Serval.Shared/Utils/TupleExtensions.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using System.Diagnostics.CodeAnalysis;
-
-namespace Serval.Shared.Utils;
-
-public static class TupleExtensions
-{
- public static bool IsSuccess(
- this ValueTuple tuple,
- [MaybeNullWhen(true)] out ActionResult errorResult
- )
- {
- bool success;
- (success, errorResult) = tuple;
- return success;
- }
-}
diff --git a/src/Serval.Translation/Contracts/PretranslationFormat.cs b/src/Serval.Translation/Contracts/PretranslationFormat.cs
new file mode 100644
index 00000000..e0f53ab9
--- /dev/null
+++ b/src/Serval.Translation/Contracts/PretranslationFormat.cs
@@ -0,0 +1,7 @@
+namespace Serval.Translation.Contracts;
+
+public enum PretranslationFormat
+{
+ Json,
+ Usfm
+}
diff --git a/src/Serval.Translation/Controllers/TranslationEngineTypesController.cs b/src/Serval.Translation/Controllers/TranslationEngineTypesController.cs
index 22880c70..53df27a0 100644
--- a/src/Serval.Translation/Controllers/TranslationEngineTypesController.cs
+++ b/src/Serval.Translation/Controllers/TranslationEngineTypesController.cs
@@ -3,7 +3,7 @@
[ApiVersion(1.0)]
[Route("api/v{version:apiVersion}/translation/engine-types")]
[OpenApiTag("Translation Engines")]
-public class TranslationController(IAuthorizationService authService, IEngineService engineService)
+public class TranslationEngineTypesController(IAuthorizationService authService, IEngineService engineService)
: ServalControllerBase(authService)
{
private readonly IEngineService _engineService = engineService;
diff --git a/src/Serval.Translation/Controllers/TranslationEnginesController.cs b/src/Serval.Translation/Controllers/TranslationEnginesController.cs
index 8a01d75f..73e397a4 100644
--- a/src/Serval.Translation/Controllers/TranslationEnginesController.cs
+++ b/src/Serval.Translation/Controllers/TranslationEnginesController.cs
@@ -23,9 +23,9 @@ IUrlService urlService
///
///
/// The engines
- /// The client is not authenticated
- /// The authenticated client cannot perform the operation
- /// A necessary service is currently unavailable. Check `/health` for more details.
+ /// The client is not authenticated.
+ /// The authenticated client cannot perform the operation.
+ /// A necessary service is currently unavailable. Check `/health` for more details.
[Authorize(Scopes.ReadTranslationEngines)]
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
@@ -43,10 +43,10 @@ public async Task> GetAllAsync(CancellationTok
/// The translation engine id
///
/// The translation engine
- /// The client is not authenticated
- /// The authenticated client cannot perform the operation or does not own the translation engine
- /// The engine does not exist
- /// A necessary service is currently unavailable. Check `/health` for more details.
+ /// The client is not authenticated.
+ /// The authenticated client cannot perform the operation or does not own the translation engine.
+ /// The engine does not exist.
+ /// A necessary service is currently unavailable. Check `/health` for more details.
[Authorize(Scopes.ReadTranslationEngines)]
[HttpGet("{id}", Name = "GetTranslationEngine")]
@@ -60,12 +60,8 @@ public async Task> GetAsync(
CancellationToken cancellationToken
)
{
- Engine? engine = await _engineService.GetAsync(id, cancellationToken);
- if (engine == null)
- return NotFound();
- if (!await AuthorizeIsOwnerAsync(engine))
- return Forbid();
-
+ Engine engine = await _engineService.GetAsync(id, cancellationToken);
+ await AuthorizeAsync(engine);
return Ok(Map(engine));
}
@@ -103,20 +99,18 @@ CancellationToken cancellationToken
/// The translation engine configuration (see above)
///
///
- /// The translation engine was created successfully
- /// Bad request. Is the engine type correct?
- /// The client is not authenticated
- /// The authenticated client cannot perform the operation or does not own the translation engine
- /// The engine does not exist
- /// The engine was specified incorrectly. Did you use the same language for the source and target?
- /// A necessary service is currently unavailable. Check `/health` for more details.
+ /// The new translation engine
+ /// Bad request. Is the engine type correct?
+ /// The client is not authenticated.
+ /// The authenticated client cannot perform the operation or does not own the translation engine.
+ /// The engine does not exist.
+ /// A necessary service is currently unavailable. Check `/health` for more details.
[Authorize(Scopes.CreateTranslationEngines)]
[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(typeof(void), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)]
- [ProducesResponseType(typeof(void), StatusCodes.Status422UnprocessableEntity)]
[ProducesResponseType(typeof(void), StatusCodes.Status503ServiceUnavailable)]
public async Task> CreateAsync(
[FromBody] TranslationEngineConfigDto engineConfig,
@@ -126,19 +120,7 @@ CancellationToken cancellationToken
{
Engine engine = Map(engineConfig);
engine.Id = idGenerator.GenerateId();
- try
- {
- bool success = await _engineService.CreateAsync(engine, cancellationToken);
- if (!success)
- return BadRequest();
- }
- catch (RpcException rpcEx)
- {
- if (rpcEx.StatusCode == Grpc.Core.StatusCode.InvalidArgument)
- return UnprocessableEntity(rpcEx.Message);
- throw;
- }
-
+ await _engineService.CreateAsync(engine, cancellationToken);
TranslationEngineDto dto = Map(engine);
return Created(dto.Url, dto);
}
@@ -148,11 +130,11 @@ CancellationToken cancellationToken
///
/// The translation engine id
///
- /// The engine was successfully deleted
- /// The client is not authenticated
- /// The authenticated client cannot perform the operation or does not own the translation engine
- /// The engine does not exist and therefore cannot be deleted
- /// A necessary service is currently unavailable. Check `/health` for more details.
+ /// The engine was successfully deleted.
+ /// The client is not authenticated.
+ /// The authenticated client cannot perform the operation or does not own the translation engine.
+ /// The engine does not exist and therefore cannot be deleted.
+ /// A necessary service is currently unavailable. Check `/health` for more details.
[Authorize(Scopes.DeleteTranslationEngines)]
[HttpDelete("{id}")]
[ProducesResponseType(typeof(void), StatusCodes.Status200OK)]
@@ -162,11 +144,8 @@ CancellationToken cancellationToken
[ProducesResponseType(typeof(void), StatusCodes.Status503ServiceUnavailable)]
public async Task DeleteAsync([NotNull] string id, CancellationToken cancellationToken)
{
- if (!(await AuthorizeAsync(id, cancellationToken)).IsSuccess(out ActionResult? errorResult))
- return errorResult;
-
- if (!await _engineService.DeleteAsync(id, cancellationToken))
- return NotFound();
+ await AuthorizeAsync(id, cancellationToken);
+ await _engineService.DeleteAsync(id, cancellationToken);
return Ok();
}
@@ -178,12 +157,12 @@ public async Task DeleteAsync([NotNull] string id, CancellationTok
///
/// The translation result
/// Bad request
- /// The client is not authenticated
- /// The authenticated client cannot perform the operation or does not own the translation engine
- /// The engine does not exist
- /// The method is not supported
- /// The engine needs to be built before it can translate segments
- /// A necessary service is currently unavailable. Check `/health` for more details.
+ /// The client is not authenticated.
+ /// The authenticated client cannot perform the operation or does not own the translation engine.
+ /// The engine does not exist.
+ /// The method is not supported.
+ /// The engine needs to be built before it can translate segments.
+ /// A necessary service is currently unavailable. Check `/health` for more details.
[Authorize(Scopes.ReadTranslationEngines)]
[HttpPost("{id}/translate")]
[ProducesResponseType(StatusCodes.Status200OK)]
@@ -200,12 +179,8 @@ public async Task> TranslateAsync(
CancellationToken cancellationToken
)
{
- if (!(await AuthorizeAsync(id, cancellationToken)).IsSuccess(out ActionResult? errorResult))
- return errorResult;
-
- TranslationResult? result = await _engineService.TranslateAsync(id, segment, cancellationToken);
- if (result == null)
- return NotFound();
+ await AuthorizeAsync(id, cancellationToken);
+ TranslationResult result = await _engineService.TranslateAsync(id, segment, cancellationToken);
return Ok(Map(result));
}
@@ -218,12 +193,12 @@ CancellationToken cancellationToken
///
/// The translation results
/// Bad request
- /// The client is not authenticated
- /// The authenticated client cannot perform the operation or does not own the translation engine
- /// The engine does not exist
- /// The method is not supported
- /// The engine needs to be built before it can translate segments
- /// A necessary service is currently unavailable. Check `/health` for more details.
+ /// The client is not authenticated.
+ /// The authenticated client cannot perform the operation or does not own the translation engine.
+ /// The engine does not exist.
+ /// The method is not supported.
+ /// The engine needs to be built before it can translate segments.
+ /// A necessary service is currently unavailable. Check `/health` for more details.
[Authorize(Scopes.ReadTranslationEngines)]
[HttpPost("{id}/translate/{n}")]
[ProducesResponseType(StatusCodes.Status200OK)]
@@ -241,17 +216,8 @@ public async Task>> TranslateNAsy
CancellationToken cancellationToken
)
{
- if (!(await AuthorizeAsync(id, cancellationToken)).IsSuccess(out ActionResult? errorResult))
- return errorResult;
-
- IEnumerable? results = await _engineService.TranslateAsync(
- id,
- n,
- segment,
- cancellationToken
- );
- if (results == null)
- return NotFound();
+ await AuthorizeAsync(id, cancellationToken);
+ IEnumerable results = await _engineService.TranslateAsync(id, n, segment, cancellationToken);
return Ok(results.Select(Map));
}
@@ -263,12 +229,12 @@ CancellationToken cancellationToken
///
/// The word graph result
/// Bad request
- /// The client is not authenticated
- /// The authenticated client cannot perform the operation or does not own the translation engine
- /// The engine does not exist
- /// The method is not supported
- /// The engine needs to be built first
- /// A necessary service is currently unavailable. Check `/health` for more details.
+ /// The client is not authenticated.
+ /// The authenticated client cannot perform the operation or does not own the translation engine.
+ /// The engine does not exist.
+ /// The method is not supported.
+ /// The engine needs to be built first.
+ /// A necessary service is currently unavailable. Check `/health` for more details.
[Authorize(Scopes.ReadTranslationEngines)]
[HttpPost("{id}/get-word-graph")]
[ProducesResponseType(StatusCodes.Status200OK)]
@@ -285,12 +251,8 @@ public async Task> GetWordGraphAsync(
CancellationToken cancellationToken
)
{
- if (!(await AuthorizeAsync(id, cancellationToken)).IsSuccess(out ActionResult? errorResult))
- return errorResult;
-
- WordGraph? wordGraph = await _engineService.GetWordGraphAsync(id, segment, cancellationToken);
- if (wordGraph == null)
- return NotFound();
+ await AuthorizeAsync(id, cancellationToken);
+ WordGraph wordGraph = await _engineService.GetWordGraphAsync(id, segment, cancellationToken);
return Ok(Map(wordGraph));
}
@@ -305,14 +267,14 @@ CancellationToken cancellationToken
/// The translation engine id
/// The segment pair
///
- /// The engine was trained successfully
+ /// The engine was trained successfully.
/// Bad request
- /// The client is not authenticated
- /// The authenticated client cannot perform the operation or does not own the translation engine
- /// The engine does not exist
- /// The method is not supported
- /// The engine needs to be built first
- /// A necessary service is currently unavailable. Check `/health` for more details.
+ /// The client is not authenticated.
+ /// The authenticated client cannot perform the operation or does not own the translation engine.
+ /// The engine does not exist.
+ /// The method is not supported.
+ /// The engine needs to be built first.
+ /// A necessary service is currently unavailable. Check `/health` for more details.
[Authorize(Scopes.UpdateTranslationEngines)]
[HttpPost("{id}/train-segment")]
[ProducesResponseType(StatusCodes.Status200OK)]
@@ -329,21 +291,14 @@ public async Task TrainSegmentAsync(
CancellationToken cancellationToken
)
{
- if (!(await AuthorizeAsync(id, cancellationToken)).IsSuccess(out ActionResult? errorResult))
- return errorResult;
-
- if (
- !await _engineService.TrainSegmentPairAsync(
- id,
- segmentPair.SourceSegment,
- segmentPair.TargetSegment,
- segmentPair.SentenceStart,
- cancellationToken
- )
- )
- {
- return NotFound();
- }
+ await AuthorizeAsync(id, cancellationToken);
+ await _engineService.TrainSegmentPairAsync(
+ id,
+ segmentPair.SourceSegment,
+ segmentPair.TargetSegment,
+ segmentPair.SentenceStart,
+ cancellationToken
+ );
return Ok();
}
@@ -372,13 +327,12 @@ CancellationToken cancellationToken
///
///
///
- /// The corpus was added successfully
+ /// The added corpus
/// Bad request
- /// The client is not authenticated
- /// The authenticated client cannot perform the operation or does not own the translation engine
- /// The engine does not exist
- /// The engine was specified incorrectly. Did you use the same language for the source and target?
- /// A necessary service is currently unavailable. Check `/health` for more details.
+ /// The client is not authenticated.
+ /// The authenticated client cannot perform the operation or does not own the translation engine.
+ /// The engine does not exist.
+ /// A necessary service is currently unavailable. Check `/health` for more details.
[Authorize(Scopes.UpdateTranslationEngines)]
[HttpPost("{id}/corpora")]
[ProducesResponseType(StatusCodes.Status201Created)]
@@ -386,7 +340,6 @@ CancellationToken cancellationToken
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)]
[ProducesResponseType(typeof(void), StatusCodes.Status404NotFound)]
- [ProducesResponseType(typeof(void), StatusCodes.Status422UnprocessableEntity)]
[ProducesResponseType(typeof(void), StatusCodes.Status503ServiceUnavailable)]
public async Task> AddCorpusAsync(
[NotNull] string id,
@@ -396,17 +349,9 @@ public async Task> AddCorpusAsync(
CancellationToken cancellationToken
)
{
- Engine? engine = await _engineService.GetAsync(id, cancellationToken);
- if (engine is null)
- return NotFound();
- if (!await AuthorizeIsOwnerAsync(engine))
- return Forbid();
+ Engine engine = await _engineService.GetAsync(id, cancellationToken);
+ await AuthorizeAsync(engine);
Corpus corpus = await MapAsync(getDataFileClient, idGenerator.GenerateId(), corpusConfig, cancellationToken);
- if (engine.SourceLanguage != corpus.SourceLanguage || engine.TargetLanguage != corpus.TargetLanguage)
- return UnprocessableEntity(
- $"Source and target languages, {corpus.SourceLanguage} & {corpus.TargetLanguage}, do not match engine source and target languages, {engine.SourceLanguage} & {engine.TargetLanguage}"
- );
-
await _engineService.AddCorpusAsync(id, corpus, cancellationToken);
TranslationCorpusDto dto = Map(id, corpus);
return Created(dto.Url, dto);
@@ -416,8 +361,8 @@ CancellationToken cancellationToken
/// Update a corpus with a new set of files
///
///
- /// See posting a new corpus for details of use. Will completely replace corpus' file associations.
- /// Will not affect jobs already queued or running. Will not affect existing pretranslations until new build is complete.
+ /// See posting a new corpus for details of use. Will completely replace corpus' file associations.
+ /// Will not affect jobs already queued or running. Will not affect existing pretranslations until new build is complete.
///
/// The translation engine id
/// The corpus id
@@ -426,10 +371,10 @@ CancellationToken cancellationToken
///
/// The corpus was updated successfully
/// Bad request
- /// The client is not authenticated
- /// The authenticated client cannot perform the operation or does not own the translation engine
- /// The engine or corpus does not exist
- /// A necessary service is currently unavailable. Check `/health` for more details.
+ /// The client is not authenticated.
+ /// The authenticated client cannot perform the operation or does not own the translation engine.
+ /// The engine or corpus does not exist.
+ /// A necessary service is currently unavailable. Check `/health` for more details.
[Authorize(Scopes.UpdateTranslationEngines)]
[HttpPatch("{id}/corpora/{corpusId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
@@ -446,10 +391,8 @@ public async Task> UpdateCorpusAsync(
CancellationToken cancellationToken
)
{
- if (!(await AuthorizeAsync(id, cancellationToken)).IsSuccess(out ActionResult? errorResult))
- return errorResult;
-
- Corpus? corpus = await _engineService.UpdateCorpusAsync(
+ await AuthorizeAsync(id, cancellationToken);
+ Corpus corpus = await _engineService.UpdateCorpusAsync(
id,
corpusId,
corpusConfig.SourceFiles is null
@@ -460,8 +403,6 @@ corpusConfig.TargetFiles is null
: await MapAsync(getDataFileClient, corpusConfig.TargetFiles, cancellationToken),
cancellationToken
);
- if (corpus is null)
- return NotFound();
return Ok(Map(id, corpus));
}
@@ -487,12 +428,8 @@ public async Task>> GetAllCorpora
CancellationToken cancellationToken
)
{
- Engine? engine = await _engineService.GetAsync(id, cancellationToken);
- if (engine == null)
- return NotFound();
- if (!await AuthorizeIsOwnerAsync(engine))
- return Forbid();
-
+ Engine engine = await _engineService.GetAsync(id, cancellationToken);
+ await AuthorizeAsync(engine);
return Ok(engine.Corpora.Select(c => Map(id, c)));
}
@@ -503,10 +440,10 @@ CancellationToken cancellationToken
/// The corpus id
///
/// The corpus configuration
- /// The client is not authenticated
- /// The authenticated client cannot perform the operation or does not own the translation engine
- /// The engine or corpus does not exist
- /// A necessary service is currently unavailable. Check `/health` for more details.
+ /// The client is not authenticated.
+ /// The authenticated client cannot perform the operation or does not own the translation engine.
+ /// The engine or corpus does not exist.
+ /// A necessary service is currently unavailable. Check `/health` for more details.
[Authorize(Scopes.ReadTranslationEngines)]
[HttpGet("{id}/corpora/{corpusId}", Name = "GetTranslationCorpus")]
[ProducesResponseType(StatusCodes.Status200OK)]
@@ -520,15 +457,11 @@ public async Task> GetCorpusAsync(
CancellationToken cancellationToken
)
{
- Engine? engine = await _engineService.GetAsync(id, cancellationToken);
- if (engine == null)
- return NotFound();
- if (!await AuthorizeIsOwnerAsync(engine))
- return Forbid();
+ Engine engine = await _engineService.GetAsync(id, cancellationToken);
+ await AuthorizeAsync(engine);
Corpus? corpus = engine.Corpora.FirstOrDefault(f => f.Id == corpusId);
if (corpus == null)
return NotFound();
-
return Ok(Map(id, corpus));
}
@@ -541,11 +474,11 @@ CancellationToken cancellationToken
/// The translation engine id
/// The corpus id
///
- /// The data file was deleted successfully
- /// The client is not authenticated
- /// The authenticated client cannot perform the operation or does not own the translation engine
- /// The engine or corpus does not exist
- /// A necessary service is currently unavailable. Check `/health` for more details.
+ /// The data file was deleted successfully.
+ /// The client is not authenticated.
+ /// The authenticated client cannot perform the operation or does not own the translation engine.
+ /// The engine or corpus does not exist.
+ /// A necessary service is currently unavailable. Check `/health` for more details.
[Authorize(Scopes.UpdateTranslationEngines)]
[HttpDelete("{id}/corpora/{corpusId}")]
[ProducesResponseType(typeof(void), StatusCodes.Status200OK)]
@@ -559,12 +492,8 @@ public async Task DeleteCorpusAsync(
CancellationToken cancellationToken
)
{
- if (!(await AuthorizeAsync(id, cancellationToken)).IsSuccess(out ActionResult? errorResult))
- return errorResult;
-
- if (!await _engineService.DeleteCorpusAsync(id, corpusId, cancellationToken))
- return NotFound();
-
+ await AuthorizeAsync(id, cancellationToken);
+ await _engineService.DeleteCorpusAsync(id, corpusId, cancellationToken);
return Ok();
}
@@ -586,11 +515,11 @@ CancellationToken cancellationToken
/// The text id (optional)
///
/// The pretranslations
- /// The client is not authenticated
- /// The authenticated client cannot perform the operation or does not own the translation engine
- /// The engine or corpus does not exist
- /// The engine needs to be built first
- /// A necessary service is currently unavailable. Check `/health` for more details.
+ /// The client is not authenticated.
+ /// The authenticated client cannot perform the operation or does not own the translation engine.
+ /// The engine or corpus does not exist.
+ /// The engine needs to be built first.
+ /// A necessary service is currently unavailable. Check `/health` for more details.
[Authorize(Scopes.ReadTranslationEngines)]
[HttpGet("{id}/corpora/{corpusId}/pretranslations")]
[ProducesResponseType(StatusCodes.Status200OK)]
@@ -606,11 +535,61 @@ public async Task>> GetAllPretransla
CancellationToken cancellationToken
)
{
- Engine? engine = await _engineService.GetAsync(id, cancellationToken);
- if (engine == null)
+ Engine engine = await _engineService.GetAsync(id, cancellationToken);
+ await AuthorizeAsync(engine);
+ if (!engine.Corpora.Any(c => c.Id == corpusId))
return NotFound();
- if (!await AuthorizeIsOwnerAsync(engine))
- return Forbid();
+ if (engine.ModelRevision == 0)
+ return Conflict();
+
+ IEnumerable pretranslations = await _pretranslationService.GetAllAsync(
+ id,
+ engine.ModelRevision,
+ corpusId,
+ textId,
+ cancellationToken
+ );
+ return Ok(pretranslations.Select(Map));
+ }
+
+ ///
+ /// Get all pretranslations for the specified text in a corpus of a translation engine
+ ///
+ ///
+ /// Pretranslations are arranged in a list of dictionaries with the following fields per pretranslation:
+ /// * **TextId**: The TextId of the SourceFile defined when the corpus was created.
+ /// * **Refs** (a list of strings): A list of references including:
+ /// * The references defined in the SourceFile per line, if any.
+ /// * An auto-generated reference of `[TextId]:[lineNumber]`, 1 indexed.
+ /// * **Translation**: the text of the pretranslation
+ ///
+ /// The translation engine id
+ /// The corpus id
+ /// The text id
+ ///
+ /// The pretranslations
+ /// The client is not authenticated.
+ /// The authenticated client cannot perform the operation or does not own the translation engine.
+ /// The engine or corpus does not exist.
+ /// The engine needs to be built first.
+ /// A necessary service is currently unavailable. Check `/health` for more details.
+ [Authorize(Scopes.ReadTranslationEngines)]
+ [HttpGet("{id}/corpora/{corpusId}/pretranslations/{textId}")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
+ [ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)]
+ [ProducesResponseType(typeof(void), StatusCodes.Status404NotFound)]
+ [ProducesResponseType(typeof(void), StatusCodes.Status409Conflict)]
+ [ProducesResponseType(typeof(void), StatusCodes.Status503ServiceUnavailable)]
+ public async Task>> GetPretranslationsByTextIdAsync(
+ [NotNull] string id,
+ [NotNull] string corpusId,
+ [NotNull] string textId,
+ CancellationToken cancellationToken
+ )
+ {
+ Engine engine = await _engineService.GetAsync(id, cancellationToken);
+ await AuthorizeAsync(engine);
if (!engine.Corpora.Any(c => c.Id == corpusId))
return NotFound();
if (engine.ModelRevision == 0)
@@ -626,16 +605,73 @@ CancellationToken cancellationToken
return Ok(pretranslations.Select(Map));
}
+ ///
+ /// Get a pretranslated Scripture book in USFM format.
+ ///
+ ///
+ /// If the USFM book exists in the target corpus, then the pretranslated text will be inserted into any empty
+ /// segments in the the target book and returned. If the USFM book does not exist in the target corpus, then the
+ /// pretranslated text will be inserted into an empty template created from the source USFM book and returned.
+ ///
+ /// The translation engine id
+ /// The corpus id
+ /// The text id
+ ///
+ /// The book in USFM format
+ /// The specified book does not exist in the source or target corpus.
+ /// The corpus is not a valid Scripture corpus.
+ /// The client is not authenticated
+ /// The authenticated client cannot perform the operation or does not own the translation engine.
+ /// The engine or corpus does not exist.
+ /// The engine needs to be built first.
+ /// A necessary service is currently unavailable. Check `/health` for more details.
+ [Authorize(Scopes.ReadTranslationEngines)]
+ [HttpGet("{id}/corpora/{corpusId}/pretranslations/{textId}/usfm")]
+ [Produces("text/plain")]
+ [ProducesResponseType(typeof(string), StatusCodes.Status200OK, "text/plain")]
+ [ProducesResponseType(typeof(void), StatusCodes.Status204NoContent)]
+ [ProducesResponseType(typeof(void), StatusCodes.Status400BadRequest)]
+ [ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
+ [ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)]
+ [ProducesResponseType(typeof(void), StatusCodes.Status404NotFound)]
+ [ProducesResponseType(typeof(void), StatusCodes.Status409Conflict)]
+ [ProducesResponseType(typeof(void), StatusCodes.Status503ServiceUnavailable)]
+ public async Task GetPretranslatedUsfmAsync(
+ [NotNull] string id,
+ [NotNull] string corpusId,
+ [NotNull] string textId,
+ CancellationToken cancellationToken
+ )
+ {
+ Engine engine = await _engineService.GetAsync(id, cancellationToken);
+ await AuthorizeAsync(engine);
+ if (!engine.Corpora.Any(c => c.Id == corpusId))
+ return NotFound();
+ if (engine.ModelRevision == 0)
+ return Conflict();
+
+ string usfm = await _pretranslationService.GetUsfmAsync(
+ id,
+ engine.ModelRevision,
+ corpusId,
+ textId,
+ cancellationToken
+ );
+ if (usfm == "")
+ return NoContent();
+ return Content(usfm, "text/plain");
+ }
+
///
/// Get all build jobs for a translation engine
///
/// The translation engine id
///
/// The build jobs
- /// The client is not authenticated
- /// The authenticated client cannot perform the operation or does not own the translation engine
- /// The engine does not exist
- /// A necessary service is currently unavailable. Check `/health` for more details.
+ /// The client is not authenticated.
+ /// The authenticated client cannot perform the operation or does not own the translation engine.
+ /// The engine does not exist.
+ /// A necessary service is currently unavailable. Check `/health` for more details.
[Authorize(Scopes.ReadTranslationEngines)]
[HttpGet("{id}/builds")]
[ProducesResponseType(StatusCodes.Status200OK)]
@@ -648,9 +684,7 @@ public async Task>> GetAllBuildsAs
CancellationToken cancellationToken
)
{
- if (!(await AuthorizeAsync(id, cancellationToken)).IsSuccess(out ActionResult? errorResult))
- return errorResult;
-
+ await AuthorizeAsync(id, cancellationToken);
return Ok((await _buildService.GetAllAsync(id, cancellationToken)).Select(Map));
}
@@ -672,16 +706,14 @@ CancellationToken cancellationToken
/// The minimum revision
///
/// The build job
- /// Bad request
- /// The client is not authenticated
- /// The authenticated client does not own the translation engine
- /// The engine or build does not exist
- /// The long polling request timed out. This is expected behavior if you're using long-polling with the minRevision strategy specified in the docs
- /// A necessary service is currently unavailable. Check `/health` for more details.
+ /// The client is not authenticated.
+ /// The authenticated client does not own the translation engine.
+ /// The engine or build does not exist.
+ /// The long polling request timed out. This is expected behavior if you're using long-polling with the minRevision strategy specified in the docs.
+ /// A necessary service is currently unavailable. Check `/health` for more details.
[Authorize(Scopes.ReadTranslationEngines)]
[HttpGet("{id}/builds/{buildId}", Name = "GetTranslationBuild")]
[ProducesResponseType(StatusCodes.Status200OK)]
- [ProducesResponseType(typeof(void), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)]
[ProducesResponseType(typeof(void), StatusCodes.Status404NotFound)]
@@ -694,9 +726,7 @@ public async Task> GetBuildAsync(
CancellationToken cancellationToken
)
{
- if (!(await AuthorizeAsync(id, cancellationToken)).IsSuccess(out ActionResult? errorResult))
- return errorResult;
-
+ await AuthorizeAsync(id, cancellationToken);
if (minRevision != null)
{
EntityChange change = await TaskEx.Timeout(
@@ -713,10 +743,7 @@ CancellationToken cancellationToken
}
else
{
- Build? build = await _buildService.GetAsync(buildId, cancellationToken);
- if (build == null)
- return NotFound();
-
+ Build build = await _buildService.GetAsync(buildId, cancellationToken);
return Ok(Map(build));
}
}
@@ -743,12 +770,12 @@ CancellationToken cancellationToken
/// The translation engine id
/// The build config (see remarks)
///
- /// The build job was started successfully
- /// A corpus id is invalid
- /// The client is not authenticated
- /// The authenticated client does not own the translation engine
- /// The engine does not exist
- /// There is already an active or pending build or a build in the process of being canceled
+ /// The new build job
+ /// A corpus id is invalid.
+ /// The client is not authenticated.
+ /// The authenticated client does not own the translation engine.
+ /// The engine does not exist.
+ /// There is already an active or pending build or a build in the process of being canceled.
/// A necessary service is currently unavailable. Check `/health` for more details.
[Authorize(Scopes.UpdateTranslationEngines)]
[HttpPost("{id}/builds")]
@@ -765,30 +792,10 @@ public async Task> StartBuildAsync(
CancellationToken cancellationToken
)
{
- Engine? engine = await _engineService.GetAsync(id, cancellationToken);
- if (engine is null)
- return NotFound();
- if (!await AuthorizeIsOwnerAsync(engine))
- return Forbid();
-
- if (await _buildService.GetActiveAsync(id) is not null)
- return Conflict();
-
- Build build;
- try
- {
- build = Map(engine, buildConfig);
- }
- catch (InvalidOperationException ioe)
- {
- return BadRequest(ioe.Message);
- }
- catch (ArgumentException ae)
- {
- return BadRequest(ae.Message);
- }
- if (!await _engineService.StartBuildAsync(build, cancellationToken))
- return NotFound();
+ Engine engine = await _engineService.GetAsync(id, cancellationToken);
+ await AuthorizeAsync(engine);
+ Build build = Map(engine, buildConfig);
+ await _engineService.StartBuildAsync(build, cancellationToken);
var dto = Map(build);
return Created(dto.Url, dto);
@@ -804,13 +811,13 @@ CancellationToken cancellationToken
/// The minimum revision
///
/// The build job
- /// There is no build currently running
+ /// There is no build currently running.
/// Bad request
- /// The client is not authenticated
- /// The authenticated client does not own the translation engine
- /// The engine does not exist
- /// The long polling request timed out. This is expected behavior if you're using long-polling with the minRevision strategy specified in the docs
- /// A necessary service is currently unavailable. Check `/health` for more details.
+ /// The client is not authenticated.
+ /// The authenticated client does not own the translation engine.
+ /// The engine does not exist.
+ /// The long polling request timed out. This is expected behavior if you're using long-polling with the minRevision strategy specified in the docs.
+ /// A necessary service is currently unavailable. Check `/health` for more details.
[Authorize(Scopes.ReadTranslationEngines)]
[HttpGet("{id}/current-build")]
[ProducesResponseType(StatusCodes.Status200OK)]
@@ -827,9 +834,7 @@ public async Task> GetCurrentBuildAsync(
CancellationToken cancellationToken
)
{
- if (!(await AuthorizeAsync(id, cancellationToken)).IsSuccess(out ActionResult? errorResult))
- return errorResult;
-
+ await AuthorizeAsync(id, cancellationToken);
if (minRevision != null)
{
EntityChange change = await TaskEx.Timeout(
@@ -861,15 +866,17 @@ CancellationToken cancellationToken
///
/// The translation engine id
///
- /// The build job was cancelled successfully
- /// The client is not authenticated
- /// The authenticated client does not own the translation engine
- /// The engine does not exist or there is no active build
- /// The translation engine does not support cancelling builds
- /// A necessary service is currently unavailable. Check `/health` for more details.
+ /// The build job was cancelled successfully.
+ /// There is no active build job.
+ /// The client is not authenticated.
+ /// The authenticated client does not own the translation engine.
+ /// The engine does not exist.
+ /// The translation engine does not support cancelling builds.
+ /// A necessary service is currently unavailable. Check `/health` for more details.
[Authorize(Scopes.UpdateTranslationEngines)]
[HttpPost("{id}/current-build/cancel")]
[ProducesResponseType(typeof(void), StatusCodes.Status200OK)]
+ [ProducesResponseType(typeof(void), StatusCodes.Status204NoContent)]
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)]
[ProducesResponseType(typeof(void), StatusCodes.Status404NotFound)]
@@ -877,24 +884,16 @@ CancellationToken cancellationToken
[ProducesResponseType(typeof(void), StatusCodes.Status503ServiceUnavailable)]
public async Task CancelBuildAsync([NotNull] string id, CancellationToken cancellationToken)
{
- if (!(await AuthorizeAsync(id, cancellationToken)).IsSuccess(out ActionResult? errorResult))
- return errorResult;
-
- if (await _buildService.GetActiveAsync(id) == null)
- return NotFound();
-
- await _engineService.CancelBuildAsync(id, cancellationToken);
+ await AuthorizeAsync(id, cancellationToken);
+ if (!await _engineService.CancelBuildAsync(id, cancellationToken))
+ return NoContent();
return Ok();
}
- private async Task<(bool, ActionResult?)> AuthorizeAsync(string id, CancellationToken cancellationToken)
+ private async Task AuthorizeAsync(string id, CancellationToken cancellationToken)
{
- Engine? engine = await _engineService.GetAsync(id, cancellationToken);
- if (engine == null)
- return (false, NotFound());
- if (!await AuthorizeIsOwnerAsync(engine))
- return (false, Forbid());
- return (true, null);
+ Engine engine = await _engineService.GetAsync(id, cancellationToken);
+ await AuthorizeAsync(engine);
}
private async Task MapAsync(
@@ -1001,7 +1000,7 @@ private static Build Map(Engine engine, TranslationBuildConfigDto source)
}
catch (Exception e)
{
- throw new ArgumentException($"Unable to parse field 'options' : {e.Message}");
+ throw new InvalidOperationException($"Unable to parse field 'options' : {e.Message}", e);
}
return build;
}
diff --git a/src/Serval.Translation/Services/EngineService.cs b/src/Serval.Translation/Services/EngineService.cs
index 8113b2f9..2159e42b 100644
--- a/src/Serval.Translation/Services/EngineService.cs
+++ b/src/Serval.Translation/Services/EngineService.cs
@@ -19,15 +19,13 @@ ILoggerFactory loggerFactory
private readonly IDataAccessContext _dataAccessContext = dataAccessContext;
private readonly ILogger _logger = loggerFactory.CreateLogger();
- public async Task TranslateAsync(
+ public async Task TranslateAsync(
string engineId,
string segment,
CancellationToken cancellationToken = default
)
{
- Engine? engine = await GetAsync(engineId, cancellationToken);
- if (engine == null)
- return null;
+ Engine engine = await GetAsync(engineId, cancellationToken);
var client = _grpcClientFactory.CreateClient(engine.Type);
TranslateResponse response = await client.TranslateAsync(
@@ -43,16 +41,14 @@ ILoggerFactory loggerFactory
return Map(response.Results[0]);
}
- public async Task?> TranslateAsync(
+ public async Task> TranslateAsync(
string engineId,
int n,
string segment,
CancellationToken cancellationToken = default
)
{
- Engine? engine = await GetAsync(engineId, cancellationToken);
- if (engine == null)
- return null;
+ Engine engine = await GetAsync(engineId, cancellationToken);
var client = _grpcClientFactory.CreateClient(engine.Type);
TranslateResponse response = await client.TranslateAsync(
@@ -68,15 +64,13 @@ ILoggerFactory loggerFactory
return response.Results.Select(Map);
}
- public async Task GetWordGraphAsync(
+ public async Task GetWordGraphAsync(
string engineId,
string segment,
CancellationToken cancellationToken = default
)
{
- Engine? engine = await GetAsync(engineId, cancellationToken);
- if (engine == null)
- return null;
+ Engine engine = await GetAsync(engineId, cancellationToken);
var client = _grpcClientFactory.CreateClient(engine.Type);
GetWordGraphResponse response = await client.GetWordGraphAsync(
@@ -91,7 +85,7 @@ ILoggerFactory loggerFactory
return Map(response.WordGraph);
}
- public async Task TrainSegmentPairAsync(
+ public async Task TrainSegmentPairAsync(
string engineId,
string sourceSegment,
string targetSegment,
@@ -99,9 +93,7 @@ public async Task TrainSegmentPairAsync(
CancellationToken cancellationToken = default
)
{
- Engine? engine = await GetAsync(engineId, cancellationToken);
- if (engine == null)
- return false;
+ Engine engine = await GetAsync(engineId, cancellationToken);
var client = _grpcClientFactory.CreateClient(engine.Type);
await client.TrainSegmentPairAsync(
@@ -115,7 +107,6 @@ await client.TrainSegmentPairAsync(
},
cancellationToken: cancellationToken
);
- return true;
}
public async Task> GetAllAsync(string owner, CancellationToken cancellationToken = default)
@@ -123,7 +114,7 @@ public async Task> GetAllAsync(string owner, CancellationTok
return await Entities.GetAllAsync(e => e.Owner == owner, cancellationToken);
}
- public override async Task CreateAsync(Engine engine, CancellationToken cancellationToken = default)
+ public override async Task CreateAsync(Engine engine, CancellationToken cancellationToken = default)
{
await Entities.InsertAsync(engine, cancellationToken);
try
@@ -131,7 +122,7 @@ public override async Task CreateAsync(Engine engine, CancellationToken ca
TranslationEngineApi.TranslationEngineApiClient? client =
_grpcClientFactory.CreateClient(engine.Type);
if (client is null)
- return false;
+ throw new InvalidOperationException($"'{engine.Type}' is an invalid engine type.");
var request = new CreateRequest
{
EngineType = engine.Type,
@@ -142,7 +133,6 @@ public override async Task CreateAsync(Engine engine, CancellationToken ca
if (engine.Name is not null)
request.EngineName = engine.Name;
await client.CreateAsync(request, cancellationToken: cancellationToken);
- return true;
}
catch
{
@@ -151,11 +141,11 @@ public override async Task CreateAsync(Engine engine, CancellationToken ca
}
}
- public override async Task DeleteAsync(string engineId, CancellationToken cancellationToken = default)
+ public override async Task DeleteAsync(string engineId, CancellationToken cancellationToken = default)
{
Engine? engine = await Entities.GetAsync(engineId, cancellationToken);
- if (engine == null)
- return false;
+ if (engine is null)
+ throw new EntityNotFoundException($"Could not find the Engine '{engineId}'.");
var client = _grpcClientFactory.CreateClient(engine.Type);
await client.DeleteAsync(
@@ -168,16 +158,11 @@ await client.DeleteAsync(
await _builds.DeleteAllAsync(b => b.EngineRef == engineId, CancellationToken.None);
await _pretranslations.DeleteAllAsync(pt => pt.EngineRef == engineId, CancellationToken.None);
await _dataAccessContext.CommitTransactionAsync(CancellationToken.None);
-
- return true;
}
- public async Task StartBuildAsync(Build build, CancellationToken cancellationToken = default)
+ public async Task StartBuildAsync(Build build, CancellationToken cancellationToken = default)
{
- Engine? engine = await GetAsync(build.EngineRef, cancellationToken);
- if (engine == null)
- return false;
-
+ Engine engine = await GetAsync(build.EngineRef, cancellationToken);
await _builds.InsertAsync(build, cancellationToken);
try
@@ -253,21 +238,29 @@ public async Task StartBuildAsync(Build build, CancellationToken cancellat
await _builds.DeleteAsync(build, CancellationToken.None);
throw;
}
-
- return true;
}
- public async Task CancelBuildAsync(string engineId, CancellationToken cancellationToken = default)
+ public async Task CancelBuildAsync(string engineId, CancellationToken cancellationToken = default)
{
Engine? engine = await GetAsync(engineId, cancellationToken);
- if (engine == null)
- return;
+ if (engine is null)
+ throw new EntityNotFoundException($"Could not find the Engine '{engineId}'.");
var client = _grpcClientFactory.CreateClient(engine.Type);
- await client.CancelBuildAsync(
- new CancelBuildRequest { EngineType = engine.Type, EngineId = engine.Id },
- cancellationToken: cancellationToken
- );
+ try
+ {
+ await client.CancelBuildAsync(
+ new CancelBuildRequest { EngineType = engine.Type, EngineId = engine.Id },
+ cancellationToken: cancellationToken
+ );
+ }
+ catch (RpcException re)
+ {
+ if (re.StatusCode is StatusCode.Aborted)
+ return false;
+ throw;
+ }
+ return true;
}
public Task AddCorpusAsync(string engineId, Models.Corpus corpus, CancellationToken cancellationToken = default)
@@ -275,7 +268,7 @@ public Task AddCorpusAsync(string engineId, Models.Corpus corpus, CancellationTo
return Entities.UpdateAsync(engineId, u => u.Add(e => e.Corpora, corpus), cancellationToken: cancellationToken);
}
- public async Task UpdateCorpusAsync(
+ public async Task UpdateCorpusAsync(
string engineId,
string corpusId,
IList? sourceFiles,
@@ -294,14 +287,12 @@ public Task AddCorpusAsync(string engineId, Models.Corpus corpus, CancellationTo
},
cancellationToken: cancellationToken
);
- return engine?.Corpora.FirstOrDefault(c => c.Id == corpusId);
+ if (engine is null)
+ throw new EntityNotFoundException($"Could not find the Corpus '{corpusId}' in Engine '{engineId}'.");
+ return engine.Corpora.First(c => c.Id == corpusId);
}
- public async Task DeleteCorpusAsync(
- string engineId,
- string corpusId,
- CancellationToken cancellationToken = default
- )
+ public async Task DeleteCorpusAsync(string engineId, string corpusId, CancellationToken cancellationToken = default)
{
await _dataAccessContext.BeginTransactionAsync(cancellationToken);
Engine? originalEngine = await Entities.UpdateAsync(
@@ -310,9 +301,10 @@ public async Task DeleteCorpusAsync(
returnOriginal: true,
cancellationToken: cancellationToken
);
+ if (originalEngine is null || !originalEngine.Corpora.Any(c => c.Id == corpusId))
+ throw new EntityNotFoundException($"Could not find the Corpus '{corpusId}' in Engine '{engineId}'.");
await _pretranslations.DeleteAllAsync(pt => pt.CorpusRef == corpusId, cancellationToken);
await _dataAccessContext.CommitTransactionAsync(cancellationToken);
- return originalEngine is not null && originalEngine.Corpora.Any(c => c.Id == corpusId);
}
public Task DeleteAllCorpusFilesAsync(string dataFileId, CancellationToken cancellationToken = default)
diff --git a/src/Serval.Translation/Services/IBuildService.cs b/src/Serval.Translation/Services/IBuildService.cs
index e3ab12a6..4fc13dee 100644
--- a/src/Serval.Translation/Services/IBuildService.cs
+++ b/src/Serval.Translation/Services/IBuildService.cs
@@ -3,7 +3,7 @@
public interface IBuildService
{
Task> GetAllAsync(string parentId, CancellationToken cancellationToken = default);
- Task GetAsync(string id, CancellationToken cancellationToken = default);
+ Task GetAsync(string id, CancellationToken cancellationToken = default);
Task GetActiveAsync(string parentId, CancellationToken cancellationToken = default);
Task> GetNewerRevisionAsync(
string id,
diff --git a/src/Serval.Translation/Services/IEngineService.cs b/src/Serval.Translation/Services/IEngineService.cs
index fa88dfa7..49cafbf1 100644
--- a/src/Serval.Translation/Services/IEngineService.cs
+++ b/src/Serval.Translation/Services/IEngineService.cs
@@ -3,27 +3,27 @@
public interface IEngineService
{
Task> GetAllAsync(string owner, CancellationToken cancellationToken = default);
- Task GetAsync(string engineId, CancellationToken cancellationToken = default);
+ Task GetAsync(string engineId, CancellationToken cancellationToken = default);
- Task CreateAsync(Engine engine, CancellationToken cancellationToken = default);
- Task DeleteAsync(string engineId, CancellationToken cancellationToken = default);
+ Task CreateAsync(Engine engine, CancellationToken cancellationToken = default);
+ Task DeleteAsync(string engineId, CancellationToken cancellationToken = default);
- Task TranslateAsync(
+ Task TranslateAsync(
string engineId,
string segment,
CancellationToken cancellationToken = default
);
- Task?> TranslateAsync(
+ Task> TranslateAsync(
string engineId,
int n,
string segment,
CancellationToken cancellationToken = default
);
- Task GetWordGraphAsync(string engineId, string segment, CancellationToken cancellationToken = default);
+ Task GetWordGraphAsync(string engineId, string segment, CancellationToken cancellationToken = default);
- Task TrainSegmentPairAsync(
+ Task TrainSegmentPairAsync(
string engineId,
string sourceSegment,
string targetSegment,
@@ -31,19 +31,19 @@ Task TrainSegmentPairAsync(
CancellationToken cancellationToken = default
);
- Task StartBuildAsync(Build build, CancellationToken cancellationToken = default);
+ Task StartBuildAsync(Build build, CancellationToken cancellationToken = default);
- Task CancelBuildAsync(string engineId, CancellationToken cancellationToken = default);
+ Task CancelBuildAsync(string engineId, CancellationToken cancellationToken = default);
Task AddCorpusAsync(string engineId, Corpus corpus, CancellationToken cancellationToken = default);
- Task UpdateCorpusAsync(
+ Task UpdateCorpusAsync(
string engineId,
string corpusId,
IList? sourceFiles,
IList? targetFiles,
CancellationToken cancellationToken = default
);
- Task DeleteCorpusAsync(string engineId, string corpusId, CancellationToken cancellationToken = default);
+ Task DeleteCorpusAsync(string engineId, string corpusId, CancellationToken cancellationToken = default);
Task DeleteAllCorpusFilesAsync(string dataFileId, CancellationToken cancellationToken = default);
diff --git a/src/Serval.Translation/Services/IPretranslationService.cs b/src/Serval.Translation/Services/IPretranslationService.cs
index 40ea2920..146c945b 100644
--- a/src/Serval.Translation/Services/IPretranslationService.cs
+++ b/src/Serval.Translation/Services/IPretranslationService.cs
@@ -9,4 +9,12 @@ Task> GetAllAsync(
string? textId = null,
CancellationToken cancellationToken = default
);
+
+ Task GetUsfmAsync(
+ string engineId,
+ int modelRevision,
+ string corpusId,
+ string textId,
+ CancellationToken cancellationToken = default
+ );
}
diff --git a/src/Serval.Translation/Services/PretranslationService.cs b/src/Serval.Translation/Services/PretranslationService.cs
index 917f1239..589b7452 100644
--- a/src/Serval.Translation/Services/PretranslationService.cs
+++ b/src/Serval.Translation/Services/PretranslationService.cs
@@ -1,9 +1,15 @@
-namespace Serval.Translation.Services;
+using SIL.Machine.Corpora;
-public class PretranslationService : EntityServiceBase, IPretranslationService
+namespace Serval.Translation.Services;
+
+public class PretranslationService(
+ IRepository pretranslations,
+ IRepository engines,
+ IScriptureDataFileService scriptureDataFileService
+) : EntityServiceBase(pretranslations), IPretranslationService
{
- public PretranslationService(IRepository pretranslations)
- : base(pretranslations) { }
+ private readonly IRepository _engines = engines;
+ private readonly IScriptureDataFileService _scriptureDataFileService = scriptureDataFileService;
public async Task> GetAllAsync(
string engineId,
@@ -22,4 +28,71 @@ public async Task> GetAllAsync(
cancellationToken
);
}
+
+ public async Task GetUsfmAsync(
+ string engineId,
+ int modelRevision,
+ string corpusId,
+ string textId,
+ CancellationToken cancellationToken = default
+ )
+ {
+ Engine? engine = await _engines.GetAsync(engineId, cancellationToken);
+ Corpus? corpus = engine?.Corpora.SingleOrDefault(c => c.Id == corpusId);
+ if (corpus is null)
+ throw new EntityNotFoundException($"Could not find the Corpus '{corpusId}' in Engine '{engineId}'.");
+
+ CorpusFile sourceFile = corpus.SourceFiles.First();
+ CorpusFile targetFile = corpus.TargetFiles.First();
+ if (sourceFile.Format is not FileFormat.Paratext || targetFile.Format is not FileFormat.Paratext)
+ throw new InvalidOperationException("USFM format is not valid for non-Scripture corpora.");
+
+ ParatextProjectSettings sourceSettings = _scriptureDataFileService.GetParatextProjectSettings(
+ sourceFile.Filename
+ );
+ ParatextProjectSettings targetSettings = _scriptureDataFileService.GetParatextProjectSettings(
+ targetFile.Filename
+ );
+
+ IReadOnlyList<(IReadOnlyList, string)> pretranslations = (
+ await GetAllAsync(engineId, modelRevision, corpusId, textId, cancellationToken)
+ )
+ .Select(p =>
+ (
+ (IReadOnlyList)p.Refs.Select(r => new VerseRef(r, targetSettings.Versification)).ToList(),
+ p.Translation
+ )
+ )
+ .OrderBy(p => p.Item1[0])
+ .ToList();
+
+ // Update the target book if it exists
+ string? usfm = await _scriptureDataFileService.ReadParatextProjectBookAsync(targetFile.Filename, textId);
+ if (usfm is not null)
+ return UpdateUsfm(targetSettings, usfm, pretranslations);
+
+ // Copy and update the source book if it exists
+ usfm = await _scriptureDataFileService.ReadParatextProjectBookAsync(sourceFile.Filename, textId);
+ if (usfm is not null)
+ return UpdateUsfm(sourceSettings, usfm, pretranslations, targetSettings.FullName, stripAllText: true);
+
+ return "";
+ }
+
+ private static string UpdateUsfm(
+ ParatextProjectSettings settings,
+ string usfm,
+ IReadOnlyList<(IReadOnlyList, string)> pretranslations,
+ string? fullName = null,
+ bool stripAllText = false
+ )
+ {
+ var updater = new UsfmVerseTextUpdater(
+ pretranslations,
+ fullName is null ? null : $"- {fullName}",
+ stripAllText
+ );
+ UsfmParser.Parse(usfm, updater, settings.Stylesheet, settings.Versification);
+ return updater.GetUsfm(settings.Stylesheet);
+ }
}
diff --git a/src/Serval.Translation/Usings.cs b/src/Serval.Translation/Usings.cs
index 77bb4439..1fda2ed5 100644
--- a/src/Serval.Translation/Usings.cs
+++ b/src/Serval.Translation/Usings.cs
@@ -27,3 +27,4 @@
global using Serval.Translation.Models;
global using Serval.Translation.Services;
global using SIL.DataAccess;
+global using SIL.Scripture;
diff --git a/src/Serval.Webhooks/Controllers/WebhooksController.cs b/src/Serval.Webhooks/Controllers/WebhooksController.cs
index d7bf81a7..83cd5ba8 100644
--- a/src/Serval.Webhooks/Controllers/WebhooksController.cs
+++ b/src/Serval.Webhooks/Controllers/WebhooksController.cs
@@ -45,12 +45,8 @@ public async Task> GetAllAsync(CancellationToken cancell
[ProducesResponseType(typeof(void), StatusCodes.Status503ServiceUnavailable)]
public async Task> GetAsync([NotNull] string id, CancellationToken cancellationToken)
{
- Webhook? hook = await _hookService.GetAsync(id, cancellationToken);
- if (hook == null)
- return NotFound();
- if (!await AuthorizeIsOwnerAsync(hook))
- return Forbid();
-
+ Webhook hook = await _hookService.GetAsync(id, cancellationToken);
+ await AuthorizeAsync(hook);
return Ok(Map(hook));
}
@@ -93,17 +89,17 @@ CancellationToken cancellationToken
[ProducesResponseType(typeof(void), StatusCodes.Status503ServiceUnavailable)]
public async Task DeleteAsync([NotNull] string id, CancellationToken cancellationToken)
{
- Webhook? hook = await _hookService.GetAsync(id, cancellationToken);
- if (hook == null)
- return NotFound();
- if (!await AuthorizeIsOwnerAsync(hook))
- return Forbid();
-
- if (!await _hookService.DeleteAsync(id, cancellationToken))
- return NotFound();
+ await AuthorizeAsync(id, cancellationToken);
+ await _hookService.DeleteAsync(id, cancellationToken);
return Ok();
}
+ private async Task AuthorizeAsync(string id, CancellationToken cancellationToken)
+ {
+ Webhook hook = await _hookService.GetAsync(id, cancellationToken);
+ await AuthorizeAsync(hook);
+ }
+
private WebhookDto Map(Webhook source)
{
return new WebhookDto
diff --git a/src/Serval.Webhooks/Services/IWebhookService.cs b/src/Serval.Webhooks/Services/IWebhookService.cs
index 03e479a6..30a8e91c 100644
--- a/src/Serval.Webhooks/Services/IWebhookService.cs
+++ b/src/Serval.Webhooks/Services/IWebhookService.cs
@@ -3,10 +3,10 @@
public interface IWebhookService
{
Task> GetAllAsync(string owner, CancellationToken cancellationToken = default);
- Task GetAsync(string id, CancellationToken cancellationToken = default);
+ Task GetAsync(string id, CancellationToken cancellationToken = default);
Task CreateAsync(Webhook hook, CancellationToken cancellationToken = default);
- Task DeleteAsync(string id, CancellationToken cancellationToken = default);
+ Task DeleteAsync(string id, CancellationToken cancellationToken = default);
Task SendEventAsync(
WebhookEvent webhookEvent,
diff --git a/tests/SIL.DataAccess.Tests/SIL.DataAccess.Tests.csproj b/tests/SIL.DataAccess.Tests/SIL.DataAccess.Tests.csproj
index 9f7b61a8..8848ce87 100644
--- a/tests/SIL.DataAccess.Tests/SIL.DataAccess.Tests.csproj
+++ b/tests/SIL.DataAccess.Tests/SIL.DataAccess.Tests.csproj
@@ -13,15 +13,15 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
-
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/tests/Serval.ApiServer.IntegrationTests/DataFilesTests.cs b/tests/Serval.ApiServer.IntegrationTests/DataFilesTests.cs
index d3737abd..6828234a 100644
--- a/tests/Serval.ApiServer.IntegrationTests/DataFilesTests.cs
+++ b/tests/Serval.ApiServer.IntegrationTests/DataFilesTests.cs
@@ -4,7 +4,7 @@ namespace Serval.ApiServer;
[Category("Integration")]
public class DataFilesTests
{
- TestEnvironment? _env;
+ TestEnvironment _env;
const string ID1 = "000000000000000000000001";
const string NAME1 = "sample1.txt";
@@ -53,7 +53,7 @@ public async Task SetUp()
[TestCase(new[] { Scopes.CreateTranslationEngines }, 403)]
public async Task GetAllAsync(IEnumerable scope, int expectedStatusCode)
{
- DataFilesClient client = _env!.CreateClient(scope);
+ DataFilesClient client = _env.CreateClient(scope);
switch (expectedStatusCode)
{
case 200:
@@ -72,7 +72,7 @@ public async Task GetAllAsync(IEnumerable scope, int expectedStatusCode)
await client.GetAllAsync();
});
Assert.That(ex, Is.Not.Null);
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
break;
default:
@@ -89,7 +89,7 @@ public async Task GetAllAsync(IEnumerable scope, int expectedStatusCode)
[TestCase(new[] { Scopes.ReadFiles }, 404, DOES_NOT_EXIST_ID)]
public async Task GetByIDAsync(IEnumerable scope, int expectedStatusCode, string fileId)
{
- DataFilesClient client = _env!.CreateClient(scope);
+ DataFilesClient client = _env.CreateClient(scope);
switch (expectedStatusCode)
{
case 200:
@@ -105,7 +105,7 @@ public async Task GetByIDAsync(IEnumerable scope, int expectedStatusCode
{
await client.GetAsync(fileId);
});
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
break;
default:
Assert.Fail("Invalid expectedStatusCode. Check test case for typo.");
@@ -120,8 +120,7 @@ public async Task GetByIDAsync(IEnumerable scope, int expectedStatusCode
[TestCase(new[] { Scopes.ReadFiles }, 403)]
public async Task CreateAsync(IEnumerable scope, int expectedStatusCode)
{
- DataFilesClient client = _env!.CreateClient(scope);
- ServalApiException ex;
+ DataFilesClient client = _env.CreateClient(scope);
switch (expectedStatusCode)
{
case 201:
@@ -141,23 +140,23 @@ public async Task CreateAsync(IEnumerable scope, int expectedStatusCode)
{
var fp = new FileParameter(fs);
fp = new FileParameter(fs);
- ex = Assert.ThrowsAsync(async () =>
+ var ex = Assert.ThrowsAsync(async () =>
{
- await client.CreateAsync(fp, Client.FileFormat.Text);
+ await client.CreateAsync(fp, FileFormat.Text);
});
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
}
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
break;
case 403:
using (var fs = new MemoryStream())
{
var fp = new FileParameter(fs);
- ex = Assert.ThrowsAsync(async () =>
+ var ex = Assert.ThrowsAsync(async () =>
{
await client.CreateAsync(fp, Client.FileFormat.Text);
});
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
}
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
break;
default:
Assert.Fail("Unanticipated expectedStatusCode. Check test case for typo.");
@@ -172,8 +171,7 @@ public async Task CreateAsync(IEnumerable scope, int expectedStatusCode)
[TestCase(new[] { Scopes.CreateFiles, Scopes.ReadFiles }, 404, DOES_NOT_EXIST_ID)]
public async Task DownloadAsync(IEnumerable scope, int expectedStatusCode, string fileId)
{
- DataFilesClient client = _env!.CreateClient(scope);
- ServalApiException ex;
+ DataFilesClient client = _env.CreateClient(scope);
string content = "This is a file.";
var contentBytes = Encoding.UTF8.GetBytes(content);
@@ -206,20 +204,24 @@ public async Task DownloadAsync(IEnumerable scope, int expectedStatusCod
}
break;
case 400:
- ex = Assert.ThrowsAsync(async () =>
+ {
+ var ex = Assert.ThrowsAsync(async () =>
{
await client.DownloadAsync(fileId);
});
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
break;
+ }
case 403:
case 404:
- ex = Assert.ThrowsAsync(async () =>
+ {
+ var ex = Assert.ThrowsAsync(async () =>
{
await client.DownloadAsync(fileId);
});
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
break;
+ }
default:
Assert.Fail("Unanticipated expectedStatusCode. Check test case for typo.");
break;
@@ -234,8 +236,7 @@ public async Task DownloadAsync(IEnumerable scope, int expectedStatusCod
[TestCase(new[] { Scopes.UpdateFiles, Scopes.ReadFiles }, 404, DOES_NOT_EXIST_ID)]
public async Task UpdateAsync(IEnumerable scope, int expectedStatusCode, string fileId)
{
- DataFilesClient client = _env!.CreateClient(scope);
- ServalApiException ex;
+ DataFilesClient client = _env.CreateClient(scope);
switch (expectedStatusCode)
{
case 200:
@@ -249,20 +250,24 @@ public async Task UpdateAsync(IEnumerable scope, int expectedStatusCode,
Assert.That(resultAfterUpdate.Id, Is.EqualTo(ID1));
break;
case 400:
- ex = Assert.ThrowsAsync(async () =>
+ {
+ var ex = Assert.ThrowsAsync(async () =>
{
await client.UpdateAsync(fileId, new FileParameter(new MemoryStream(new byte[2_000_000_000])));
});
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
break;
+ }
case 403:
case 404:
- ex = Assert.ThrowsAsync(async () =>
+ {
+ var ex = Assert.ThrowsAsync(async () =>
{
await client.UpdateAsync(fileId, new FileParameter(new MemoryStream()));
});
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
break;
+ }
default:
Assert.Fail("Unanticipated expectedStatusCode. Check test case for typo.");
break;
@@ -277,7 +282,7 @@ public async Task UpdateAsync(IEnumerable scope, int expectedStatusCode,
[TestCase(new[] { Scopes.DeleteFiles, Scopes.ReadFiles }, 404, DOES_NOT_EXIST_ID)]
public async Task DeleteAsync(IEnumerable scope, int expectedStatusCode, string fileId)
{
- DataFilesClient client = _env!.CreateClient(scope);
+ DataFilesClient client = _env.CreateClient(scope);
switch (expectedStatusCode)
{
case 200:
@@ -297,7 +302,7 @@ public async Task DeleteAsync(IEnumerable scope, int expectedStatusCode,
{
await client.DeleteAsync(fileId);
});
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
ICollection resultsAfterDelete = await client.GetAllAsync();
Assert.That(resultsAfterDelete, Has.Count.EqualTo(2));
break;
@@ -310,12 +315,12 @@ public async Task DeleteAsync(IEnumerable scope, int expectedStatusCode,
[TearDown]
public void TearDown()
{
- _env!.Dispose();
+ _env.Dispose();
}
private class TestEnvironment : DisposableBase
{
- private readonly IMongoClient _mongoClient;
+ private readonly MongoClient _mongoClient;
private readonly IServiceScope _scope;
public TestEnvironment()
diff --git a/tests/Serval.ApiServer.IntegrationTests/Serval.ApiServer.IntegrationTests.csproj b/tests/Serval.ApiServer.IntegrationTests/Serval.ApiServer.IntegrationTests.csproj
index a05921d4..89dcc1e1 100644
--- a/tests/Serval.ApiServer.IntegrationTests/Serval.ApiServer.IntegrationTests.csproj
+++ b/tests/Serval.ApiServer.IntegrationTests/Serval.ApiServer.IntegrationTests.csproj
@@ -17,16 +17,16 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
-
-
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/tests/Serval.ApiServer.IntegrationTests/TranslationEngineTests.cs b/tests/Serval.ApiServer.IntegrationTests/TranslationEngineTests.cs
index 85257e29..1fadc355 100644
--- a/tests/Serval.ApiServer.IntegrationTests/TranslationEngineTests.cs
+++ b/tests/Serval.ApiServer.IntegrationTests/TranslationEngineTests.cs
@@ -7,7 +7,7 @@ namespace Serval.ApiServer;
[Category("Integration")]
public class TranslationEngineTests
{
- private readonly TranslationCorpusConfig TestCorpusConfig =
+ private static readonly TranslationCorpusConfig TestCorpusConfig =
new()
{
Name = "TestCorpus",
@@ -22,7 +22,7 @@ public class TranslationEngineTests
new TranslationCorpusFileConfig { FileId = FILE2_ID, TextId = "all" }
}
};
- private readonly TranslationCorpusConfig TestCorpusConfigNonEcho =
+ private static readonly TranslationCorpusConfig TestCorpusConfigNonEcho =
new()
{
Name = "TestCorpus",
@@ -38,6 +38,16 @@ public class TranslationEngineTests
}
};
+ private static readonly TranslationCorpusConfig TestCorpusConfigScripture =
+ new()
+ {
+ Name = "TestCorpus",
+ SourceLanguage = "en",
+ TargetLanguage = "en",
+ SourceFiles = { new TranslationCorpusFileConfig { FileId = FILE3_ID } },
+ TargetFiles = { new TranslationCorpusFileConfig { FileId = FILE4_ID } }
+ };
+
private const string ECHO_ENGINE1_ID = "e00000000000000000000001";
private const string ECHO_ENGINE2_ID = "e00000000000000000000002";
private const string ECHO_ENGINE3_ID = "e00000000000000000000003";
@@ -47,10 +57,15 @@ public class TranslationEngineTests
private const string FILE1_FILENAME = "abcd";
private const string FILE2_ID = "f00000000000000000000002";
private const string FILE2_FILENAME = "efgh";
+ private const string FILE3_ID = "f00000000000000000000003";
+ private const string FILE3_FILENAME = "ijkl";
+ private const string FILE4_ID = "f00000000000000000000004";
+ private const string FILE4_FILENAME = "mnop";
+
private const string DOES_NOT_EXIST_ENGINE_ID = "e00000000000000000000004";
private const string DOES_NOT_EXIST_CORPUS_ID = "c00000000000000000000001";
- private TestEnvironment? _env;
+ private TestEnvironment _env;
[SetUp]
public async Task SetUp()
@@ -64,7 +79,7 @@ public async Task SetUp()
TargetLanguage = "en",
Type = "Echo",
Owner = "client1",
- Corpora = new List()
+ Corpora = []
};
var e1 = new Engine
{
@@ -74,7 +89,7 @@ public async Task SetUp()
TargetLanguage = "en",
Type = "Echo",
Owner = "client1",
- Corpora = new List()
+ Corpora = []
};
var e2 = new Engine
{
@@ -84,7 +99,7 @@ public async Task SetUp()
TargetLanguage = "en",
Type = "Echo",
Owner = "client2",
- Corpora = new List()
+ Corpora = []
};
var be0 = new Engine
{
@@ -94,7 +109,7 @@ public async Task SetUp()
TargetLanguage = "es",
Type = "SMTTransfer",
Owner = "client1",
- Corpora = new List()
+ Corpora = []
};
var ce0 = new Engine
{
@@ -104,7 +119,7 @@ public async Task SetUp()
TargetLanguage = "es",
Type = "Nmt",
Owner = "client1",
- Corpora = new List()
+ Corpora = []
};
await _env.Engines.InsertAllAsync(new[] { e0, e1, e2, be0, ce0 });
@@ -125,7 +140,23 @@ public async Task SetUp()
Filename = FILE2_FILENAME,
Format = Shared.Contracts.FileFormat.Text
};
- await _env.DataFiles.InsertAllAsync(new[] { srcFile, trgFile });
+ var srcParatextFile = new DataFiles.Models.DataFile
+ {
+ Id = FILE3_ID,
+ Owner = "client1",
+ Name = "src.zip",
+ Filename = FILE3_FILENAME,
+ Format = Shared.Contracts.FileFormat.Paratext
+ };
+ var trgParatextFile = new DataFiles.Models.DataFile
+ {
+ Id = FILE4_ID,
+ Owner = "client1",
+ Name = "trg.zip",
+ Filename = FILE4_FILENAME,
+ Format = Shared.Contracts.FileFormat.Paratext
+ };
+ await _env.DataFiles.InsertAllAsync([srcFile, trgFile, srcParatextFile, trgParatextFile]);
}
[Test]
@@ -133,7 +164,7 @@ public async Task SetUp()
[TestCase(new[] { Scopes.ReadFiles }, 403)] //Arbitrary unrelated privilege
public async Task GetAllAsync(IEnumerable scope, int expectedStatusCode)
{
- ITranslationEnginesClient client = _env!.CreateClient(scope);
+ TranslationEnginesClient client = _env.CreateTranslationEnginesClient(scope);
switch (expectedStatusCode)
{
case 200:
@@ -146,7 +177,7 @@ public async Task GetAllAsync(IEnumerable scope, int expectedStatusCode)
{
await client.GetAllAsync();
});
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
break;
default:
Assert.Fail("Unanticipated expectedStatusCode. Check test case for typo.");
@@ -161,7 +192,7 @@ public async Task GetAllAsync(IEnumerable scope, int expectedStatusCode)
[TestCase(new[] { Scopes.ReadTranslationEngines }, 404, DOES_NOT_EXIST_ENGINE_ID)]
public async Task GetByIdAsync(IEnumerable scope, int expectedStatusCode, string engineId)
{
- ITranslationEnginesClient client = _env!.CreateClient(scope);
+ TranslationEnginesClient client = _env.CreateTranslationEnginesClient(scope);
switch (expectedStatusCode)
{
case 200:
@@ -174,7 +205,7 @@ public async Task GetByIdAsync(IEnumerable scope, int expectedStatusCode
{
await client.GetAsync(engineId);
});
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
break;
default:
Assert.Fail("Unanticipated expectedStatusCode. Check test case for typo.");
@@ -188,8 +219,7 @@ public async Task GetByIdAsync(IEnumerable scope, int expectedStatusCode
[TestCase(new[] { Scopes.ReadFiles }, 403, "Echo")] //Arbitrary unrelated privilege
public async Task CreateEngineAsync(IEnumerable scope, int expectedStatusCode, string engineType)
{
- ITranslationEnginesClient client = _env!.CreateClient(scope);
- ServalApiException? ex;
+ TranslationEnginesClient client = _env.CreateTranslationEnginesClient(scope);
switch (expectedStatusCode)
{
case 201:
@@ -208,7 +238,8 @@ public async Task CreateEngineAsync(IEnumerable scope, int expectedStatu
Assert.That(engine.Name, Is.EqualTo("test"));
break;
case 400:
- ex = Assert.ThrowsAsync(async () =>
+ {
+ var ex = Assert.ThrowsAsync(async () =>
{
await client.CreateAsync(
new TranslationEngineConfig
@@ -220,10 +251,12 @@ await client.CreateAsync(
}
);
});
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
break;
+ }
case 403:
- ex = Assert.ThrowsAsync(async () =>
+ {
+ var ex = Assert.ThrowsAsync(async () =>
{
await client.CreateAsync(
new TranslationEngineConfig
@@ -235,8 +268,9 @@ await client.CreateAsync(
}
);
});
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
break;
+ }
default:
Assert.Fail("Unanticipated expectedStatusCode. Check test case for typo.");
break;
@@ -249,7 +283,7 @@ await client.CreateAsync(
[TestCase(new[] { Scopes.DeleteTranslationEngines }, 404, DOES_NOT_EXIST_ENGINE_ID)]
public async Task DeleteEngineByIdAsync(IEnumerable scope, int expectedStatusCode, string engineId)
{
- ITranslationEnginesClient client = _env!.CreateClient(scope);
+ TranslationEnginesClient client = _env.CreateTranslationEnginesClient(scope);
switch (expectedStatusCode)
{
case 200:
@@ -264,7 +298,7 @@ public async Task DeleteEngineByIdAsync(IEnumerable scope, int expectedS
{
await client.DeleteAsync(engineId);
});
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
break;
default:
Assert.Fail("Unanticipated expectedStatusCode. Check test case for typo.");
@@ -283,8 +317,7 @@ public async Task TranslateSegmentWithEngineByIdAsync(
string engineId
)
{
- ITranslationEnginesClient client = _env!.CreateClient(scope);
- ServalApiException ex;
+ TranslationEnginesClient client = _env.CreateTranslationEnginesClient(scope);
switch (expectedStatusCode)
{
case 200:
@@ -300,22 +333,26 @@ await _env.Builds.InsertAsync(
);
break;
case 409:
+ {
_env.EchoClient.TranslateAsync(Arg.Any(), null, null, Arg.Any())
.Returns(CreateAsyncUnaryCall(StatusCode.Aborted));
- ex = Assert.ThrowsAsync(async () =>
+ var ex = Assert.ThrowsAsync(async () =>
{
await client.TranslateAsync(engineId, "This is a test .");
});
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
break;
+ }
case 403:
case 404:
- ex = Assert.ThrowsAsync(async () =>
+ {
+ var ex = Assert.ThrowsAsync(async () =>
{
await client.TranslateAsync(engineId, "This is a test .");
});
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
break;
+ }
default:
Assert.Fail("Unanticipated expectedStatusCode. Check test case for typo.");
break;
@@ -333,8 +370,7 @@ public async Task TranslateNSegmentWithEngineByIdAsync(
string engineId
)
{
- ITranslationEnginesClient client = _env!.CreateClient(scope);
- ServalApiException ex;
+ TranslationEnginesClient client = _env.CreateTranslationEnginesClient(scope);
switch (expectedStatusCode)
{
case 200:
@@ -355,22 +391,26 @@ await _env.Builds.InsertAsync(
);
break;
case 409:
+ {
_env.EchoClient.TranslateAsync(Arg.Any(), null, null, Arg.Any())
.Returns(CreateAsyncUnaryCall(StatusCode.Aborted));
- ex = Assert.ThrowsAsync(async () =>
+ var ex = Assert.ThrowsAsync(async () =>
{
await client.TranslateNAsync(engineId, 1, "This is a test .");
});
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
break;
+ }
case 403:
case 404:
- ex = Assert.ThrowsAsync(async () =>
+ {
+ var ex = Assert.ThrowsAsync(async () =>
{
await client.TranslateNAsync(engineId, 1, "This is a test .");
});
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
break;
+ }
default:
Assert.Fail("Unanticipated expectedStatusCode. Check test case for typo.");
break;
@@ -388,8 +428,7 @@ public async Task GetWordGraphForSegmentByIdAsync(
string engineId
)
{
- ITranslationEnginesClient client = _env!.CreateClient(scope);
- ServalApiException ex;
+ TranslationEnginesClient client = _env.CreateTranslationEnginesClient(scope);
switch (expectedStatusCode)
{
case 200:
@@ -405,6 +444,7 @@ await _env.Builds.InsertAsync(
});
break;
case 409:
+ {
_env.EchoClient.GetWordGraphAsync(
Arg.Any(),
null,
@@ -412,20 +452,23 @@ await _env.Builds.InsertAsync(
Arg.Any()
)
.Returns(CreateAsyncUnaryCall(StatusCode.Aborted));
- ex = Assert.ThrowsAsync(async () =>
+ var ex = Assert.ThrowsAsync(async () =>
{
await client.GetWordGraphAsync(engineId, "This is a test .");
});
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
break;
+ }
case 403:
case 404:
- ex = Assert.ThrowsAsync(async () =>
+ {
+ var ex = Assert.ThrowsAsync(async () =>
{
await client.GetWordGraphAsync(engineId, "This is a test .");
});
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
break;
+ }
default:
Assert.Fail("Unanticipated expectedStatusCode. Check test case for typo.");
break;
@@ -443,14 +486,13 @@ public async Task TrainEngineByIdOnSegmentPairAsync(
string engineId
)
{
- ITranslationEnginesClient client = _env!.CreateClient(scope);
+ TranslationEnginesClient client = _env.CreateTranslationEnginesClient(scope);
var sp = new SegmentPair
{
SourceSegment = "This is a test .",
TargetSegment = "This is a test .",
SentenceStart = true
};
- ServalApiException ex;
switch (expectedStatusCode)
{
case 200:
@@ -461,6 +503,7 @@ await _env.Builds.InsertAsync(
await client.TrainSegmentAsync(engineId, sp);
break;
case 409:
+ {
_env.EchoClient.TrainSegmentPairAsync(
Arg.Any(),
null,
@@ -468,20 +511,23 @@ await _env.Builds.InsertAsync(
Arg.Any()
)
.Returns(CreateAsyncUnaryCall(StatusCode.Aborted));
- ex = Assert.ThrowsAsync(async () =>
+ var ex = Assert.ThrowsAsync(async () =>
{
await client.TrainSegmentAsync(engineId, sp);
});
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
break;
+ }
case 403:
case 404:
- ex = Assert.ThrowsAsync(async () =>
+ {
+ var ex = Assert.ThrowsAsync(async () =>
{
await client.TrainSegmentAsync(engineId, sp);
});
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
break;
+ }
default:
Assert.Fail("Unanticipated expectedStatusCode. Check test case for typo.");
break;
@@ -494,10 +540,11 @@ await _env.Builds.InsertAsync(
[TestCase(new[] { Scopes.ReadFiles }, 403, ECHO_ENGINE1_ID)] //Arbitrary unrelated privilege
public async Task AddCorpusToEngineByIdAsync(IEnumerable scope, int expectedStatusCode, string engineId)
{
- ITranslationEnginesClient client = _env!.CreateClient(scope);
+ TranslationEnginesClient client = _env.CreateTranslationEnginesClient(scope);
switch (expectedStatusCode)
{
case 201:
+ {
TranslationCorpus result = await client.AddCorpusAsync(engineId, TestCorpusConfig);
Assert.Multiple(() =>
{
@@ -509,17 +556,18 @@ public async Task AddCorpusToEngineByIdAsync(IEnumerable scope, int expe
Assert.That(engine, Is.Not.Null);
Assert.Multiple(() =>
{
- Assert.That(engine!.Corpora[0].SourceFiles[0].Filename, Is.EqualTo(FILE1_FILENAME));
+ Assert.That(engine.Corpora[0].SourceFiles[0].Filename, Is.EqualTo(FILE1_FILENAME));
Assert.That(engine.Corpora[0].TargetFiles[0].Filename, Is.EqualTo(FILE2_FILENAME));
});
break;
+ }
case 403:
case 404:
var ex = Assert.ThrowsAsync(async () =>
{
- result = await client.AddCorpusAsync(engineId, TestCorpusConfig);
+ await client.AddCorpusAsync(engineId, TestCorpusConfig);
});
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
break;
default:
Assert.Fail("Unanticipated expectedStatusCode. Check test case for typo.");
@@ -550,10 +598,11 @@ public async Task UpdateCorpusByIdForEngineByIdAsync(
string engineId
)
{
- TranslationEnginesClient client = _env!.CreateClient(scope);
+ TranslationEnginesClient client = _env.CreateTranslationEnginesClient(scope);
switch (expectedStatusCode)
{
case 200:
+ {
TranslationCorpus result = await client.AddCorpusAsync(engineId, TestCorpusConfig);
var src = new[]
{
@@ -569,10 +618,11 @@ string engineId
Assert.That(engine, Is.Not.Null);
Assert.Multiple(() =>
{
- Assert.That(engine!.Corpora[0].SourceFiles[0].Filename, Is.EqualTo(FILE2_FILENAME));
+ Assert.That(engine.Corpora[0].SourceFiles[0].Filename, Is.EqualTo(FILE2_FILENAME));
Assert.That(engine.Corpora[0].TargetFiles[0].Filename, Is.EqualTo(FILE1_FILENAME));
});
break;
+ }
case 400:
case 403:
case 404:
@@ -589,7 +639,7 @@ string engineId
var updateConfig = new TranslationCorpusUpdateConfig { SourceFiles = src, TargetFiles = trg };
await client.UpdateCorpusAsync(engineId, DOES_NOT_EXIST_CORPUS_ID, updateConfig);
});
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
break;
default:
Assert.Fail("Unanticipated expectedStatusCode. Check test case for typo.");
@@ -615,8 +665,7 @@ public async Task GetAllCorporaForEngineByIdAsync(
string engineId
)
{
- ITranslationEnginesClient client = _env!.CreateClient(scope);
- ServalApiException? ex;
+ TranslationEnginesClient client = _env.CreateTranslationEnginesClient(scope);
switch (expectedStatusCode)
{
case 200:
@@ -631,11 +680,11 @@ string engineId
break;
case 403:
case 404:
- ex = Assert.ThrowsAsync(async () =>
+ var ex = Assert.ThrowsAsync(async () =>
{
TranslationCorpus result = (await client.GetAllCorporaAsync(engineId)).First();
});
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
break;
default:
@@ -657,8 +706,7 @@ public async Task GetCorpusByIdForEngineByIdAsync(
bool addCorpus = false
)
{
- ITranslationEnginesClient client = _env!.CreateClient(scope);
- ServalApiException? ex;
+ TranslationEnginesClient client = _env.CreateTranslationEnginesClient(scope);
TranslationCorpus? result = null;
if (addCorpus)
{
@@ -667,9 +715,9 @@ public async Task GetCorpusByIdForEngineByIdAsync(
switch (expectedStatusCode)
{
case 200:
- if (result is null)
- Assert.Fail();
- TranslationCorpus resultAfterAdd = await client.GetCorpusAsync(engineId, result!.Id);
+ {
+ Assert.That(result, Is.Not.Null);
+ TranslationCorpus resultAfterAdd = await client.GetCorpusAsync(engineId, result.Id);
Assert.Multiple(() =>
{
Assert.That(resultAfterAdd.Name, Is.EqualTo(result.Name));
@@ -677,13 +725,14 @@ public async Task GetCorpusByIdForEngineByIdAsync(
Assert.That(resultAfterAdd.TargetLanguage, Is.EqualTo(result.TargetLanguage));
});
break;
+ }
case 403:
case 404:
- ex = Assert.ThrowsAsync(async () =>
+ var ex = Assert.ThrowsAsync(async () =>
{
TranslationCorpus result_afterAdd = await client.GetCorpusAsync(engineId, DOES_NOT_EXIST_CORPUS_ID);
});
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
break;
default:
@@ -703,8 +752,7 @@ public async Task DeleteCorpusByIdForEngineByIdAsync(
string engineId
)
{
- ITranslationEnginesClient client = _env!.CreateClient(scope);
- ServalApiException? ex;
+ TranslationEnginesClient client = _env.CreateTranslationEnginesClient(scope);
switch (expectedStatusCode)
{
case 200:
@@ -715,11 +763,11 @@ string engineId
break;
case 403:
case 404:
- ex = Assert.ThrowsAsync(async () =>
+ var ex = Assert.ThrowsAsync(async () =>
{
await client.DeleteCorpusAsync(engineId, DOES_NOT_EXIST_CORPUS_ID);
});
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
break;
default:
@@ -731,7 +779,7 @@ string engineId
[Test]
public async Task GetAllPretranslationsAsync_Exists()
{
- ITranslationEnginesClient client = _env!.CreateClient();
+ TranslationEnginesClient client = _env.CreateTranslationEnginesClient();
TranslationCorpus addedCorpus = await client.AddCorpusAsync(ECHO_ENGINE1_ID, TestCorpusConfig);
await _env.Engines.UpdateAsync(ECHO_ENGINE1_ID, u => u.Set(e => e.ModelRevision, 1));
@@ -740,7 +788,7 @@ public async Task GetAllPretranslationsAsync_Exists()
CorpusRef = addedCorpus.Id,
TextId = "all",
EngineRef = ECHO_ENGINE1_ID,
- Refs = new List { "ref1", "ref2" },
+ Refs = ["ref1", "ref2"],
Translation = "translation",
ModelRevision = 1
};
@@ -756,41 +804,41 @@ public async Task GetAllPretranslationsAsync_Exists()
[Test]
public void GetAllPretranslationsAsync_EngineDoesNotExist()
{
- ITranslationEnginesClient client = _env!.CreateClient();
+ TranslationEnginesClient client = _env.CreateTranslationEnginesClient();
var ex = Assert.ThrowsAsync(
() => client.GetAllPretranslationsAsync(DOES_NOT_EXIST_ENGINE_ID, "cccccccccccccccccccccccc")
);
- Assert.That(ex!.StatusCode, Is.EqualTo(404));
+ Assert.That(ex?.StatusCode, Is.EqualTo(404));
}
[Test]
public void GetAllPretranslationsAsync_CorpusDoesNotExist()
{
- ITranslationEnginesClient client = _env!.CreateClient();
+ TranslationEnginesClient client = _env.CreateTranslationEnginesClient();
var ex = Assert.ThrowsAsync(
() => client.GetAllPretranslationsAsync(ECHO_ENGINE1_ID, "cccccccccccccccccccccccc")
);
- Assert.That(ex!.StatusCode, Is.EqualTo(404));
+ Assert.That(ex?.StatusCode, Is.EqualTo(404));
}
[Test]
public async Task GetAllPretranslationsAsync_EngineNotBuilt()
{
- ITranslationEnginesClient client = _env!.CreateClient();
+ TranslationEnginesClient client = _env.CreateTranslationEnginesClient();
TranslationCorpus addedCorpus = await client.AddCorpusAsync(ECHO_ENGINE1_ID, TestCorpusConfig);
var ex = Assert.ThrowsAsync(
() => client.GetAllPretranslationsAsync(ECHO_ENGINE1_ID, addedCorpus.Id)
);
- Assert.That(ex!.StatusCode, Is.EqualTo(409));
+ Assert.That(ex?.StatusCode, Is.EqualTo(409));
}
[Test]
public async Task GetAllPretranslationsAsync_TextIdExists()
{
- ITranslationEnginesClient client = _env!.CreateClient();
+ TranslationEnginesClient client = _env.CreateTranslationEnginesClient();
TranslationCorpus addedCorpus = await client.AddCorpusAsync(ECHO_ENGINE1_ID, TestCorpusConfig);
await _env.Engines.UpdateAsync(ECHO_ENGINE1_ID, u => u.Set(e => e.ModelRevision, 1));
@@ -799,7 +847,7 @@ public async Task GetAllPretranslationsAsync_TextIdExists()
CorpusRef = addedCorpus.Id,
TextId = "all",
EngineRef = ECHO_ENGINE1_ID,
- Refs = new List { "ref1", "ref2" },
+ Refs = ["ref1", "ref2"],
Translation = "translation",
ModelRevision = 1
};
@@ -816,7 +864,7 @@ public async Task GetAllPretranslationsAsync_TextIdExists()
[Test]
public async Task GetAllPretranslationsAsync_TextIdDoesNotExist()
{
- ITranslationEnginesClient client = _env!.CreateClient();
+ TranslationEnginesClient client = _env.CreateTranslationEnginesClient();
TranslationCorpus addedCorpus = await client.AddCorpusAsync(ECHO_ENGINE1_ID, TestCorpusConfig);
await _env.Engines.UpdateAsync(ECHO_ENGINE1_ID, u => u.Set(e => e.ModelRevision, 1));
@@ -825,7 +873,7 @@ public async Task GetAllPretranslationsAsync_TextIdDoesNotExist()
CorpusRef = addedCorpus.Id,
TextId = "all",
EngineRef = ECHO_ENGINE1_ID,
- Refs = new List { "ref1", "ref2" },
+ Refs = ["ref1", "ref2"],
Translation = "translation",
ModelRevision = 1
};
@@ -850,7 +898,7 @@ public async Task GetAllBuildsForEngineByIdAsync(
bool addBuild = true
)
{
- ITranslationEnginesClient client = _env!.CreateClient(scope);
+ TranslationEnginesClient client = _env.CreateTranslationEnginesClient(scope);
Build? build = null;
if (addBuild)
{
@@ -865,8 +913,8 @@ public async Task GetAllBuildsForEngineByIdAsync(
Assert.Multiple(() =>
{
Assert.That(results.First().Revision, Is.EqualTo(1));
- Assert.That(results.First().Id, Is.EqualTo(build!.Id));
- Assert.That(results.First().State, Is.EqualTo(Client.JobState.Pending));
+ Assert.That(results.First().Id, Is.EqualTo(build?.Id));
+ Assert.That(results.First().State, Is.EqualTo(JobState.Pending));
});
break;
case 403:
@@ -895,42 +943,48 @@ public async Task GetBuildByIdForEngineByIdAsync(
bool addBuild = true
)
{
- ITranslationEnginesClient client = _env!.CreateClient(scope);
+ TranslationEnginesClient client = _env.CreateTranslationEnginesClient(scope);
Build? build = null;
if (addBuild)
{
build = new Build { EngineRef = engineId };
await _env.Builds.InsertAsync(build);
}
- ServalApiException ex;
+
switch (expectedStatusCode)
{
case 200:
+ {
Assert.That(build, Is.Not.Null);
- TranslationBuild result = await client.GetBuildAsync(engineId, build!.Id);
+ TranslationBuild result = await client.GetBuildAsync(engineId, build.Id);
Assert.Multiple(() =>
{
Assert.That(result.Revision, Is.EqualTo(1));
Assert.That(result.Id, Is.EqualTo(build.Id));
- Assert.That(result.State, Is.EqualTo(Client.JobState.Pending));
+ Assert.That(result.State, Is.EqualTo(JobState.Pending));
});
break;
+ }
case 403:
case 404:
- ex = Assert.ThrowsAsync(async () =>
+ {
+ var ex = Assert.ThrowsAsync(async () =>
{
await client.GetBuildAsync(engineId, "bbbbbbbbbbbbbbbbbbbbbbbb");
});
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
break;
+ }
case 408:
+ {
Assert.That(build, Is.Not.Null);
- ex = Assert.ThrowsAsync(async () =>
+ var ex = Assert.ThrowsAsync(async () =>
{
await client.GetBuildAsync(engineId, build!.Id, 3);
});
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
break;
+ }
default:
Assert.Fail("Unanticipated expectedStatusCode. Check test case for typo.");
break;
@@ -956,7 +1010,7 @@ public async Task GetBuildByIdForEngineByIdAsync(
[TestCase(new[] { Scopes.ReadFiles }, 403, ECHO_ENGINE1_ID)] //Arbitrary unrelated privilege
public async Task StartBuildForEngineByIdAsync(IEnumerable scope, int expectedStatusCode, string engineId)
{
- ITranslationEnginesClient client = _env!.CreateClient(scope);
+ TranslationEnginesClient client = _env.CreateTranslationEnginesClient(scope);
PretranslateCorpusConfig ptcc;
TrainingCorpusConfig tcc;
TranslationBuildConfig tbc;
@@ -1006,7 +1060,7 @@ public async Task StartBuildForEngineByIdAsync(IEnumerable scope, int ex
{
await client.StartBuildAsync(engineId, tbc);
});
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
break;
default:
Assert.Fail("Unanticipated expectedStatusCode. Check test case for typo.");
@@ -1027,7 +1081,7 @@ public async Task GetCurrentBuildForEngineByIdAsync(
bool addBuild = true
)
{
- ITranslationEnginesClient client = _env!.CreateClient(scope);
+ TranslationEnginesClient client = _env.CreateTranslationEnginesClient(scope);
Build? build = null;
if (addBuild)
{
@@ -1035,31 +1089,35 @@ public async Task GetCurrentBuildForEngineByIdAsync(
await _env.Builds.InsertAsync(build);
}
- ServalApiException ex;
switch (expectedStatusCode)
{
case 200:
+ {
Assert.That(build, Is.Not.Null);
TranslationBuild result = await client.GetCurrentBuildAsync(engineId);
- Assert.That(result.Id, Is.EqualTo(build!.Id));
+ Assert.That(result.Id, Is.EqualTo(build.Id));
break;
+ }
case 204:
case 403:
case 404:
- ex = Assert.ThrowsAsync(async () =>
+ {
+ var ex = Assert.ThrowsAsync(async () =>
{
await client.GetCurrentBuildAsync(engineId);
});
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
break;
+ }
case 408:
- ex = Assert.ThrowsAsync(async () =>
+ {
+ var ex = Assert.ThrowsAsync(async () =>
{
await client.GetCurrentBuildAsync(engineId, minRevision: 3);
});
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
-
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
break;
+ }
default:
Assert.Fail("Unanticipated expectedStatusCode. Check test case for typo.");
break;
@@ -1069,7 +1127,7 @@ public async Task GetCurrentBuildForEngineByIdAsync(
[Test]
[TestCase(new[] { Scopes.UpdateTranslationEngines }, 200, ECHO_ENGINE1_ID)]
[TestCase(new[] { Scopes.UpdateTranslationEngines }, 404, DOES_NOT_EXIST_ENGINE_ID, false)]
- [TestCase(new[] { Scopes.UpdateTranslationEngines }, 404, ECHO_ENGINE1_ID, false)]
+ [TestCase(new[] { Scopes.UpdateTranslationEngines }, 204, ECHO_ENGINE1_ID, false)]
[TestCase(new[] { Scopes.ReadFiles }, 403, ECHO_ENGINE1_ID, false)] //Arbitrary unrelated privilege
public async Task CancelCurrentBuildForEngineByIdAsync(
IEnumerable scope,
@@ -1078,17 +1136,19 @@ public async Task CancelCurrentBuildForEngineByIdAsync(
bool addBuild = true
)
{
- ITranslationEnginesClient client = _env!.CreateClient(scope);
- Build? build = null;
- if (addBuild)
+ TranslationEnginesClient client = _env.CreateTranslationEnginesClient(scope);
+ if (!addBuild)
{
- build = new Build { EngineRef = engineId };
+ var build = new Build { EngineRef = engineId };
await _env.Builds.InsertAsync(build);
+ _env.NmtClient.CancelBuildAsync(Arg.Any(), null, null, Arg.Any())
+ .Returns(CreateAsyncUnaryCall(StatusCode.Aborted));
}
switch (expectedStatusCode)
{
case 200:
+ case 204:
await client.CancelBuildAsync(engineId);
break;
case 403:
@@ -1097,7 +1157,7 @@ public async Task CancelCurrentBuildForEngineByIdAsync(
{
await client.CancelBuildAsync(engineId);
});
- Assert.That(ex!.StatusCode, Is.EqualTo(expectedStatusCode));
+ Assert.That(ex?.StatusCode, Is.EqualTo(expectedStatusCode));
break;
default:
Assert.Fail("Unanticipated expectedStatusCode. Check test case for typo.");
@@ -1108,7 +1168,7 @@ public async Task CancelCurrentBuildForEngineByIdAsync(
[Test]
public async Task TryToQueueMultipleBuildsPerSingleUser()
{
- ITranslationEnginesClient client = _env!.CreateClient();
+ TranslationEnginesClient client = _env.CreateTranslationEnginesClient();
var engineId = NMT_ENGINE1_ID;
var expectedStatusCode = 409;
TranslationCorpus addedCorpus = await client.AddCorpusAsync(engineId, TestCorpusConfigNonEcho);
@@ -1119,6 +1179,8 @@ public async Task TryToQueueMultipleBuildsPerSingleUser()
};
var tbc = new TranslationBuildConfig { Pretranslate = new List { ptcc } };
TranslationBuild build = await client.StartBuildAsync(engineId, tbc);
+ _env.NmtClient.StartBuildAsync(Arg.Any(), null, null, Arg.Any())
+ .Returns(CreateAsyncUnaryCall(StatusCode.Aborted));
var ex = Assert.ThrowsAsync(async () =>
{
build = await client.StartBuildAsync(engineId, tbc);
@@ -1128,15 +1190,50 @@ public async Task TryToQueueMultipleBuildsPerSingleUser()
}
[Test]
- public void AddCorpusWithSameSourceAndTargetLangs()
+ public async Task GetPretranslatedUsfmAsync_BookExists()
{
- ITranslationEnginesClient client = _env!.CreateClient();
- var ex = Assert.ThrowsAsync(async () =>
+ TranslationEnginesClient client = _env.CreateTranslationEnginesClient();
+ TranslationCorpus addedCorpus = await client.AddCorpusAsync(ECHO_ENGINE1_ID, TestCorpusConfigScripture);
+
+ await _env.Engines.UpdateAsync(ECHO_ENGINE1_ID, u => u.Set(e => e.ModelRevision, 1));
+ var pret = new Translation.Models.Pretranslation
{
- await client.AddCorpusAsync(NMT_ENGINE1_ID, TestCorpusConfig);
- });
- Assert.That(ex, Is.Not.Null);
- Assert.That(ex.StatusCode, Is.EqualTo(422));
+ CorpusRef = addedCorpus.Id,
+ TextId = "MAT",
+ EngineRef = ECHO_ENGINE1_ID,
+ Refs = ["MAT 1:1"],
+ Translation = "translation",
+ ModelRevision = 1
+ };
+ await _env.Pretranslations.InsertAsync(pret);
+
+ string usfm = await client.GetPretranslatedUsfmAsync(ECHO_ENGINE1_ID, addedCorpus.Id, "MAT");
+ Assert.That(
+ usfm.Replace("\r\n", "\n"),
+ Is.EqualTo(
+ @"\id MAT - TRG
+\h
+\c 1
+\p
+\v 1 translation
+\v 2
+".Replace("\r\n", "\n")
+ )
+ );
+ }
+
+ [Test]
+ public async Task GetPretranslatedUsfmAsync_BookDoesNotExist()
+ {
+ TranslationEnginesClient client = _env.CreateTranslationEnginesClient();
+ TranslationCorpus addedCorpus = await client.AddCorpusAsync(ECHO_ENGINE1_ID, TestCorpusConfigScripture);
+
+ await _env.Engines.UpdateAsync(ECHO_ENGINE1_ID, u => u.Set(e => e.ModelRevision, 1));
+
+ var ex = Assert.ThrowsAsync(
+ () => client.GetPretranslatedUsfmAsync(ECHO_ENGINE1_ID, addedCorpus.Id, "MRK")
+ );
+ Assert.That(ex?.StatusCode, Is.EqualTo(204));
}
[Test]
@@ -1144,7 +1241,7 @@ public void AddCorpusWithSameSourceAndTargetLangs()
[TestCase("Echo")]
public async Task GetQueueAsync(string engineType)
{
- TranslationClient client = _env!.CreateTranslationClient();
+ TranslationEngineTypesClient client = _env.CreateTranslationEngineTypesClient();
Client.Queue queue = await client.GetQueueAsync(engineType);
Assert.That(queue.Size, Is.EqualTo(0));
}
@@ -1152,7 +1249,7 @@ public async Task GetQueueAsync(string engineType)
[Test]
public void GetQueueAsync_NotAuthorized()
{
- TranslationClient client = _env!.CreateTranslationClient([Scopes.ReadFiles]);
+ TranslationEngineTypesClient client = _env.CreateTranslationEngineTypesClient([Scopes.ReadFiles]);
ServalApiException? ex = Assert.ThrowsAsync(async () =>
{
Client.Queue queue = await client.GetQueueAsync("Echo");
@@ -1164,7 +1261,7 @@ public void GetQueueAsync_NotAuthorized()
[Test]
public async Task GetLanguageInfoAsync()
{
- TranslationClient client = _env!.CreateTranslationClient();
+ TranslationEngineTypesClient client = _env.CreateTranslationEngineTypesClient();
Client.LanguageInfo languageInfo = await client.GetLanguageInfoAsync("Nmt", "Alphabet");
Assert.Multiple(() =>
{
@@ -1176,7 +1273,7 @@ public async Task GetLanguageInfoAsync()
[Test]
public void GetLanguageInfo_Error()
{
- TranslationClient client = _env!.CreateTranslationClient([Scopes.ReadFiles]);
+ TranslationEngineTypesClient client = _env.CreateTranslationEngineTypesClient([Scopes.ReadFiles]);
ServalApiException? ex = Assert.ThrowsAsync(async () =>
{
Client.LanguageInfo languageInfo = await client.GetLanguageInfoAsync("Nmt", "abc");
@@ -1188,7 +1285,7 @@ public void GetLanguageInfo_Error()
[TearDown]
public void TearDown()
{
- _env!.Dispose();
+ _env.Dispose();
}
private static AsyncUnaryCall CreateAsyncUnaryCall(StatusCode statusCode)
@@ -1217,7 +1314,7 @@ private static AsyncUnaryCall CreateAsyncUnaryCall(TRespon
private class TestEnvironment : DisposableBase
{
private readonly IServiceScope _scope;
- private readonly IMongoClient _mongoClient;
+ private readonly MongoClient _mongoClient;
public TestEnvironment()
{
@@ -1383,7 +1480,7 @@ public TestEnvironment()
.Returns(CreateAsyncUnaryCall(StatusCode.Unimplemented));
}
- ServalWebApplicationFactory Factory { get; }
+ public ServalWebApplicationFactory Factory { get; }
public IRepository Engines { get; }
public IRepository DataFiles { get; }
public IRepository