From 345c276e295b414432df5bda00433b8064199fd6 Mon Sep 17 00:00:00 2001 From: Anthony Timmers Date: Fri, 21 Nov 2025 15:09:16 +0100 Subject: [PATCH 1/7] Make support up to net10.0 and drop netstandard1.4 support Modernizes the codebase by upgrading to .NET 10, enabling use of newer language features and APIs. Removes legacy netstandard1.4 support and related conditional logic to simplify maintenance. Improves compatibility with future .NET releases. --- .github/workflows/publish_nuget_package.yml | 2 +- .../SignhostAPIClient.Tests.csproj | 2 +- .../Rest/JsonConverters/JsonBaseConverter.cs | 8 ++--- .../JsonVerificationConverter.cs | 33 +++++++++++++++-- .../Rest/JsonConverters/LevelEnumConverter.cs | 20 ++++++++--- .../Rest/SignHostApiClient.cs | 2 ++ .../StreamContentDigestOptionsExtensions.cs | 36 +++++++------------ .../SignhostAPIClient.csproj | 11 ++---- .../System/SerializableAttribute.cs | 9 ----- 9 files changed, 70 insertions(+), 53 deletions(-) delete mode 100644 src/SignhostAPIClient/System/SerializableAttribute.cs diff --git a/.github/workflows/publish_nuget_package.yml b/.github/workflows/publish_nuget_package.yml index dc459d1c..8ce91f8a 100644 --- a/.github/workflows/publish_nuget_package.yml +++ b/.github/workflows/publish_nuget_package.yml @@ -15,7 +15,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v5 with: - dotnet-version: '8.x' + dotnet-version: '10.x' - name: Check for Tag on Current Commit run: | diff --git a/src/SignhostAPIClient.Tests/SignhostAPIClient.Tests.csproj b/src/SignhostAPIClient.Tests/SignhostAPIClient.Tests.csproj index cc06f7b3..fbe586e5 100644 --- a/src/SignhostAPIClient.Tests/SignhostAPIClient.Tests.csproj +++ b/src/SignhostAPIClient.Tests/SignhostAPIClient.Tests.csproj @@ -1,6 +1,6 @@ - net8.0 + net10.0 ../signhost.ruleset test diff --git a/src/SignhostAPIClient/Rest/JsonConverters/JsonBaseConverter.cs b/src/SignhostAPIClient/Rest/JsonConverters/JsonBaseConverter.cs index cc3f3e53..ff5642bd 100644 --- a/src/SignhostAPIClient/Rest/JsonConverters/JsonBaseConverter.cs +++ b/src/SignhostAPIClient/Rest/JsonConverters/JsonBaseConverter.cs @@ -8,12 +8,12 @@ namespace Signhost.APIClient.Rest.JsonConverters public abstract class JsonBaseConverter : JsonConverter { -#if TYPEINFO public override bool CanConvert(Type objectType) - => typeof(T).GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo()); + => typeof(T) +#if TYPEINFO + .GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo()); #else - public override bool CanConvert(Type objectType) - => typeof(T).IsAssignableFrom(objectType); + .IsAssignableFrom(objectType); #endif public override object ReadJson( diff --git a/src/SignhostAPIClient/Rest/JsonConverters/JsonVerificationConverter.cs b/src/SignhostAPIClient/Rest/JsonConverters/JsonVerificationConverter.cs index 3019809e..4e1f9fa6 100644 --- a/src/SignhostAPIClient/Rest/JsonConverters/JsonVerificationConverter.cs +++ b/src/SignhostAPIClient/Rest/JsonConverters/JsonVerificationConverter.cs @@ -11,7 +11,11 @@ namespace Signhost.APIClient.Rest.JsonConverters internal class JsonVerificationConverter : JsonBaseConverter { +#if TYPEINFO private static readonly IDictionary VerificationTypes = +#else + private static readonly IDictionary VerificationTypes = +#endif CreateVerificationTypeMap(); public override bool CanWrite @@ -30,7 +34,12 @@ internal static void RegisterVerification() { var verification = (IVerification)Activator.CreateInstance(typeof(T)); - VerificationTypes[verification.Type] = typeof(T).GetTypeInfo(); + VerificationTypes[verification.Type] = +#if TYPEINFO + typeof(T).GetTypeInfo(); +#else + typeof(T); +#endif } protected override IVerification Create( @@ -40,13 +49,18 @@ protected override IVerification Create( var typeName = jsonObject["Type"]?.ToString(); if (VerificationTypes.TryGetValue(typeName, out var verificationType)) { +#if TYPEINFO return (IVerification)Activator.CreateInstance(verificationType.AsType()); +#else + return (IVerification)Activator.CreateInstance(verificationType); +#endif } return new UnknownVerification(); } - private static IDictionary CreateVerificationTypeMap() +#if TYPEINFO + private static Dictionary CreateVerificationTypeMap() { return typeof(JsonVerificationConverter).GetTypeInfo().Assembly.ExportedTypes .Select(t => t.GetTypeInfo()) @@ -60,5 +74,20 @@ private static IDictionary CreateVerificationTypeMap() .Where(t => t.instance.Type != null) .ToDictionary(t => t.instance.Type, t => t.typeInfo); } +#else + private static Dictionary CreateVerificationTypeMap() + { + return typeof(JsonVerificationConverter).Assembly.ExportedTypes + .Where(t => typeof(IVerification).IsAssignableFrom(t)) + .Where(t => !t.IsInterface && !t.IsAbstract) +#pragma warning disable SA1008 // Opening parenthesis must be spaced correctly + .Select(t => ( + type: t, + instance: (IVerification)Activator.CreateInstance(t))) +#pragma warning restore SA1008 // Opening parenthesis must be spaced correctly + .Where(t => t.instance.Type is not null) + .ToDictionary(t => t.instance.Type, t => t.type); + } +#endif } } diff --git a/src/SignhostAPIClient/Rest/JsonConverters/LevelEnumConverter.cs b/src/SignhostAPIClient/Rest/JsonConverters/LevelEnumConverter.cs index c088635a..e0e5aeed 100644 --- a/src/SignhostAPIClient/Rest/JsonConverters/LevelEnumConverter.cs +++ b/src/SignhostAPIClient/Rest/JsonConverters/LevelEnumConverter.cs @@ -47,11 +47,23 @@ public override void WriteJson( => throw new NotImplementedException(); private static Type GetUnderlyingType(Type type) - => type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>) - ? Nullable.GetUnderlyingType(type) - : type; + => +#if TYPEINFO + type.GetTypeInfo().IsGenericType && +#else + type.IsGenericType && +#endif + type.GetGenericTypeDefinition() == typeof(Nullable<>) + ? Nullable.GetUnderlyingType(type) + : type; private static bool IsLevelEnum(Type type) - => type.GetTypeInfo().IsEnum && type == typeof(Level); + => +#if TYPEINFO + type.GetTypeInfo().IsEnum && +#else + type.IsEnum && +#endif + type == typeof(Level); } } diff --git a/src/SignhostAPIClient/Rest/SignHostApiClient.cs b/src/SignhostAPIClient/Rest/SignHostApiClient.cs index 093632b8..dd2e3a89 100644 --- a/src/SignhostAPIClient/Rest/SignHostApiClient.cs +++ b/src/SignhostAPIClient/Rest/SignHostApiClient.cs @@ -22,7 +22,9 @@ public class SignHostApiClient private const string ApiVersion = "v1"; private static readonly string Version = typeof(SignHostApiClient) +#if TYPEINFO .GetTypeInfo() +#endif .Assembly.GetCustomAttribute() .Version; diff --git a/src/SignhostAPIClient/Rest/StreamContentDigestOptionsExtensions.cs b/src/SignhostAPIClient/Rest/StreamContentDigestOptionsExtensions.cs index 2aad9008..3ae2389b 100644 --- a/src/SignhostAPIClient/Rest/StreamContentDigestOptionsExtensions.cs +++ b/src/SignhostAPIClient/Rest/StreamContentDigestOptionsExtensions.cs @@ -63,27 +63,17 @@ private static HashAlgorithm HashAlgorithmCreate( string algorithmName = options.DigestHashAlgorithm; HashAlgorithm algorithm = null; -#if NETSTANDARD1_4 || NETSTANDARD2_0 - switch (algorithmName) { - case "SHA1": - case "SHA-1": - algorithm = SHA1.Create(); - break; - case "SHA256": - case "SHA-256": - algorithm = SHA256.Create(); - break; - case "SHA384": - case "SHA-384": - algorithm = SHA384.Create(); - break; - case "SHA512": - case "SHA-512": - algorithm = SHA512.Create(); - break; - } -#else +#if NET462 algorithm = HashAlgorithm.Create(algorithmName); +#else + algorithm = algorithmName switch { + "SHA1" or "SHA-1" => SHA1.Create(), + "SHA256" or "SHA-256" => SHA256.Create(), + "SHA384" or "SHA-384" => SHA384.Create(), + "SHA512" or "SHA-512" => SHA512.Create(), + + _ => null, + }; #endif if (algorithm == null && options.DigestHashValue == null) { algorithm = DefaultHashAlgorithm(); @@ -98,10 +88,10 @@ private static HashAlgorithm HashAlgorithmCreate( } private static HashAlgorithm DefaultHashAlgorithm() => -#if NETSTANDARD1_4 || NETSTANDARD2_0 - SHA256.Create(); -#else +#if NET462 HashAlgorithm.Create(); +#else + SHA256.Create(); #endif } } diff --git a/src/SignhostAPIClient/SignhostAPIClient.csproj b/src/SignhostAPIClient/SignhostAPIClient.csproj index f8acfff0..8c6a83a0 100644 --- a/src/SignhostAPIClient/SignhostAPIClient.csproj +++ b/src/SignhostAPIClient/SignhostAPIClient.csproj @@ -1,11 +1,9 @@ - netstandard2.0;netstandard1.4;net462 + net10.0;net9.0;net8.0;netstandard2.0;net462 + 10 ../signhost.ruleset - SERIALIZABLE - TYPEINFO TYPEINFO - SERIALIZABLE Signhost.APIClient @@ -53,9 +51,4 @@ - - - - - diff --git a/src/SignhostAPIClient/System/SerializableAttribute.cs b/src/SignhostAPIClient/System/SerializableAttribute.cs deleted file mode 100644 index 568c0bad..00000000 --- a/src/SignhostAPIClient/System/SerializableAttribute.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace System -{ -#if !SERIALIZABLE - internal sealed class SerializableAttribute - : Attribute - { - } -#endif -} From f0528f1b9b3b2e93c4c0992fb3d7414d55e5f291 Mon Sep 17 00:00:00 2001 From: Anthony Timmers Date: Fri, 21 Nov 2025 18:53:41 +0100 Subject: [PATCH 2/7] Refactor Signhost API Client to use System.Text.Json - Replaced Newtonsoft.Json with System.Text.Json for JSON serialization and deserialization across the API client. - Updated interfaces and classes to reflect consistent naming conventions (e.g., ISignHostApiClient to ISignhostApiClient). - Removed obsolete JsonConverter classes that were specific to Newtonsoft.Json. - Introduced centralized JSON serializer options in SignhostJsonSerializerOptions for consistent serialization behavior. - Added new JSON test resources for various transaction scenarios to ensure compatibility with the updated serialization logic. --- README.md | 4 +- .../APIResponses.Designer.cs | 186 -------- src/SignhostAPIClient.Tests/APIResponses.resx | 443 ------------------ .../AddOrReplaceFileMetaToTransaction.json | 1 + .../JSON/AddTransaction.json | 80 ++++ .../JSON/DeleteTransaction.json | 80 ++++ .../JSON/GetTransaction.json | 80 ++++ .../JSON/JsonResources.cs | 37 ++ .../JSON/MinimalTransactionResponse.json | 4 + .../JSON/MockPostbackInvalid.json | 76 +++ .../JSON/MockPostbackValid.json | 112 +++++ .../JSON/TransactionSingleSignerJson.json | 46 ++ .../LevelEnumConverterTests.cs | 10 +- src/SignhostAPIClient.Tests/PostbackTests.cs | 12 +- .../RequestBodies.Designer.cs | 114 ----- .../RequestBodies.resx | 355 -------------- .../SignhostAPIClient.Tests.csproj | 21 +- .../SignhostApiClientTests.cs | 166 +++---- .../SignhostApiReceiverTests.cs | 9 +- src/SignhostAPIClient.Tests/app.config | 11 - .../Rest/DataObjects/ConsentVerification.cs | 4 - .../Rest/DataObjects/DigidVerification.cs | 2 - .../DataObjects/EidasLoginVerification.cs | 8 +- .../Rest/DataObjects/FileMeta.cs | 4 +- .../Rest/DataObjects/IPAddressVerification.cs | 15 - .../Rest/DataObjects/IVerification.cs | 18 +- .../Rest/DataObjects/IdealVerification.cs | 2 - .../Rest/DataObjects/IdinVerification.cs | 2 - .../ItsmeIdentificationVerification.cs | 5 - .../Rest/DataObjects/ItsmeSignVerification.cs | 4 - .../Rest/DataObjects/KennisnetVerification.cs | 11 - .../Rest/DataObjects/Level.cs | 4 - .../DataObjects/PhoneNumberVerification.cs | 2 - .../Rest/DataObjects/PostbackTransaction.cs | 18 +- .../Rest/DataObjects/Receiver.cs | 2 +- .../Rest/DataObjects/ScribbleVerification.cs | 2 - .../Rest/DataObjects/Signer.cs | 2 +- .../SigningCertificateVerification.cs | 2 - .../Rest/DataObjects/SurfnetVerification.cs | 5 +- .../Rest/DataObjects/Transaction.cs | 34 +- .../Rest/DataObjects/UnknownVerification.cs | 8 - ...pResponseMessageErrorHandlingExtensions.cs | 23 +- .../Rest/HttpContentJsonExtensions.cs | 4 +- .../Rest/ISignHostApiClient.cs | 2 +- .../Rest/ISignhostApiClientSettings.cs | 2 +- src/SignhostAPIClient/Rest/JsonContent.cs | 4 +- .../Rest/JsonConverters/JsonBaseConverter.cs | 33 -- .../JsonVerificationConverter.cs | 93 ---- .../Rest/JsonConverters/LevelEnumConverter.cs | 81 ++-- .../Rest/SignHostApiClient.cs | 38 +- .../Rest/SignHostApiClientSettings.cs | 8 +- .../Rest/SignhostApiReceiver.cs | 12 +- .../Rest/SignhostJsonSerializerOptions.cs | 23 + .../SignhostAPIClient.csproj | 2 +- 54 files changed, 757 insertions(+), 1569 deletions(-) delete mode 100644 src/SignhostAPIClient.Tests/APIResponses.Designer.cs delete mode 100644 src/SignhostAPIClient.Tests/APIResponses.resx create mode 100644 src/SignhostAPIClient.Tests/JSON/AddOrReplaceFileMetaToTransaction.json create mode 100644 src/SignhostAPIClient.Tests/JSON/AddTransaction.json create mode 100644 src/SignhostAPIClient.Tests/JSON/DeleteTransaction.json create mode 100644 src/SignhostAPIClient.Tests/JSON/GetTransaction.json create mode 100644 src/SignhostAPIClient.Tests/JSON/JsonResources.cs create mode 100644 src/SignhostAPIClient.Tests/JSON/MinimalTransactionResponse.json create mode 100644 src/SignhostAPIClient.Tests/JSON/MockPostbackInvalid.json create mode 100644 src/SignhostAPIClient.Tests/JSON/MockPostbackValid.json create mode 100644 src/SignhostAPIClient.Tests/JSON/TransactionSingleSignerJson.json delete mode 100644 src/SignhostAPIClient.Tests/RequestBodies.Designer.cs delete mode 100644 src/SignhostAPIClient.Tests/RequestBodies.resx delete mode 100644 src/SignhostAPIClient.Tests/app.config delete mode 100644 src/SignhostAPIClient/Rest/DataObjects/KennisnetVerification.cs delete mode 100644 src/SignhostAPIClient/Rest/DataObjects/UnknownVerification.cs delete mode 100644 src/SignhostAPIClient/Rest/JsonConverters/JsonBaseConverter.cs delete mode 100644 src/SignhostAPIClient/Rest/JsonConverters/JsonVerificationConverter.cs create mode 100644 src/SignhostAPIClient/Rest/SignhostJsonSerializerOptions.cs diff --git a/README.md b/README.md index 6da273b1..16fa8783 100644 --- a/README.md +++ b/README.md @@ -15,11 +15,11 @@ For full API documentation, please visit [evidos.github.io](https://evidos.githu ### Example code The following code is an example of how to create and start a sign transaction with two documents. ```c# -var settings = new SignHostApiClientSettings( +var settings = new SignhostApiClientSettings( "AppName appkey", "apikey or usertoken")); -var client = new SignHostApiClient(settings); +var client = new SignhostApiClient(settings); var transaction = await client.CreateTransactionAsync(new Transaction { Signers = new List { diff --git a/src/SignhostAPIClient.Tests/APIResponses.Designer.cs b/src/SignhostAPIClient.Tests/APIResponses.Designer.cs deleted file mode 100644 index 9a092696..00000000 --- a/src/SignhostAPIClient.Tests/APIResponses.Designer.cs +++ /dev/null @@ -1,186 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Signhost.APIClient.Rest.Tests { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class APIResponses { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal APIResponses() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Signhost.APIClient.Rest.Tests.APIResponses", typeof(APIResponses).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to { - /// "Id": "c487be92-0255-40c7-bd7d-20805a65e7d9", - /// "Status": 20, - /// "File": { - /// "Id": "d4bba0df-f9e5-44c8-89db-f2bb46632d7b", - /// "Name": "contract.pdf" - /// }, - /// "Seal": true, - /// "Signers": [ - /// { - /// "Id": "a2932c07-ca93-4011-96f5-a77d2cd1ec32", - /// "Expires": null, - /// "Email": "user@example.com", - /// "Mobile": "+31612345678", - /// "Iban": null, - /// "BSN": null, - /// "RequireScribbleName": false, - /// "RequireScribble": true, - /// "RequireEmailVerification": true, - /// "R [rest of string was truncated]";. - /// - internal static string AddTransaction { - get { - return ResourceManager.GetString("AddTransaction", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to { - /// "Id": "496bec4d-4ac7-428f-894a-b3e9bade725d", - /// "Status": 20, - /// "File": { - /// "Id": "3149bf06-d01e-4f0d-9aa1-77e100e19772", - /// "Name": "contract.pdf" - /// }, - /// "Seal": true, - /// "Signers": [ - /// { - /// "Id": "4813e178-68a4-4105-b007-5ce9a3630867", - /// "Expires": null, - /// "Email": "user@example.com", - /// "Mobile": "+31612345678", - /// "Iban": null, - /// "BSN": null, - /// "RequireScribbleName": false, - /// "RequireScribble": true, - /// "RequireEmailVerification": true, - /// "R [rest of string was truncated]";. - /// - internal static string DeleteTransaction { - get { - return ResourceManager.GetString("DeleteTransaction", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to { - /// "Id": "c487be92-0255-40c7-bd7d-20805a65e7d9", - /// "Status": 20, - /// "File": { - /// "Id": "d4bba0df-f9e5-44c8-89db-f2bb46632d7b", - /// "Name": "contract.pdf" - /// }, - /// "Seal": true, - /// "Signers": [ - /// { - /// "Id": "a2932c07-ca93-4011-96f5-a77d2cd1ec32", - /// "Expires": null, - /// "Email": "user@example.com", - /// "Mobile": "+31612345678", - /// "Iban": null, - /// "BSN": null, - /// "RequireScribbleName": false, - /// "RequireScribble": true, - /// "RequireEmailVerification": true, - /// "R [rest of string was truncated]";. - /// - internal static string GetTransaction { - get { - return ResourceManager.GetString("GetTransaction", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to { - /// "Id": "c487be92-0255-40c7-bd7d-20805a65e7d9", - /// "Status": 20, - /// "Seal": true, - /// "Signers": [ - /// { - /// "Id": "a2932c07-ca93-4011-96f5-a77d2cd1ec32", - /// "Expires": null, - /// "Email": "user@example.com", - /// "Mobile": "+31612345678", - /// "Iban": null, - /// "BSN": null, - /// "SendSignRequest": true, - /// "SendSignConfirmation": null, - /// "SignRequestMessage": "Hello, could you please sign this document? Best regards, John Doe", - /// "DaysToRemind": 15, - /// "Language": "en-US", - /// "Reference": "Client #123", - /// "ReturnUrl": "h [rest of string was truncated]";. - /// - internal static string GetTransactionCustomVerificationType { - get { - return ResourceManager.GetString("GetTransactionCustomVerificationType", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to { - /// "Id": "50262c3f-9744-45bf-a4c6-8a3whatever", - /// "Status": 5 - ///}. - /// - internal static string MinimalTransactionResponse { - get { - return ResourceManager.GetString("MinimalTransactionResponse", resourceCulture); - } - } - } -} diff --git a/src/SignhostAPIClient.Tests/APIResponses.resx b/src/SignhostAPIClient.Tests/APIResponses.resx deleted file mode 100644 index 197489d0..00000000 --- a/src/SignhostAPIClient.Tests/APIResponses.resx +++ /dev/null @@ -1,443 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - { - "Id": "c487be92-0255-40c7-bd7d-20805a65e7d9", - "Status": 20, - "File": { - "Id": "d4bba0df-f9e5-44c8-89db-f2bb46632d7b", - "Name": "contract.pdf" - }, - "Seal": true, - "Signers": [ - { - "Id": "a2932c07-ca93-4011-96f5-a77d2cd1ec32", - "Expires": null, - "Email": "user@example.com", - "Mobile": "+31612345678", - "Iban": null, - "BSN": null, - "RequireScribbleName": false, - "RequireScribble": true, - "RequireEmailVerification": true, - "RequireSmsVerification": true, - "RequireIdealVerification": false, - "RequireDigidVerification": false, - "RequireKennisnetVerification": false, - "RequireSurfnetVerification": false, - "SendSignRequest": true, - "SendSignConfirmation": null, - "SignRequestMessage": "Hello, could you please sign this document? Best regards, John Doe", - "DaysToRemind": 15, - "Language": "en-US", - "ScribbleName": "John Doe", - "ScribbleNameFixed": false, - "Reference": "Client #123", - "ReturnUrl": "http://signhost.com", - "Activities": [ - { - "Id": "0b47eb5c-e800-4fe3-9795-09d380dff1f9", - "Code": 103, - "Activity": "Opened", - "CreatedDateTime": "2016-03-17T21:08:55.1349315+01:00" - }, - { - "Id": "761f8678-116c-4e86-a47a-c8312681d285", - "Code": 203, - "Activity": "Signed", - "CreatedDateTime": "2016-03-17T21:13:55.1349315+01:00" - } - ], - "RejectReason": null, - "SignUrl": "http://ui.signhost.com/sign/93dc596f-ab81-4d31-87aa-50352c4c237e", - "SignedDateTime": null, - "RejectDateTime": null, - "CreatedDateTime": "2016-03-17T21:08:55.1349315+01:00", - "ModifiedDateTime": "2016-03-17T21:08:55.1349315+01:00", - "Context": null - } - ], - "Receivers": [ - { - "Id": "2fe3dddf-4b50-49d1-a3d2-45b7d175fb97", - "Name": "John Doe", - "Email": "user@example.com", - "Language": "en-US", - "Message": "Hello, please find enclosed the digital signed document. Best regards, John Doe", - "Reference": null, - "Activities": null, - "CreatedDateTime": "2016-03-17T21:08:55.1349315+01:00", - "ModifiedDateTime": "2016-03-17T21:08:55.1349315+01:00", - "Context": null - } - ], - "Reference": "Contract #123", - "PostbackUrl": "http://example.com/postback.php", - "SignRequestMode": 2, - "DaysToExpire": 30, - "SendEmailNotifications": true, - "CreatedDateTime": "2016-03-17T21:08:55.1349315+01:00", - "ModifiedDateTime": "2016-03-17T21:08:55.1349315+01:00", - "CanceledDateTime": null, - "Context": null -} - - - { - "Id": "496bec4d-4ac7-428f-894a-b3e9bade725d", - "Status": 20, - "File": { - "Id": "3149bf06-d01e-4f0d-9aa1-77e100e19772", - "Name": "contract.pdf" - }, - "Seal": true, - "Signers": [ - { - "Id": "4813e178-68a4-4105-b007-5ce9a3630867", - "Expires": null, - "Email": "user@example.com", - "Mobile": "+31612345678", - "Iban": null, - "BSN": null, - "RequireScribbleName": false, - "RequireScribble": true, - "RequireEmailVerification": true, - "RequireSmsVerification": true, - "RequireIdealVerification": false, - "RequireDigidVerification": false, - "RequireKennisnetVerification": false, - "RequireSurfnetVerification": false, - "SendSignRequest": true, - "SendSignConfirmation": null, - "SignRequestMessage": "Hello, could you please sign this document? Best regards, John Doe", - "DaysToRemind": 15, - "Language": "en-US", - "ScribbleName": "John Doe", - "ScribbleNameFixed": false, - "Reference": "Client #123", - "ReturnUrl": "http://signhost.com", - "Activities": [ - { - "Id": "866183ae-0a3c-4441-a589-6fe3e1a0f1a1", - "Code": 103, - "Activity": "Opened", - "CreatedDateTime": "2016-03-31T21:11:42.0267461+02:00" - }, - { - "Id": "9b7c4de9-6b8d-4d22-9b88-b7d2d0f084b9", - "Code": 203, - "Activity": "Signed", - "CreatedDateTime": "2016-03-31T21:16:42.0267461+02:00" - } - ], - "RejectReason": null, - "SignUrl": "http://ui.signhost.com/sign/2eeaa5b9-9d4d-4418-b79f-4a33810e7147", - "SignedDateTime": null, - "RejectDateTime": null, - "CreatedDateTime": "2016-03-31T21:11:42.0267461+02:00", - "ModifiedDateTime": "2016-03-31T21:11:42.0267461+02:00", - "Context": null - } - ], - "Receivers": [ - { - "Id": "af07aaec-b612-4f7c-bb1b-c32603c9c6a2", - "Name": "John Doe", - "Email": "user@example.com", - "Language": "en-US", - "Message": "Hello, please find enclosed the digital signed document. Best regards, John Doe", - "Reference": null, - "Activities": null, - "CreatedDateTime": "2016-03-31T21:11:42.0267461+02:00", - "ModifiedDateTime": "2016-03-31T21:11:42.0267461+02:00", - "Context": null - } - ], - "Reference": "Contract #123", - "PostbackUrl": "http://example.com/postback.php", - "SignRequestMode": 2, - "DaysToExpire": 30, - "SendEmailNotifications": true, - "CreatedDateTime": "2016-03-31T21:11:42.0267461+02:00", - "ModifiedDateTime": "2016-03-31T21:11:42.0267461+02:00", - "CanceledDateTime": null, - "Context": null -} - - - { - "Id": "c487be92-0255-40c7-bd7d-20805a65e7d9", - "Status": 20, - "File": { - "Id": "d4bba0df-f9e5-44c8-89db-f2bb46632d7b", - "Name": "contract.pdf" - }, - "Seal": true, - "Signers": [ - { - "Id": "a2932c07-ca93-4011-96f5-a77d2cd1ec32", - "Expires": null, - "Email": "user@example.com", - "Mobile": "+31612345678", - "Iban": null, - "BSN": null, - "RequireScribbleName": false, - "RequireScribble": true, - "RequireEmailVerification": true, - "RequireSmsVerification": true, - "RequireIdealVerification": false, - "RequireDigidVerification": false, - "RequireKennisnetVerification": false, - "RequireSurfnetVerification": false, - "SendSignRequest": true, - "SendSignConfirmation": null, - "SignRequestMessage": "Hello, could you please sign this document? Best regards, John Doe", - "DaysToRemind": 15, - "Language": "en-US", - "ScribbleName": "John Doe", - "ScribbleNameFixed": false, - "Reference": "Client #123", - "ReturnUrl": "http://signhost.com", - "Activities": [ - { - "Id": "0b47eb5c-e800-4fe3-9795-09d380dff1f9", - "Code": 103, - "Activity": "Opened", - "CreatedDateTime": "2016-03-17T21:08:55.1349315+01:00" - }, - { - "Id": "761f8678-116c-4e86-a47a-c8312681d285", - "Code": 203, - "Activity": "Signed", - "CreatedDateTime": "2016-03-17T21:13:55.1349315+01:00" - } - ], - "RejectReason": null, - "SignUrl": "http://ui.signhost.com/sign/93dc596f-ab81-4d31-87aa-50352c4c237e", - "SignedDateTime": null, - "RejectDateTime": null, - "CreatedDateTime": "2016-03-17T21:08:55.1349315+01:00", - "ModifiedDateTime": "2016-03-17T21:08:55.1349315+01:00", - "Context": null - } - ], - "Receivers": [ - { - "Id": "2fe3dddf-4b50-49d1-a3d2-45b7d175fb97", - "Name": "John Doe", - "Email": "user@example.com", - "Language": "en-US", - "Message": "Hello, please find enclosed the digital signed document. Best regards, John Doe", - "Reference": null, - "Activities": null, - "CreatedDateTime": "2016-03-17T21:08:55.1349315+01:00", - "ModifiedDateTime": "2016-03-17T21:08:55.1349315+01:00", - "Context": null - } - ], - "Reference": "Contract #123", - "PostbackUrl": "http://example.com/postback.php", - "SignRequestMode": 2, - "DaysToExpire": 30, - "SendEmailNotifications": true, - "CreatedDateTime": "2016-03-17T21:08:55.1349315+01:00", - "ModifiedDateTime": "2016-03-17T21:08:55.1349315+01:00", - "CanceledDateTime": null, - "Context": null -} - - - { - "Id": "c487be92-0255-40c7-bd7d-20805a65e7d9", - "Status": 20, - "Seal": true, - "Signers": [ - { - "Id": "a2932c07-ca93-4011-96f5-a77d2cd1ec32", - "Expires": null, - "Email": "user@example.com", - "Mobile": "+31612345678", - "Iban": null, - "BSN": null, - "SendSignRequest": true, - "SendSignConfirmation": null, - "SignRequestMessage": "Hello, could you please sign this document? Best regards, John Doe", - "DaysToRemind": 15, - "Language": "en-US", - "Reference": "Client #123", - "ReturnUrl": "http://signhost.com", - "Verifications": [ - { - "Type": "CustomVerificationType" - }, - { - "Type": "IPAddress", - "IPAddress": "127.0.0.33" - }, - { - "Type": "PhoneNumber", - "Number": "123" - } - ], - "Activities": [ - { - "Id": "0b47eb5c-e800-4fe3-9795-09d380dff1f9", - "Code": 103, - "Activity": "Opened", - "CreatedDateTime": "2016-03-17T21:08:55.1349315+01:00" - }, - { - "Id": "761f8678-116c-4e86-a47a-c8312681d285", - "Code": 203, - "Activity": "Signed", - "CreatedDateTime": "2016-03-17T21:13:55.1349315+01:00" - } - ], - "SignUrl": "http://ui.signhost.com/sign/93dc596f-ab81-4d31-87aa-50352c4c237e", - "CreatedDateTime": "2016-03-17T21:08:55.1349315+01:00", - "ModifiedDateTime": "2016-03-17T21:08:55.1349315+01:00" - } - ], - "Receivers": [ - { - "Id": "2fe3dddf-4b50-49d1-a3d2-45b7d175fb97", - "Name": "John Doe", - "Email": "user@example.com", - "Language": "en-US", - "Message": "Hello, please find enclosed the digital signed document. Best regards, John Doe", - "CreatedDateTime": "2016-03-17T21:08:55.1349315+01:00", - "ModifiedDateTime": "2016-03-17T21:08:55.1349315+01:00", - } - ], - "Reference": "Contract #123", - "SignRequestMode": 2, - "DaysToExpire": 30, - "SendEmailNotifications": true, - "CreatedDateTime": "2016-03-17T21:08:55.1349315+01:00", - "ModifiedDateTime": "2016-03-17T21:08:55.1349315+01:00" -} - - - { - "Id": "50262c3f-9744-45bf-a4c6-8a3whatever", - "Status": 5 -} - - \ No newline at end of file diff --git a/src/SignhostAPIClient.Tests/JSON/AddOrReplaceFileMetaToTransaction.json b/src/SignhostAPIClient.Tests/JSON/AddOrReplaceFileMetaToTransaction.json new file mode 100644 index 00000000..1fc00000 --- /dev/null +++ b/src/SignhostAPIClient.Tests/JSON/AddOrReplaceFileMetaToTransaction.json @@ -0,0 +1 @@ +{"Signers":{"someSignerId":{"FormSets":["SampleFormSet"]}},"FormSets":{"SampleFormSet":{"SampleCheck":{"Type":"Check","Value":"I agree","Location":{"Search":"test"}}}}} \ No newline at end of file diff --git a/src/SignhostAPIClient.Tests/JSON/AddTransaction.json b/src/SignhostAPIClient.Tests/JSON/AddTransaction.json new file mode 100644 index 00000000..ea0bbe9f --- /dev/null +++ b/src/SignhostAPIClient.Tests/JSON/AddTransaction.json @@ -0,0 +1,80 @@ +{ + "Id":"c487be92-0255-40c7-bd7d-20805a65e7d9", + "Status":20, + "File":{ + "Id":"d4bba0df-f9e5-44c8-89db-f2bb46632d7b", + "Name":"contract.pdf" + }, + "Seal":true, + "Signers":[ + { + "Id":"a2932c07-ca93-4011-96f5-a77d2cd1ec32", + "Expires":null, + "Email":"user@example.com", + "Mobile":"+31612345678", + "Iban":null, + "BSN":null, + "RequireScribbleName":false, + "RequireScribble":true, + "RequireEmailVerification":true, + "RequireSmsVerification":true, + "RequireIdealVerification":false, + "RequireDigidVerification":false, + "RequireKennisnetVerification":false, + "RequireSurfnetVerification":false, + "SendSignRequest":true, + "SendSignConfirmation":null, + "SignRequestMessage":"Hello, could you please sign this document? Best regards, John Doe", + "DaysToRemind":15, + "Language":"en-US", + "ScribbleName":"John Doe", + "ScribbleNameFixed":false, + "Reference":"Client #123", + "ReturnUrl":"http://signhost.com", + "Activities":[ + { + "Id":"0b47eb5c-e800-4fe3-9795-09d380dff1f9", + "Code":103, + "Activity":"Opened", + "CreatedDateTime":"2016-03-17T21:08:55.1349315+01:00" + }, + { + "Id":"761f8678-116c-4e86-a47a-c8312681d285", + "Code":203, + "Activity":"Signed", + "CreatedDateTime":"2016-03-17T21:13:55.1349315+01:00" + } + ], + "RejectReason":null, + "SignUrl":"http://ui.signhost.com/sign/93dc596f-ab81-4d31-87aa-50352c4c237e", + "SignedDateTime":null, + "RejectDateTime":null, + "CreatedDateTime":"2016-03-17T21:08:55.1349315+01:00", + "ModifiedDateTime":"2016-03-17T21:08:55.1349315+01:00", + "Context":null + } + ], + "Receivers":[ + { + "Id":"2fe3dddf-4b50-49d1-a3d2-45b7d175fb97", + "Name":"John Doe", + "Email":"user@example.com", + "Language":"en-US", + "Message":"Hello, please find enclosed the digital signed document. Best regards, John Doe", + "Reference":null, + "Activities":null, + "CreatedDateTime":"2016-03-17T21:08:55.1349315+01:00", + "ModifiedDateTime":"2016-03-17T21:08:55.1349315+01:00", + "Context":null + } + ], + "Reference":"Contract #123", + "PostbackUrl":"http://example.com/postback.php", + "SignRequestMode":2, + "DaysToExpire":30, + "SendEmailNotifications":true, + "CreatedDateTime":"2016-03-17T21:08:55.1349315+01:00", + "ModifiedDateTime":"2016-03-17T21:08:55.1349315+01:00", + "CanceledDateTime":null, + "Context":null +} diff --git a/src/SignhostAPIClient.Tests/JSON/DeleteTransaction.json b/src/SignhostAPIClient.Tests/JSON/DeleteTransaction.json new file mode 100644 index 00000000..d87b4271 --- /dev/null +++ b/src/SignhostAPIClient.Tests/JSON/DeleteTransaction.json @@ -0,0 +1,80 @@ +{ + "Id":"496bec4d-4ac7-428f-894a-b3e9bade725d", + "Status":20, + "File":{ + "Id":"3149bf06-d01e-4f0d-9aa1-77e100e19772", + "Name":"contract.pdf" + }, + "Seal":true, + "Signers":[ + { + "Id":"4813e178-68a4-4105-b007-5ce9a3630867", + "Expires":null, + "Email":"user@example.com", + "Mobile":"+31612345678", + "Iban":null, + "BSN":null, + "RequireScribbleName":false, + "RequireScribble":true, + "RequireEmailVerification":true, + "RequireSmsVerification":true, + "RequireIdealVerification":false, + "RequireDigidVerification":false, + "RequireKennisnetVerification":false, + "RequireSurfnetVerification":false, + "SendSignRequest":true, + "SendSignConfirmation":null, + "SignRequestMessage":"Hello, could you please sign this document? Best regards, John Doe", + "DaysToRemind":15, + "Language":"en-US", + "ScribbleName":"John Doe", + "ScribbleNameFixed":false, + "Reference":"Client #123", + "ReturnUrl":"http://signhost.com", + "Activities":[ + { + "Id":"866183ae-0a3c-4441-a589-6fe3e1a0f1a1", + "Code":103, + "Activity":"Opened", + "CreatedDateTime":"2016-03-31T21:11:42.0267461+02:00" + }, + { + "Id":"9b7c4de9-6b8d-4d22-9b88-b7d2d0f084b9", + "Code":203, + "Activity":"Signed", + "CreatedDateTime":"2016-03-31T21:16:42.0267461+02:00" + } + ], + "RejectReason":null, + "SignUrl":"http://ui.signhost.com/sign/2eeaa5b9-9d4d-4418-b79f-4a33810e7147", + "SignedDateTime":null, + "RejectDateTime":null, + "CreatedDateTime":"2016-03-31T21:11:42.0267461+02:00", + "ModifiedDateTime":"2016-03-31T21:11:42.0267461+02:00", + "Context":null + } + ], + "Receivers":[ + { + "Id":"af07aaec-b612-4f7c-bb1b-c32603c9c6a2", + "Name":"John Doe", + "Email":"user@example.com", + "Language":"en-US", + "Message":"Hello, please find enclosed the digital signed document. Best regards, John Doe", + "Reference":null, + "Activities":null, + "CreatedDateTime":"2016-03-31T21:11:42.0267461+02:00", + "ModifiedDateTime":"2016-03-31T21:11:42.0267461+02:00", + "Context":null + } + ], + "Reference":"Contract #123", + "PostbackUrl":"http://example.com/postback.php", + "SignRequestMode":2, + "DaysToExpire":30, + "SendEmailNotifications":true, + "CreatedDateTime":"2016-03-31T21:11:42.0267461+02:00", + "ModifiedDateTime":"2016-03-31T21:11:42.0267461+02:00", + "CanceledDateTime":null, + "Context":null +} diff --git a/src/SignhostAPIClient.Tests/JSON/GetTransaction.json b/src/SignhostAPIClient.Tests/JSON/GetTransaction.json new file mode 100644 index 00000000..ea0bbe9f --- /dev/null +++ b/src/SignhostAPIClient.Tests/JSON/GetTransaction.json @@ -0,0 +1,80 @@ +{ + "Id":"c487be92-0255-40c7-bd7d-20805a65e7d9", + "Status":20, + "File":{ + "Id":"d4bba0df-f9e5-44c8-89db-f2bb46632d7b", + "Name":"contract.pdf" + }, + "Seal":true, + "Signers":[ + { + "Id":"a2932c07-ca93-4011-96f5-a77d2cd1ec32", + "Expires":null, + "Email":"user@example.com", + "Mobile":"+31612345678", + "Iban":null, + "BSN":null, + "RequireScribbleName":false, + "RequireScribble":true, + "RequireEmailVerification":true, + "RequireSmsVerification":true, + "RequireIdealVerification":false, + "RequireDigidVerification":false, + "RequireKennisnetVerification":false, + "RequireSurfnetVerification":false, + "SendSignRequest":true, + "SendSignConfirmation":null, + "SignRequestMessage":"Hello, could you please sign this document? Best regards, John Doe", + "DaysToRemind":15, + "Language":"en-US", + "ScribbleName":"John Doe", + "ScribbleNameFixed":false, + "Reference":"Client #123", + "ReturnUrl":"http://signhost.com", + "Activities":[ + { + "Id":"0b47eb5c-e800-4fe3-9795-09d380dff1f9", + "Code":103, + "Activity":"Opened", + "CreatedDateTime":"2016-03-17T21:08:55.1349315+01:00" + }, + { + "Id":"761f8678-116c-4e86-a47a-c8312681d285", + "Code":203, + "Activity":"Signed", + "CreatedDateTime":"2016-03-17T21:13:55.1349315+01:00" + } + ], + "RejectReason":null, + "SignUrl":"http://ui.signhost.com/sign/93dc596f-ab81-4d31-87aa-50352c4c237e", + "SignedDateTime":null, + "RejectDateTime":null, + "CreatedDateTime":"2016-03-17T21:08:55.1349315+01:00", + "ModifiedDateTime":"2016-03-17T21:08:55.1349315+01:00", + "Context":null + } + ], + "Receivers":[ + { + "Id":"2fe3dddf-4b50-49d1-a3d2-45b7d175fb97", + "Name":"John Doe", + "Email":"user@example.com", + "Language":"en-US", + "Message":"Hello, please find enclosed the digital signed document. Best regards, John Doe", + "Reference":null, + "Activities":null, + "CreatedDateTime":"2016-03-17T21:08:55.1349315+01:00", + "ModifiedDateTime":"2016-03-17T21:08:55.1349315+01:00", + "Context":null + } + ], + "Reference":"Contract #123", + "PostbackUrl":"http://example.com/postback.php", + "SignRequestMode":2, + "DaysToExpire":30, + "SendEmailNotifications":true, + "CreatedDateTime":"2016-03-17T21:08:55.1349315+01:00", + "ModifiedDateTime":"2016-03-17T21:08:55.1349315+01:00", + "CanceledDateTime":null, + "Context":null +} diff --git a/src/SignhostAPIClient.Tests/JSON/JsonResources.cs b/src/SignhostAPIClient.Tests/JSON/JsonResources.cs new file mode 100644 index 00000000..9bbfbe6e --- /dev/null +++ b/src/SignhostAPIClient.Tests/JSON/JsonResources.cs @@ -0,0 +1,37 @@ +using System.IO; +using System.Reflection; + +namespace SignhostAPIClient.Tests.JSON; + +public static class JsonResources +{ + public static string TransactionSingleSignerJson { get; } = + GetJson("TransactionSingleSignerJson"); + + public static string AddOrReplaceFileMetaToTransaction { get; } = + GetJson("AddOrReplaceFileMetaToTransaction"); + public static string AddTransaction { get; } = + GetJson("AddTransaction"); + public static string DeleteTransaction { get; } = + GetJson("DeleteTransaction"); + public static string GetTransaction { get; } = + GetJson("GetTransaction"); + public static string MinimalTransactionResponse { get; } = + GetJson("MinimalTransactionResponse"); + public static string MockPostbackInvalid { get; } = + GetJson("MockPostbackInvalid"); + public static string MockPostbackValid { get; } = + GetJson("MockPostbackValid"); + + private static string GetJson(string fileName) + { + var assembly = Assembly.GetExecutingAssembly(); + string resourceName = $"Signhost.APIClient.Rest.Tests.JSON.{fileName}.json"; + + using var stream = assembly.GetManifestResourceStream(resourceName) + ?? throw new FileNotFoundException($"File not found: {fileName}"); + + using var reader = new StreamReader(stream); + return reader.ReadToEnd(); + } +} diff --git a/src/SignhostAPIClient.Tests/JSON/MinimalTransactionResponse.json b/src/SignhostAPIClient.Tests/JSON/MinimalTransactionResponse.json new file mode 100644 index 00000000..99016264 --- /dev/null +++ b/src/SignhostAPIClient.Tests/JSON/MinimalTransactionResponse.json @@ -0,0 +1,4 @@ +{ + "Id":"50262c3f-9744-45bf-a4c6-8a3whatever", + "Status":5 +} diff --git a/src/SignhostAPIClient.Tests/JSON/MockPostbackInvalid.json b/src/SignhostAPIClient.Tests/JSON/MockPostbackInvalid.json new file mode 100644 index 00000000..ce1c2c4e --- /dev/null +++ b/src/SignhostAPIClient.Tests/JSON/MockPostbackInvalid.json @@ -0,0 +1,76 @@ +{ + "Id":"b10ae331-af78-4e79-a39e-5b64693b6b68", + "Status":20, + "Seal":true, + "Signers":[ + { + "Id":"fa95495d-6c59-48e0-962a-a4552f8d6b85", + "Expires":null, + "Email":"user@example.com", + "Mobile":"+31612345678", + "Iban":null, + "BSN":null, + "RequireScribbleName":false, + "RequireScribble":true, + "RequireEmailVerification":true, + "RequireSmsVerification":true, + "RequireIdealVerification":false, + "RequireDigidVerification":false, + "RequireKennisnetVerification":false, + "RequireSurfnetVerification":false, + "SendSignRequest":true, + "SendSignConfirmation":null, + "SignRequestMessage":"Hello, could you please sign this document? Best regards, John Doe", + "DaysToRemind":15, + "Language":"en-US", + "ScribbleName":"John Doe", + "ScribbleNameFixed":false, + "Reference":"Client #123", + "ReturnUrl":"https://signhost.com", + "Activities":[ + { + "Id":"bcba44a9-c201-4494-9920-2c1f7baebcf0", + "Code":103, + "Activity":"Opened", + "CreatedDateTime":"2016-06-15T23:33:04.1965465+02:00" + }, + { + "Id":"de94cf6e-e1a3-4c33-93bf-2013b036daaf", + "Code":203, + "Activity":"Signed", + "CreatedDateTime":"2016-06-15T23:38:04.1965465+02:00" + } + ], + "RejectReason":null, + "SignUrl":"https://view.signhost.com/sign/d3c93bd6-f1ce-48e7-8c9c-c2babfdd4034", + "SignedDateTime":null, + "RejectDateTime":null, + "CreatedDateTime":"2016-06-15T23:33:04.1965465+02:00", + "ModifiedDateTime":"2016-06-15T23:33:04.1965465+02:00", + "Context":null + } + ], + "Receivers":[ + { + "Id":"97ed6b54-b6d1-46ed-88c1-79779c3b47b1", + "Name":"John Doe", + "Email":"user@example.com", + "Language":"en-US", + "Message":"Hello, please find enclosed the digital signed document. Best regards, John Doe", + "Reference":null, + "Activities":null, + "CreatedDateTime":"2016-06-15T23:33:04.1965465+02:00", + "ModifiedDateTime":"2016-06-15T23:33:04.1965465+02:00", + "Context":null + } + ], + "Reference":"Contract #123", + "PostbackUrl":"https://example.com/postback.php", + "SignRequestMode":2, + "DaysToExpire":30, + "SendEmailNotifications":true, + "CreatedDateTime":"2016-08-31T21:22:56.2467731+02:00", + "ModifiedDateTime":"2016-08-31T21:22:56.2467731+02:00", + "CanceledDateTime":null, + "Context":null +} diff --git a/src/SignhostAPIClient.Tests/JSON/MockPostbackValid.json b/src/SignhostAPIClient.Tests/JSON/MockPostbackValid.json new file mode 100644 index 00000000..62ab673a --- /dev/null +++ b/src/SignhostAPIClient.Tests/JSON/MockPostbackValid.json @@ -0,0 +1,112 @@ +{ + "Id":"b10ae331-af78-4e79-a39e-5b64693b6b68", + "Status":20, + "Files":{ + "file1":{ + "Links":[ + { + "Rel":"file", + "Type":"application/pdf", + "Link":"https://api.signhost.com/api/transaction/b10ae331-af78-4e79-a39e-5b64693b6b68/file/file1" + } + ], + "DisplayName":"Sample File" + } + }, + "Seal":true, + "Signers":[ + { + "Id":"fa95495d-6c59-48e0-962a-a4552f8d6b85", + "Expires":null, + "Email":"user@example.com", + "Verifications":[ + { + "Type":"PhoneNumber", + "Number":"+31612345678" + }, + { + "Type":"Scribble", + "RequireHandsignature":false, + "ScribbleNameFixed":false, + "ScribbleName":"John Doe" + }, + { + "Type":"IPAddress", + "IPAddress":"1.2.3.4" + } + ], + "Mobile":"+31612345678", + "Iban":null, + "BSN":null, + "RequireScribbleName":false, + "RequireScribble":true, + "RequireEmailVerification":true, + "RequireSmsVerification":true, + "RequireIdealVerification":false, + "RequireDigidVerification":false, + "RequireKennisnetVerification":false, + "RequireSurfnetVerification":false, + "SendSignRequest":true, + "SendSignConfirmation":null, + "SignRequestMessage":"Hello, could you please sign this document? Best regards, John Doe", + "DaysToRemind":15, + "Language":"en-US", + "ScribbleName":"John Doe", + "ScribbleNameFixed":false, + "Reference":"Client #123", + "ReturnUrl":"https://signhost.com", + "Activities":[ + { + "Id":"bcba44a9-c201-4494-9920-2c1f7baebcf0", + "Code":103, + "Activity":"Opened", + "CreatedDateTime":"2016-06-15T23:33:04.1965465+02:00" + }, + { + "Id":"7aacf96a-5c2f-475d-98a5-726e41bfc5d3", + "Code":105, + "Activity":"DocumentOpened", + "Info":"file1", + "CreatedDateTime":"2020-01-30T16:31:05.6679583+01:00" + }, + { + "Id":"de94cf6e-e1a3-4c33-93bf-2013b036daaf", + "Code":203, + "Activity":"Signed", + "CreatedDateTime":"2016-06-15T23:38:04.1965465+02:00" + } + ], + "RejectReason":null, + "SignUrl":"https://view.signhost.com/sign/d3c93bd6-f1ce-48e7-8c9c-c2babfdd4034", + "SignedDateTime":null, + "RejectDateTime":null, + "CreatedDateTime":"2016-06-15T23:33:04.1965465+02:00", + "ModifiedDateTime":"2016-06-15T23:33:04.1965465+02:00", + "Context":null + } + ], + "Receivers":[ + { + "Id":"97ed6b54-b6d1-46ed-88c1-79779c3b47b1", + "Name":"John Doe", + "Email":"user@example.com", + "Language":"en-US", + "Message":"Hello, please find enclosed the digital signed document. Best regards, John Doe", + "Reference":null, + "Activities":null, + "CreatedDateTime":"2016-06-15T23:33:04.1965465+02:00", + "ModifiedDateTime":"2016-06-15T23:33:04.1965465+02:00", + "Context":null + } + ], + "Reference":"Contract #123", + "PostbackUrl":"https://example.com/postback.php", + "SignRequestMode":2, + "DaysToExpire":30, + "SendEmailNotifications":true, + "CreatedDateTime":"2016-08-31T21:22:56.2467731+02:00", + "ModifiedDateTime":"2016-08-31T21:22:56.2467731+02:00", + "CanceledDateTime":null, + "Context":null, + "Checksum":"cdc09eee2ed6df2846dcc193aedfef59f2834f8d" +} diff --git a/src/SignhostAPIClient.Tests/JSON/TransactionSingleSignerJson.json b/src/SignhostAPIClient.Tests/JSON/TransactionSingleSignerJson.json new file mode 100644 index 00000000..07d2fdb9 --- /dev/null +++ b/src/SignhostAPIClient.Tests/JSON/TransactionSingleSignerJson.json @@ -0,0 +1,46 @@ +{ + "Id":"50262c3f-9744-45bf-a4c6-8a3whatever", + "Status":5, + "CanceledDateTime":"2017-01-01T15:00:00.0000000+01:00", + "Files":{}, + "Seal":false, + "Signers":[ + { + "Id":"Signer1", + "Email":"test1@example.com", + "Verifications":[ + { + "Type":"PhoneNumber", + "Number":"+31615123456" + } + ], + "Mobile":"+31615087075", + "SignRequestMessage":"Hello 1st signer", + "Language":"nl-NL", + "Activities":[ + { + "Id":"Activity1", + "Code":103, + "CreatedDateTime":"2017-05-31T22:15:17.6409005+02:00" + }, + { + "Id":"Activity2", + "Code":105, + "Info":"592f2448347cd", + "CreatedDateTime":"2017-05-31T22:15:20.3284659+02:00" + }, + { + "Id":"25dd4131-f1c4-4e4c-a407-c4164cfe4096", + "Code":105, + "Info":"592f244834807", + "CreatedDateTime":"2017-05-31T22:15:24.4379773+02:00" + } + ] + } + ], + "Receivers":[], + "Reference":"Contract #123", + "SignRequestMode":2, + "DaysToExpire":14, + "Context":null +} diff --git a/src/SignhostAPIClient.Tests/LevelEnumConverterTests.cs b/src/SignhostAPIClient.Tests/LevelEnumConverterTests.cs index 67e491d1..534d5484 100644 --- a/src/SignhostAPIClient.Tests/LevelEnumConverterTests.cs +++ b/src/SignhostAPIClient.Tests/LevelEnumConverterTests.cs @@ -1,5 +1,5 @@ using FluentAssertions; -using Newtonsoft.Json; +using System.Text.Json; using Signhost.APIClient.Rest.DataObjects; using System; using System.Collections; @@ -17,7 +17,7 @@ public void when_Level_is_null_should_deserialize_to_null() const string json = "{\"Type\":\"eIDAS Login\",\"Level\":null}"; // Act - var eidasLogin = JsonConvert.DeserializeObject(json); + var eidasLogin = JsonSerializer.Deserialize(json, SignhostJsonSerializerOptions.Default); // Assert eidasLogin.Level.Should().Be(null); @@ -30,7 +30,7 @@ public void when_Level_is_not_supplied_should_deserialize_to_null() const string json = "{\"Type\":\"eIDAS Login\"}"; // Act - var eidasLogin = JsonConvert.DeserializeObject(json); + var eidasLogin = JsonSerializer.Deserialize(json, SignhostJsonSerializerOptions.Default); // Assert eidasLogin.Level.Should().Be(null); @@ -43,7 +43,7 @@ public void when_Level_is_unknown_should_deserialize_to_Unknown_Level() const string json = "{\"Type\":\"eIDAS Login\",\"Level\":\"foobar\"}"; // Act - var eidasLogin = JsonConvert.DeserializeObject(json); + var eidasLogin = JsonSerializer.Deserialize(json, SignhostJsonSerializerOptions.Default); // Assert eidasLogin.Level.Should().Be(Level.Unknown); @@ -57,7 +57,7 @@ public void when_Level_is_valid_should_deserialize_to_correct_value(Level level) string json = $"{{\"Type\":\"eIDAS Login\",\"Level\":\"{level}\"}}"; // Act - var eidasLogin = JsonConvert.DeserializeObject(json); + var eidasLogin = JsonSerializer.Deserialize(json, SignhostJsonSerializerOptions.Default); // Assert eidasLogin.Level.Should().Be(level); diff --git a/src/SignhostAPIClient.Tests/PostbackTests.cs b/src/SignhostAPIClient.Tests/PostbackTests.cs index a4724723..7a005953 100644 --- a/src/SignhostAPIClient.Tests/PostbackTests.cs +++ b/src/SignhostAPIClient.Tests/PostbackTests.cs @@ -1,8 +1,9 @@ using System; using System.Linq; +using System.Text.Json; using FluentAssertions; -using Newtonsoft.Json; using Signhost.APIClient.Rest.DataObjects; +using SignhostAPIClient.Tests.JSON; using Xunit; namespace Signhost.APIClient.Rest.Tests @@ -12,8 +13,8 @@ public class PostbackTests [Fact] public void PostbackTransaction_should_get_serialized_correctly() { - string json = RequestBodies.MockPostbackValid; - var postbackTransaction = JsonConvert.DeserializeObject(json); + string json = JsonResources.MockPostbackValid; + var postbackTransaction = JsonSerializer.Deserialize(json, SignhostJsonSerializerOptions.Default); postbackTransaction.Id .Should().Be("b10ae331-af78-4e79-a39e-5b64693b6b68"); postbackTransaction.Status .Should().Be(TransactionStatus.InProgress); @@ -24,7 +25,7 @@ public void PostbackTransaction_should_get_serialized_correctly() postbackTransaction.DaysToExpire .Should().Be(30); postbackTransaction.SendEmailNotifications.Should().BeTrue(); postbackTransaction.CreatedDateTime .Should().Be(DateTimeOffset.Parse("2016-08-31T21:22:56.2467731+02:00")); - postbackTransaction.CancelledDateTime .Should().BeNull(); + postbackTransaction.CanceledDateTime .Should().BeNull(); (postbackTransaction.Context is null) .Should().BeTrue(); postbackTransaction.Checksum .Should().Be("cdc09eee2ed6df2846dcc193aedfef59f2834f8d"); @@ -53,19 +54,16 @@ public void PostbackTransaction_should_get_serialized_correctly() var phoneNumberVerification = verifications[0] as PhoneNumberVerification; phoneNumberVerification .Should().NotBeNull(); - phoneNumberVerification.Type .Should().Be("PhoneNumber"); phoneNumberVerification.Number.Should().Be("+31612345678"); var scribbleVerification = verifications[1] as ScribbleVerification; scribbleVerification .Should().NotBeNull(); - scribbleVerification.Type .Should().Be("Scribble"); scribbleVerification.RequireHandsignature.Should().BeFalse(); scribbleVerification.ScribbleNameFixed .Should().BeFalse(); scribbleVerification.ScribbleName .Should().Be("John Doe"); var ipAddressVerification = verifications[2] as IPAddressVerification; ipAddressVerification .Should().NotBeNull(); - ipAddressVerification.Type .Should().Be("IPAddress"); ipAddressVerification.IPAddress.Should().Be("1.2.3.4"); var activities = signer.Activities; diff --git a/src/SignhostAPIClient.Tests/RequestBodies.Designer.cs b/src/SignhostAPIClient.Tests/RequestBodies.Designer.cs deleted file mode 100644 index 55227f02..00000000 --- a/src/SignhostAPIClient.Tests/RequestBodies.Designer.cs +++ /dev/null @@ -1,114 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Signhost.APIClient.Rest.Tests { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class RequestBodies { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal RequestBodies() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Signhost.APIClient.Rest.Tests.RequestBodies", typeof(RequestBodies).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to {"DisplayOrder":null,"DisplayName":null,"Description":null,"Signers":{"someSignerId":{"FormSets":["SampleFormSet"]}},"FormSets":{"SampleFormSet":{"SampleCheck":{"Type":"Check","Value":"I agree","Location":{"Search":"test","Occurence":null,"Top":null,"Right":null,"Bottom":null,"Left":null,"Width":null,"Height":null,"PageNumber":null}}}}}. - /// - internal static string AddOrReplaceFileMetaToTransaction { - get { - return ResourceManager.GetString("AddOrReplaceFileMetaToTransaction", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to { - /// "Id": "50262c3f-9744-45bf-a4c6-8a3whatever", - /// "Status": 5, - /// "CanceledDateTime": "2017-01-01 15:00", - /// "Files": {}, - /// "Seal": false, - /// "Signers": [ - /// { - /// "Id": "Signer1", - /// "Email": "test1@example.com", - /// "Verifications": [ - /// { - /// "Type": "PhoneNumber", - /// "Number": "+31615123456" - /// } - /// ], - /// "Mobile": "+31615087075", - /// "SignRequestMessage": "Hello 1st signer", - /// "Language": "nl-NL", - /// "Activities": [ - /// { - /// "I [rest of string was truncated]";. - /// - internal static string TransactionSingleSignerJson { - get { - return ResourceManager.GetString("TransactionSingleSignerJson", resourceCulture); - } - } - - internal static string MockPostbackValid { - get { - return ResourceManager.GetString("MockPostbackValid", resourceCulture); - } - } - - internal static string MockPostbackInvalid { - get { - return ResourceManager.GetString("MockPostbackInvalid", resourceCulture); - } - } - } -} diff --git a/src/SignhostAPIClient.Tests/RequestBodies.resx b/src/SignhostAPIClient.Tests/RequestBodies.resx deleted file mode 100644 index 62d2094a..00000000 --- a/src/SignhostAPIClient.Tests/RequestBodies.resx +++ /dev/null @@ -1,355 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - {"DisplayOrder":null,"DisplayName":null,"Description":null,"Signers":{"someSignerId":{"FormSets":["SampleFormSet"]}},"FormSets":{"SampleFormSet":{"SampleCheck":{"Type":"Check","Value":"I agree","Location":{"Search":"test","Occurence":null,"Top":null,"Right":null,"Bottom":null,"Left":null,"Width":null,"Height":null,"PageNumber":null}}}}} - - - { - "Id": "50262c3f-9744-45bf-a4c6-8a3whatever", - "Status": 5, - "CanceledDateTime": "2017-01-01 15:00", - "Files": {}, - "Seal": false, - "Signers": [ - { - "Id": "Signer1", - "Email": "test1@example.com", - "Verifications": [ - { - "Type": "PhoneNumber", - "Number": "+31615123456" - } - ], - "Mobile": "+31615087075", - "SignRequestMessage": "Hello 1st signer", - "Language": "nl-NL", - "Activities": [ - { - "Id": "Activity1", - "Code": 103, - "CreatedDateTime": "2017-05-31T22:15:17.6409005+02:00" - }, - { - "Id": "Activity2", - "Code": 105, - "Info": "592f2448347cd", - "CreatedDateTime": "2017-05-31T22:15:20.3284659+02:00" - }, - { - "Id": "25dd4131-f1c4-4e4c-a407-c4164cfe4096", - "Code": 105, - "Info": "592f244834807", - "CreatedDateTime": "2017-05-31T22:15:24.4379773+02:00" - } - ] - } - ], - "Receivers": [], - "Reference": "Contract #123", - "SignRequestMode": 2, - "DaysToExpire": 14, - "Context": null -} - - - -{ - "Id": "b10ae331-af78-4e79-a39e-5b64693b6b68", - "Status": 20, - "Files": { - "file1": { - "Links": [ - { - "Rel": "file", - "Type": "application/pdf", - "Link": "https://api.signhost.com/api/transaction/b10ae331-af78-4e79-a39e-5b64693b6b68/file/file1" - } - ], - "DisplayName": "Sample File" - } - }, - "Seal": true, - "Signers": - [{ - "Id": "fa95495d-6c59-48e0-962a-a4552f8d6b85", - "Expires": null, - "Email": "user@example.com", - "Verifications": [ - { - "Type": "PhoneNumber", - "Number": "+31612345678" - }, - { - "Type": "Scribble", - "RequireHandsignature": false, - "ScribbleNameFixed": false, - "ScribbleName": "John Doe" - }, - { - "Type": "IPAddress", - "IPAddress": "1.2.3.4" - } - ], - "Mobile": "+31612345678", - "Iban": null, - "BSN": null, - "RequireScribbleName": false, - "RequireScribble": true, - "RequireEmailVerification": true, - "RequireSmsVerification": true, - "RequireIdealVerification": false, - "RequireDigidVerification": false, - "RequireKennisnetVerification": false, - "RequireSurfnetVerification": false, - "SendSignRequest": true, - "SendSignConfirmation": null, - "SignRequestMessage": "Hello, could you please sign this document? Best regards, John Doe", - "DaysToRemind": 15, - "Language": "en-US", - "ScribbleName": "John Doe", - "ScribbleNameFixed": false, - "Reference": "Client #123", - "ReturnUrl": "https://signhost.com", - "Activities": - [{ - "Id": "bcba44a9-c201-4494-9920-2c1f7baebcf0", - "Code": 103, - "Activity": "Opened", - "CreatedDateTime": "2016-06-15T23:33:04.1965465+02:00"}, - { - "Id": "7aacf96a-5c2f-475d-98a5-726e41bfc5d3", - "Code": 105, - "Activity": "DocumentOpened", - "Info": "file1", - "CreatedDateTime": "2020-01-30T16:31:05.6679583+01:00" - }, - { - "Id": "de94cf6e-e1a3-4c33-93bf-2013b036daaf", - "Code": 203,"Activity": "Signed", - "CreatedDateTime": "2016-06-15T23:38:04.1965465+02:00" - }], - "RejectReason": null, - "SignUrl": "https://view.signhost.com/sign/d3c93bd6-f1ce-48e7-8c9c-c2babfdd4034", - "SignedDateTime": null, - "RejectDateTime": null, - "CreatedDateTime": "2016-06-15T23:33:04.1965465+02:00", - "ModifiedDateTime": "2016-06-15T23:33:04.1965465+02:00", - "Context": null}], - "Receivers": - [{ - "Id": "97ed6b54-b6d1-46ed-88c1-79779c3b47b1", - "Name": "John Doe", - "Email": "user@example.com", - "Language": "en-US", - "Message": "Hello, please find enclosed the digital signed document. Best regards, John Doe", - "Reference": null, - "Activities": null, - "CreatedDateTime": "2016-06-15T23:33:04.1965465+02:00", - "ModifiedDateTime": "2016-06-15T23:33:04.1965465+02:00", - "Context": null - }], - "Reference": "Contract #123", - "PostbackUrl": "https://example.com/postback.php", - "SignRequestMode": 2, - "DaysToExpire": 30, - "SendEmailNotifications": true, - "CreatedDateTime": "2016-08-31T21:22:56.2467731+02:00", - "ModifiedDateTime": "2016-08-31T21:22:56.2467731+02:00", - "CanceledDateTime": null, - "Context": null, - "Checksum": "cdc09eee2ed6df2846dcc193aedfef59f2834f8d" -} - - - - -{ - "Id": "b10ae331-af78-4e79-a39e-5b64693b6b68", - "Status": 20, - "Seal": true, - "Signers": - [{ - "Id": "fa95495d-6c59-48e0-962a-a4552f8d6b85", - "Expires": null, - "Email": "user@example.com", - "Mobile": "+31612345678", - "Iban": null, - "BSN": null, - "RequireScribbleName": false, - "RequireScribble": true, - "RequireEmailVerification": true, - "RequireSmsVerification": true, - "RequireIdealVerification": false, - "RequireDigidVerification": false, - "RequireKennisnetVerification": false, - "RequireSurfnetVerification": false, - "SendSignRequest": true, - "SendSignConfirmation": null, - "SignRequestMessage": "Hello, could you please sign this document? Best regards, John Doe", - "DaysToRemind": 15, - "Language": "en-US", - "ScribbleName": "John Doe", - "ScribbleNameFixed": false, - "Reference": "Client #123", - "ReturnUrl": "https://signhost.com", - "Activities": - [{ - "Id": "bcba44a9-c201-4494-9920-2c1f7baebcf0", - "Code": 103, - "Activity": "Opened", - "CreatedDateTime": "2016-06-15T23:33:04.1965465+02:00"}, - { - "Id": "de94cf6e-e1a3-4c33-93bf-2013b036daaf", - "Code": 203,"Activity": "Signed", - "CreatedDateTime": "2016-06-15T23:38:04.1965465+02:00" - }], - "RejectReason": null, - "SignUrl": "https://view.signhost.com/sign/d3c93bd6-f1ce-48e7-8c9c-c2babfdd4034", - "SignedDateTime": null, - "RejectDateTime": null, - "CreatedDateTime": "2016-06-15T23:33:04.1965465+02:00", - "ModifiedDateTime": "2016-06-15T23:33:04.1965465+02:00", - "Context": null}], - "Receivers": - [{ - "Id": "97ed6b54-b6d1-46ed-88c1-79779c3b47b1", - "Name": "John Doe", - "Email": "user@example.com", - "Language": "en-US", - "Message": "Hello, please find enclosed the digital signed document. Best regards, John Doe", - "Reference": null, - "Activities": null, - "CreatedDateTime": "2016-06-15T23:33:04.1965465+02:00", - "ModifiedDateTime": "2016-06-15T23:33:04.1965465+02:00", - "Context": null - }], - "Reference": "Contract #123", - "PostbackUrl": "https://example.com/postback.php", - "SignRequestMode": 2, - "DaysToExpire": 30, - "SendEmailNotifications": true, - "CreatedDateTime": "2016-08-31T21:22:56.2467731+02:00", - "ModifiedDateTime": "2016-08-31T21:22:56.2467731+02:00", - "CanceledDateTime": null, - "Context": null, -} - - - diff --git a/src/SignhostAPIClient.Tests/SignhostAPIClient.Tests.csproj b/src/SignhostAPIClient.Tests/SignhostAPIClient.Tests.csproj index fbe586e5..d7aa909c 100644 --- a/src/SignhostAPIClient.Tests/SignhostAPIClient.Tests.csproj +++ b/src/SignhostAPIClient.Tests/SignhostAPIClient.Tests.csproj @@ -10,7 +10,6 @@ - @@ -22,23 +21,11 @@ - - Signhost.APIClient.Rest.Tests - - - - ResXFileCodeGenerator - - - ResXFileCodeGenerator - RequestBodies.Designer.cs - + - - - RequestBodies.resx - - + + Signhost.APIClient.Rest.Tests + diff --git a/src/SignhostAPIClient.Tests/SignhostApiClientTests.cs b/src/SignhostAPIClient.Tests/SignhostApiClientTests.cs index 041a40f4..0e5f1e9b 100644 --- a/src/SignhostAPIClient.Tests/SignhostApiClientTests.cs +++ b/src/SignhostAPIClient.Tests/SignhostApiClientTests.cs @@ -8,16 +8,18 @@ using System.Collections.Generic; using RichardSzalay.MockHttp; using System.Net; +using SignhostAPIClient.Tests.JSON; +using System.Text.Json.Serialization; namespace Signhost.APIClient.Rest.Tests { - public class SignHostApiClientTests + public class SignhostApiClientTests { - private readonly SignHostApiClientSettings settings = new("AppKey", "Usertoken") { + private readonly SignhostApiClientSettings settings = new("AppKey", "Usertoken") { Endpoint = "http://localhost/api/" }; - private readonly SignHostApiClientSettings oauthSettings = new("AppKey") { + private readonly SignhostApiClientSettings oauthSettings = new("AppKey") { Endpoint = "http://localhost/api/" }; @@ -27,11 +29,11 @@ public async Task when_AddOrReplaceFileMetaToTransaction_is_called_then_the_requ var mockHttp = new MockHttpMessageHandler(); mockHttp.Expect(HttpMethod.Put, "http://localhost/api/transaction/transactionId/file/fileId") - .WithContent(RequestBodies.AddOrReplaceFileMetaToTransaction) + .WithContent(JsonResources.AddOrReplaceFileMetaToTransaction) .Respond(HttpStatusCode.OK); using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignHostApiClient(settings, httpClient); + var signhostApiClient = new SignhostApiClient(settings, httpClient); var fileSignerMeta = new FileSignerMeta { @@ -76,11 +78,11 @@ public async Task when_a_GetTransaction_is_called_then_we_should_have_called_the var mockHttp = new MockHttpMessageHandler(); mockHttp .Expect(HttpMethod.Get, "http://localhost/api/transaction/transaction Id") - .Respond(HttpStatusCode.OK, new StringContent(APIResponses.GetTransaction)); + .Respond(HttpStatusCode.OK, new StringContent(JsonResources.GetTransaction)); using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignHostApiClient(settings, httpClient); + var signhostApiClient = new SignhostApiClient(settings, httpClient); var result = await signhostApiClient.GetTransactionAsync("transaction Id"); result.Id.Should().Be("c487be92-0255-40c7-bd7d-20805a65e7d9"); @@ -95,11 +97,15 @@ public async Task when_GetTransaction_is_called_and_the_authorization_is_bad_the var mockHttp = new MockHttpMessageHandler(); mockHttp .Expect(HttpMethod.Get, "http://localhost/api/transaction/transaction Id") - .Respond(HttpStatusCode.Unauthorized, new StringContent("{'message': 'unauthorized' }")); + .Respond(HttpStatusCode.Unauthorized, new StringContent(""" + { + "message": "unauthorized" + } + """)); using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignHostApiClient(settings, httpClient); + var signhostApiClient = new SignhostApiClient(settings, httpClient); Func getTransaction = () => signhostApiClient.GetTransactionAsync("transaction Id"); await getTransaction.Should().ThrowAsync(); @@ -114,11 +120,15 @@ public async Task when_GetTransaction_is_called_and_request_is_bad_then_we_shoul var mockHttp = new MockHttpMessageHandler(); mockHttp .Expect(HttpMethod.Get, "http://localhost/api/transaction/transaction Id") - .Respond(HttpStatusCode.BadRequest, new StringContent("{ 'message': 'Bad Request' }")); + .Respond(HttpStatusCode.BadRequest, new StringContent(""" + { + "message": "Bad Request" + } + """)); using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignHostApiClient(settings, httpClient); + var signhostApiClient = new SignhostApiClient(settings, httpClient); Func getTransaction = () => signhostApiClient.GetTransactionAsync("transaction Id"); await getTransaction.Should().ThrowAsync(); @@ -133,11 +143,15 @@ public async Task when_GetTransaction_is_called_and_credits_have_run_out_then_we var mockHttp = new MockHttpMessageHandler(); mockHttp .Expect(HttpMethod.Get, "http://localhost/api/transaction/transaction Id") - .Respond(HttpStatusCode.PaymentRequired, new StringContent("{ 'type': 'https://api.signhost.com/problem/subscription/out-of-credits' }")); + .Respond(HttpStatusCode.PaymentRequired, new StringContent(""" + { + "type": "https://api.signhost.com/problem/subscription/out-of-credits" + } + """)); using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignHostApiClient(settings, httpClient); + var signhostApiClient = new SignhostApiClient(settings, httpClient); Func getTransaction = () => signhostApiClient.GetTransactionAsync("transaction Id"); await getTransaction.Should().ThrowAsync(); @@ -152,11 +166,15 @@ public async Task when_GetTransaction_is_called_and_not_found_then_we_should_get var mockHttp = new MockHttpMessageHandler(); mockHttp .Expect(HttpMethod.Get, "http://localhost/api/transaction/transaction Id") - .Respond(HttpStatusCode.NotFound, new StringContent("{ 'Message': 'Not Found' }")); + .Respond(HttpStatusCode.NotFound, new StringContent(""" + { + "message": "Not Found" + } + """)); using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignHostApiClient(settings, httpClient); + var signhostApiClient = new SignhostApiClient(settings, httpClient); Func getTransaction = () => signhostApiClient.GetTransactionAsync("transaction Id"); @@ -172,11 +190,15 @@ public async Task when_GetTransaction_is_called_and_unkownerror_like_418_occures var mockHttp = new MockHttpMessageHandler(); mockHttp .Expect(HttpMethod.Get, "http://localhost/api/transaction/transaction Id") - .Respond((HttpStatusCode)418, new StringContent("{ 'message': '418 I\\'m a teapot' }")); + .Respond((HttpStatusCode)418, new StringContent(""" + { + "message": "418 I'm a teapot" + } + """)); using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignHostApiClient(settings, httpClient); + var signhostApiClient = new SignhostApiClient(settings, httpClient); Func getTransaction = () => signhostApiClient.GetTransactionAsync("transaction Id"); await getTransaction.Should().ThrowAsync() @@ -192,11 +214,15 @@ public async Task when_GetTransaction_is_called_and_there_is_an_InternalServerEr var mockHttp = new MockHttpMessageHandler(); mockHttp .Expect(HttpMethod.Get, "http://localhost/api/transaction/transaction Id") - .Respond(HttpStatusCode.InternalServerError, new StringContent("{ 'message': 'Internal Server Error' }")); + .Respond(HttpStatusCode.InternalServerError, new StringContent(""" + { + "message": "Internal Server Error" + } + """)); using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignHostApiClient(settings, httpClient); + var signhostApiClient = new SignhostApiClient(settings, httpClient); Func getTransaction = () => signhostApiClient.GetTransactionAsync("transaction Id"); await getTransaction.Should().ThrowAsync(); @@ -211,10 +237,10 @@ public async Task When_GetTransaction_is_called_on_gone_transaction_we_shoud_get var mockHttp = new MockHttpMessageHandler(); mockHttp .Expect(HttpMethod.Get, "http://localhost/api/transaction/transaction Id") - .Respond(HttpStatusCode.Gone, new StringContent(APIResponses.GetTransaction)); + .Respond(HttpStatusCode.Gone, new StringContent(JsonResources.GetTransaction)); using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignHostApiClient(settings, httpClient); + var signhostApiClient = new SignhostApiClient(settings, httpClient); Func getTransaction = () => signhostApiClient.GetTransactionAsync("transaction Id"); await getTransaction.Should().ThrowAsync>(); @@ -229,10 +255,10 @@ public async Task When_GetTransaction_is_called_and_gone_is_expected_we_should_g var mockHttp = new MockHttpMessageHandler(); mockHttp .Expect(HttpMethod.Get, "http://localhost/api/transaction/transaction Id") - .Respond(HttpStatusCode.Gone, new StringContent(APIResponses.GetTransaction)); + .Respond(HttpStatusCode.Gone, new StringContent(JsonResources.GetTransaction)); using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignHostApiClient(settings, httpClient); + var signhostApiClient = new SignhostApiClient(settings, httpClient); Func getTransaction = () => signhostApiClient.GetTransactionResponseAsync("transaction Id"); await getTransaction.Should().NotThrowAsync(); @@ -247,10 +273,10 @@ public async Task when_a_CreateTransaction_is_called_then_we_should_have_called_ var mockHttp = new MockHttpMessageHandler(); mockHttp .Expect(HttpMethod.Post, "http://localhost/api/transaction") - .Respond(HttpStatusCode.OK, new StringContent(APIResponses.AddTransaction)); + .Respond(HttpStatusCode.OK, new StringContent(JsonResources.AddTransaction)); using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignHostApiClient(settings, httpClient); + var signhostApiClient = new SignhostApiClient(settings, httpClient); Signer testSigner = new Signer(); testSigner.Email = "firstname.lastname@gmail.com"; @@ -273,12 +299,12 @@ public async Task when_a_CreateTransaction_is_called_we_can_add_custom_http_head .Expect(HttpMethod.Post, "http://localhost/api/transaction") .WithHeaders("X-Forwarded-For", "localhost") .With(matcher => matcher.Headers.UserAgent.ToString().Contains("SignhostClientLibrary")) - .Respond(HttpStatusCode.OK, new StringContent(APIResponses.AddTransaction)); + .Respond(HttpStatusCode.OK, new StringContent(JsonResources.AddTransaction)); using (var httpClient = mockHttp.ToHttpClient()) { settings.AddHeader = (AddHeaders a) => a("X-Forwarded-For", "localhost"); - var signhostApiClient = new SignHostApiClient(settings, httpClient); + var signhostApiClient = new SignhostApiClient(settings, httpClient); Transaction testTransaction = new Transaction(); @@ -295,10 +321,14 @@ public async Task when_CreateTransaction_is_called_with_invalid_email_then_we_sh mockHttp .Expect(HttpMethod.Post, "http://localhost/api/transaction") .WithHeaders("Content-Type", "application/json") - .Respond(HttpStatusCode.BadRequest, new StringContent(" { 'message': 'Bad Request' }")); + .Respond(HttpStatusCode.BadRequest, new StringContent(""" + { + "message": "Bad Request" + } + """)); using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignHostApiClient(settings, httpClient); + var signhostApiClient = new SignhostApiClient(settings, httpClient); Signer testSigner = new Signer(); testSigner.Email = "firstname.lastnamegmail.com"; @@ -319,10 +349,14 @@ public async Task when_a_function_is_called_with_a_wrong_endpoint_we_should_get_ var mockHttp = new MockHttpMessageHandler(); mockHttp .Expect(HttpMethod.Get, "http://localhost/api/transaction/transaction Id") - .Respond(HttpStatusCode.BadGateway, new StringContent(" { 'Message': 'Bad Gateway' }")); + .Respond(HttpStatusCode.BadGateway, new StringContent(""" + { + "message": "Bad Gateway" + } + """)); using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignHostApiClient(settings, httpClient); + var signhostApiClient = new SignhostApiClient(settings, httpClient); Func getTransaction = () => signhostApiClient.GetTransactionAsync("transaction Id"); await getTransaction.Should().ThrowAsync() @@ -338,10 +372,10 @@ public async Task when_a_DeleteTransaction_is_called_then_we_should_have_called_ var mockHttp = new MockHttpMessageHandler(); mockHttp .Expect(HttpMethod.Delete, "http://localhost/api/transaction/transaction Id") - .Respond(HttpStatusCode.OK, new StringContent(APIResponses.DeleteTransaction)); + .Respond(HttpStatusCode.OK, new StringContent(JsonResources.DeleteTransaction)); using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignHostApiClient(settings, httpClient); + var signhostApiClient = new SignhostApiClient(settings, httpClient); await signhostApiClient.DeleteTransactionAsync("transaction Id"); } @@ -357,10 +391,10 @@ public async Task when_a_DeleteTransaction_with_notification_is_called_then_we_s .Expect(HttpMethod.Delete, "http://localhost/api/transaction/transaction Id") .WithHeaders("Content-Type", "application/json") //.With(matcher => matcher.Content.ToString().Contains("'SendNotifications': true")) - .Respond(HttpStatusCode.OK, new StringContent(APIResponses.DeleteTransaction)); + .Respond(HttpStatusCode.OK, new StringContent(JsonResources.DeleteTransaction)); using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignHostApiClient(settings, httpClient); + var signhostApiClient = new SignhostApiClient(settings, httpClient); await signhostApiClient.DeleteTransactionAsync( "transaction Id", @@ -381,7 +415,7 @@ public async Task when_AddOrReplaceFileToTransaction_is_called_then_we_should_ha .Respond(HttpStatusCode.OK); using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignHostApiClient(settings, httpClient); + var signhostApiClient = new SignhostApiClient(settings, httpClient); // Create a 0 sized file using (Stream file = System.IO.File.Create("unittestdocument.pdf")) { @@ -402,7 +436,7 @@ public async Task when_AddOrReplaceFileToTransaction_is_called_default_digest_is .Respond(HttpStatusCode.OK); using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignHostApiClient(settings, httpClient); + var signhostApiClient = new SignhostApiClient(settings, httpClient); await signhostApiClient.AddOrReplaceFileToTransaction(new MemoryStream(), "transaction Id", "file Id"); } @@ -420,7 +454,7 @@ public async Task when_AddOrReplaceFileToTransaction_with_sha512_is_called_defau .Respond(HttpStatusCode.OK); using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignHostApiClient(settings, httpClient); + var signhostApiClient = new SignhostApiClient(settings, httpClient); await signhostApiClient.AddOrReplaceFileToTransactionAsync( new MemoryStream(), @@ -447,7 +481,7 @@ public async Task when_AddOrReplaceFileToTransaction_with_digest_value_is_used_a .Respond(HttpStatusCode.OK); using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignHostApiClient(settings, httpClient); + var signhostApiClient = new SignhostApiClient(settings, httpClient); await signhostApiClient.AddOrReplaceFileToTransactionAsync( new MemoryStream(), @@ -475,7 +509,7 @@ public async Task when_StartTransaction_is_called_then_we_should_have_called_the using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignHostApiClient(settings, httpClient); + var signhostApiClient = new SignhostApiClient(settings, httpClient); await signhostApiClient.StartTransactionAsync("transaction Id"); } @@ -491,7 +525,7 @@ public async Task when_GetReceipt_is_called_then_we_should_have_called_the_filer .Respond(HttpStatusCode.OK); using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignHostApiClient(settings, httpClient); + var signhostApiClient = new SignhostApiClient(settings, httpClient); var receipt = await signhostApiClient.GetReceiptAsync("transaction ID"); } @@ -508,7 +542,7 @@ public async Task when_GetDocument_is_called_then_we_should_have_called_the_file using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignHostApiClient(settings, httpClient); + var signhostApiClient = new SignhostApiClient(settings, httpClient); var document = await signhostApiClient.GetDocumentAsync("transaction Id", "file Id"); } @@ -521,11 +555,11 @@ public async Task When_a_transaction_json_is_returned_it_is_deserialized_correct { var mockHttp = new MockHttpMessageHandler(); mockHttp.Expect(HttpMethod.Post, "http://localhost/api/transaction") - .Respond(HttpStatusCode.OK, new StringContent(RequestBodies.TransactionSingleSignerJson)); + .Respond(HttpStatusCode.OK, new StringContent(JsonResources.TransactionSingleSignerJson)); using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignHostApiClient(settings, httpClient); + var signhostApiClient = new SignhostApiClient(settings, httpClient); var result = await signhostApiClient.CreateTransactionAsync(new Transaction { @@ -544,7 +578,7 @@ public async Task When_a_transaction_json_is_returned_it_is_deserialized_correct }); result.Id.Should().Be("50262c3f-9744-45bf-a4c6-8a3whatever"); - result.CancelledDateTime.Should().HaveYear(2017); + result.CanceledDateTime.Should().HaveYear(2017); result.Status.Should().Be(TransactionStatus.WaitingForDocument); result.Signers.Should().HaveCount(1); result.Receivers.Should().HaveCount(0); @@ -589,9 +623,9 @@ MockedRequest AddHeaders(MockedRequest request) var mockHttp = new MockHttpMessageHandler(); AddHeaders(mockHttp.Expect(HttpMethod.Post, "http://localhost/api/transaction")) - .Respond(new StringContent(RequestBodies.TransactionSingleSignerJson)); + .Respond(new StringContent(JsonResources.TransactionSingleSignerJson)); AddHeaders(mockHttp.Expect(HttpMethod.Put, "http://localhost/api/transaction/*/file/somefileid")) - .Respond(HttpStatusCode.Accepted, new StringContent(RequestBodies.AddOrReplaceFileMetaToTransaction)); + .Respond(HttpStatusCode.Accepted, new StringContent(JsonResources.AddOrReplaceFileMetaToTransaction)); AddHeaders(mockHttp.Expect(HttpMethod.Put, "http://localhost/api/transaction/*/file/somefileid")) .Respond(HttpStatusCode.Created); AddHeaders(mockHttp.Expect(HttpMethod.Put, "http://localhost/api/transaction/*/start")) @@ -600,7 +634,7 @@ MockedRequest AddHeaders(MockedRequest request) using (var httpClient = mockHttp.ToHttpClient()) { var clientSettings = isOauth ? oauthSettings : settings; clientSettings.AddHeader = add => add("X-Custom", "test"); - var signhostApiClient = new SignHostApiClient(clientSettings, httpClient); + var signhostApiClient = new SignhostApiClient(clientSettings, httpClient); var result = await signhostApiClient.CreateTransactionAsync(new Transaction()); await signhostApiClient.AddOrReplaceFileMetaToTransactionAsync(new FileMeta(), result.Id, "somefileid"); @@ -614,43 +648,17 @@ MockedRequest AddHeaders(MockedRequest request) mockHttp.VerifyNoOutstandingRequest(); } - [Fact] - public async Task When_a_custom_verificationtype_is_provided_it_is_deserialized_correctly() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "http://localhost/api/transaction/c487be92-0255-40c7-bd7d-20805a65e7d9") - .Respond(new StringContent(APIResponses.GetTransactionCustomVerificationType)); - - SignHostApiClient.RegisterVerification(); - - using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignHostApiClient(settings, httpClient); - - var result = await signhostApiClient.GetTransactionAsync("c487be92-0255-40c7-bd7d-20805a65e7d9"); - - result.Signers[0].Verifications.Should().HaveCount(3); - result.Signers[0].Verifications[0].Should().BeOfType(); - result.Signers[0].Verifications[1].Should().BeOfType() - .Which.IPAddress.Should().Be("127.0.0.33"); - result.Signers[0].Verifications[2].Should().BeOfType() - .Which.Number.Should().Be("123"); - } - } - [Fact] public async Task When_a_minimal_response_is_retrieved_list_and_dictionaries_are_not_null() { var mockHttp = new MockHttpMessageHandler(); mockHttp .Expect(HttpMethod.Get, "http://localhost/api/transaction/c487be92-0255-40c7-bd7d-20805a65e7d9") - .Respond(new StringContent(APIResponses.MinimalTransactionResponse)); - - SignHostApiClient.RegisterVerification(); + .Respond(new StringContent(JsonResources.MinimalTransactionResponse)); using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignHostApiClient(settings, httpClient); + var signhostApiClient = new SignhostApiClient(settings, httpClient); var result = await signhostApiClient.GetTransactionAsync("c487be92-0255-40c7-bd7d-20805a65e7d9"); @@ -659,11 +667,5 @@ public async Task When_a_minimal_response_is_retrieved_list_and_dictionaries_are result.Files.Should().BeEmpty(); } } - - public class CustomVerification - : IVerification - { - public string Type => "CustomVerificationType"; - } } } diff --git a/src/SignhostAPIClient.Tests/SignhostApiReceiverTests.cs b/src/SignhostAPIClient.Tests/SignhostApiReceiverTests.cs index 79099cc4..ba6dd32a 100644 --- a/src/SignhostAPIClient.Tests/SignhostApiReceiverTests.cs +++ b/src/SignhostAPIClient.Tests/SignhostApiReceiverTests.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using RichardSzalay.MockHttp; using System.Net; +using SignhostAPIClient.Tests.JSON; namespace Signhost.APIClient.Rest.Tests { @@ -20,7 +21,7 @@ public void when_IsPostbackChecksumValid_is_called_with_valid_postback_in_body_t { // Arrange IDictionary headers = new Dictionary { { "Content-Type", new[] { "application/json" } } }; - string body = RequestBodies.MockPostbackValid; + string body = JsonResources.MockPostbackValid; // Act SignhostApiReceiver signhostApiReceiver = new SignhostApiReceiver(receiverSettings); @@ -35,7 +36,7 @@ public void when_IsPostbackChecksumValid_is_called_with_invalid_postback_in_body { // Arrange IDictionary headers = new Dictionary { { "Content-Type", new[] { "application/json" } } }; - string body = RequestBodies.MockPostbackInvalid; + string body = JsonResources.MockPostbackInvalid; // Act SignhostApiReceiver signhostApiReceiver = new SignhostApiReceiver(receiverSettings); @@ -53,7 +54,7 @@ public void when_IsPostbackChecksumValid_is_called_with_valid_postback_in_header { "Content-Type", new[] { "application/json" }}, {"Checksum", new[] {"cdc09eee2ed6df2846dcc193aedfef59f2834f8d"}} }; - string body = RequestBodies.MockPostbackValid; + string body = JsonResources.MockPostbackValid; // Act SignhostApiReceiver signhostApiReceiver = new SignhostApiReceiver(receiverSettings); @@ -71,7 +72,7 @@ public void when_IsPostbackChecksumValid_is_called_with_invalid_postback_in_head { "Content-Type", new[] { "application/json" }}, {"Checksum", new[] {"70dda90616f744797972c0d2f787f86643a60c83"}} }; - string body = RequestBodies.MockPostbackValid; + string body = JsonResources.MockPostbackValid; // Act SignhostApiReceiver signhostApiReceiver = new SignhostApiReceiver(receiverSettings); diff --git a/src/SignhostAPIClient.Tests/app.config b/src/SignhostAPIClient.Tests/app.config deleted file mode 100644 index de5386a4..00000000 --- a/src/SignhostAPIClient.Tests/app.config +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/src/SignhostAPIClient/Rest/DataObjects/ConsentVerification.cs b/src/SignhostAPIClient/Rest/DataObjects/ConsentVerification.cs index 18c1cfd0..ec51d087 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/ConsentVerification.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/ConsentVerification.cs @@ -10,9 +10,5 @@ namespace Signhost.APIClient.Rest.DataObjects public class ConsentVerification : IVerification { - /// - /// Gets the . - /// - public string Type { get; } = "Consent"; } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/DigidVerification.cs b/src/SignhostAPIClient/Rest/DataObjects/DigidVerification.cs index b4034816..3de0acfc 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/DigidVerification.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/DigidVerification.cs @@ -3,8 +3,6 @@ public class DigidVerification : IVerification { - public string Type => "DigiD"; - public string Bsn { get; set; } } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/EidasLoginVerification.cs b/src/SignhostAPIClient/Rest/DataObjects/EidasLoginVerification.cs index 72deeac5..18ac4afa 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/EidasLoginVerification.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/EidasLoginVerification.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Text.Json.Serialization; +using Signhost.APIClient.Rest.JsonConverters; namespace Signhost.APIClient.Rest.DataObjects { @@ -9,11 +11,6 @@ namespace Signhost.APIClient.Rest.DataObjects public class EidasLoginVerification : IVerification { - /// - /// Gets the . - /// - public string Type { get; } = "eIDAS Login"; - /// /// Gets or sets the uid. /// @@ -22,6 +19,7 @@ public class EidasLoginVerification /// /// Gets or sets the level. /// + [JsonConverter(typeof(LevelEnumConverter))] public Level? Level { get; set; } /// diff --git a/src/SignhostAPIClient/Rest/DataObjects/FileMeta.cs b/src/SignhostAPIClient/Rest/DataObjects/FileMeta.cs index 4c0f2eba..6cbda5a0 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/FileMeta.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/FileMeta.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Signhost.APIClient.Rest.DataObjects { @@ -21,7 +21,7 @@ public class FileMeta /// Don't use this setting unless you are really sure this is what you /// want and know the side-effects. /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public bool? SetParaph { get; set; } } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/IPAddressVerification.cs b/src/SignhostAPIClient/Rest/DataObjects/IPAddressVerification.cs index ea2f0eb8..5e789549 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/IPAddressVerification.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/IPAddressVerification.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Text; -using Newtonsoft.Json; namespace Signhost.APIClient.Rest.DataObjects { @@ -11,20 +10,6 @@ namespace Signhost.APIClient.Rest.DataObjects public class IPAddressVerification : IVerification { - /// - /// Initializes a new instance of the class. - /// Do not use! - /// - [Obsolete("This constructor is for internal usage only!")] - public IPAddressVerification() - { - } - - /// - /// Gets the . - /// - public string Type { get; } = "IPAddress"; - /// /// Gets or sets the IP Address used by the signer while signing the documents. /// diff --git a/src/SignhostAPIClient/Rest/DataObjects/IVerification.cs b/src/SignhostAPIClient/Rest/DataObjects/IVerification.cs index fe76ce2c..a2712718 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/IVerification.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/IVerification.cs @@ -1,11 +1,21 @@ -using Newtonsoft.Json; -using Signhost.APIClient.Rest.JsonConverters; +using System.Text.Json.Serialization; namespace Signhost.APIClient.Rest.DataObjects { - [JsonConverter(typeof(JsonVerificationConverter))] + [JsonPolymorphic(TypeDiscriminatorPropertyName = "Type")] + [JsonDerivedType(typeof(ConsentVerification), "Consent")] + [JsonDerivedType(typeof(DigidVerification), "DigiD")] + [JsonDerivedType(typeof(EidasLoginVerification), "eIDAS Login")] + [JsonDerivedType(typeof(IdealVerification), "iDeal")] + [JsonDerivedType(typeof(IdinVerification), "iDIN")] + [JsonDerivedType(typeof(IPAddressVerification), "IPAddress")] + [JsonDerivedType(typeof(ItsmeIdentificationVerification), "itsme Identification")] + [JsonDerivedType(typeof(ItsmeSignVerification), "itsme sign")] + [JsonDerivedType(typeof(PhoneNumberVerification), "PhoneNumber")] + [JsonDerivedType(typeof(ScribbleVerification), "Scribble")] + [JsonDerivedType(typeof(SigningCertificateVerification), "SigningCertificate")] + [JsonDerivedType(typeof(SurfnetVerification), "SURFnet")] public interface IVerification { - string Type { get; } } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/IdealVerification.cs b/src/SignhostAPIClient/Rest/DataObjects/IdealVerification.cs index 459e159b..5267f284 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/IdealVerification.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/IdealVerification.cs @@ -3,8 +3,6 @@ public class IdealVerification : IVerification { - public string Type => "iDeal"; - public string Iban { get; set; } public string AccountHolderName { get; set; } diff --git a/src/SignhostAPIClient/Rest/DataObjects/IdinVerification.cs b/src/SignhostAPIClient/Rest/DataObjects/IdinVerification.cs index 684438c6..38adcd92 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/IdinVerification.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/IdinVerification.cs @@ -6,8 +6,6 @@ namespace Signhost.APIClient.Rest.DataObjects public class IdinVerification : IVerification { - public string Type { get; } = "iDIN"; - public string AccountHolderName { get; set; } public string AccountHolderAddress1 { get; set; } diff --git a/src/SignhostAPIClient/Rest/DataObjects/ItsmeIdentificationVerification.cs b/src/SignhostAPIClient/Rest/DataObjects/ItsmeIdentificationVerification.cs index c2c069e6..eeae90b8 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/ItsmeIdentificationVerification.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/ItsmeIdentificationVerification.cs @@ -6,11 +6,6 @@ namespace Signhost.APIClient.Rest.DataObjects public class ItsmeIdentificationVerification : IVerification { - /// - /// Gets the . - /// - public string Type => "itsme Identification"; - /// /// Gets or sets the phonenumber. /// diff --git a/src/SignhostAPIClient/Rest/DataObjects/ItsmeSignVerification.cs b/src/SignhostAPIClient/Rest/DataObjects/ItsmeSignVerification.cs index 20699888..5f988c20 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/ItsmeSignVerification.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/ItsmeSignVerification.cs @@ -6,9 +6,5 @@ namespace Signhost.APIClient.Rest.DataObjects public class ItsmeSignVerification : IVerification { - /// - /// Gets the . - /// - public string Type => "itsme sign"; } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/KennisnetVerification.cs b/src/SignhostAPIClient/Rest/DataObjects/KennisnetVerification.cs deleted file mode 100644 index 72546591..00000000 --- a/src/SignhostAPIClient/Rest/DataObjects/KennisnetVerification.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace Signhost.APIClient.Rest.DataObjects -{ - [Obsolete("This verification is no longer supported and will be removed in SemVer 4.")] - public class KennisnetVerification - : IVerification - { - public string Type => "Kennisnet"; - } -} diff --git a/src/SignhostAPIClient/Rest/DataObjects/Level.cs b/src/SignhostAPIClient/Rest/DataObjects/Level.cs index 40b016c1..93f223b1 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/Level.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/Level.cs @@ -1,12 +1,8 @@ -using Newtonsoft.Json; -using Signhost.APIClient.Rest.JsonConverters; - namespace Signhost.APIClient.Rest.DataObjects { /// /// Level of Assurance. /// - [JsonConverter(typeof(LevelEnumConverter))] public enum Level { /// diff --git a/src/SignhostAPIClient/Rest/DataObjects/PhoneNumberVerification.cs b/src/SignhostAPIClient/Rest/DataObjects/PhoneNumberVerification.cs index 8503fbfb..fad44c4a 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/PhoneNumberVerification.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/PhoneNumberVerification.cs @@ -3,8 +3,6 @@ public class PhoneNumberVerification : IVerification { - public string Type => "PhoneNumber"; - public string Number { get; set; } } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/PostbackTransaction.cs b/src/SignhostAPIClient/Rest/DataObjects/PostbackTransaction.cs index 4c5db856..76a2726e 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/PostbackTransaction.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/PostbackTransaction.cs @@ -1,27 +1,13 @@ using System; using System.Collections.Generic; -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Signhost.APIClient.Rest.DataObjects { public class PostbackTransaction : Transaction { - public PostbackTransaction() - { - } - - [JsonConstructor] - private PostbackTransaction( - IReadOnlyDictionary files, - DateTimeOffset? createdDateTime, - DateTimeOffset? canceledDateTime, - string cancelationReason) - : base(files, createdDateTime, canceledDateTime, cancelationReason) - { - } - - [JsonProperty("Checksum")] + [JsonPropertyName("Checksum")] public string Checksum { get; set; } } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/Receiver.cs b/src/SignhostAPIClient/Rest/DataObjects/Receiver.cs index 8fc286e2..5afaeb1c 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/Receiver.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/Receiver.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Signhost.APIClient.Rest.DataObjects { diff --git a/src/SignhostAPIClient/Rest/DataObjects/ScribbleVerification.cs b/src/SignhostAPIClient/Rest/DataObjects/ScribbleVerification.cs index 64f18a75..fadb57af 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/ScribbleVerification.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/ScribbleVerification.cs @@ -3,8 +3,6 @@ public class ScribbleVerification : IVerification { - public string Type => "Scribble"; - public bool RequireHandsignature { get; set; } public bool ScribbleNameFixed { get; set; } diff --git a/src/SignhostAPIClient/Rest/DataObjects/Signer.cs b/src/SignhostAPIClient/Rest/DataObjects/Signer.cs index 77cada56..e1d7f660 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/Signer.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/Signer.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Signhost.APIClient.Rest.DataObjects { diff --git a/src/SignhostAPIClient/Rest/DataObjects/SigningCertificateVerification.cs b/src/SignhostAPIClient/Rest/DataObjects/SigningCertificateVerification.cs index 98673fd3..b6f9735f 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/SigningCertificateVerification.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/SigningCertificateVerification.cs @@ -7,7 +7,5 @@ namespace Signhost.APIClient.Rest.DataObjects public class SigningCertificateVerification : IVerification { - /// - public string Type => "SigningCertificate"; } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/SurfnetVerification.cs b/src/SignhostAPIClient/Rest/DataObjects/SurfnetVerification.cs index 466551c8..7700edc8 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/SurfnetVerification.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/SurfnetVerification.cs @@ -1,8 +1,9 @@ -namespace Signhost.APIClient.Rest.DataObjects +using System.Text.Json.Serialization; + +namespace Signhost.APIClient.Rest.DataObjects { public class SurfnetVerification : IVerification { - public string Type => "SURFnet"; } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/Transaction.cs b/src/SignhostAPIClient/Rest/DataObjects/Transaction.cs index 534d31e6..35dbb133 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/Transaction.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/Transaction.cs @@ -1,55 +1,41 @@ using System; using System.Collections.Generic; -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Signhost.APIClient.Rest.DataObjects { public class Transaction { - public Transaction() - { - } - - [JsonConstructor] - protected Transaction( - IReadOnlyDictionary files, - DateTimeOffset? createdDateTime, - DateTimeOffset? canceledDateTime, - string cancelationReason) - { - Files = files ?? new Dictionary(); - CreatedDateTime = createdDateTime; - CancelledDateTime = canceledDateTime; - CancellationReason = cancelationReason; - } - public string Id { get; set; } /// /// Gets the when the was created. /// - public DateTimeOffset? CreatedDateTime { get; } + public DateTimeOffset? CreatedDateTime { get; set; } /// /// Gets the when the was cancelled. /// Returns null if the transaction was not cancelled. /// - public DateTimeOffset? CancelledDateTime { get; } + public DateTimeOffset? CanceledDateTime { get; set; } /// /// Gets the cancellation reason when the was cancelled. /// - public string CancellationReason { get; } + public string CancellationReason { get; set; } - public IReadOnlyDictionary Files { get; private set; } + public IReadOnlyDictionary Files { get; set; } = + new Dictionary(); public TransactionStatus Status { get; set; } public bool Seal { get; set; } - public IList Signers { get; set; } = new List(); + public IList Signers { get; set; } + = new List(); - public IList Receivers { get; set; } = new List(); + public IList Receivers { get; set; } + = new List(); public string Reference { get; set; } diff --git a/src/SignhostAPIClient/Rest/DataObjects/UnknownVerification.cs b/src/SignhostAPIClient/Rest/DataObjects/UnknownVerification.cs deleted file mode 100644 index 69c17ba3..00000000 --- a/src/SignhostAPIClient/Rest/DataObjects/UnknownVerification.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Signhost.APIClient.Rest.DataObjects -{ - public class UnknownVerification - : IVerification - { - public string Type { get; set; } - } -} diff --git a/src/SignhostAPIClient/Rest/ErrorHandling/HttpResponseMessageErrorHandlingExtensions.cs b/src/SignhostAPIClient/Rest/ErrorHandling/HttpResponseMessageErrorHandlingExtensions.cs index 745b17c9..1d5bcb4d 100644 --- a/src/SignhostAPIClient/Rest/ErrorHandling/HttpResponseMessageErrorHandlingExtensions.cs +++ b/src/SignhostAPIClient/Rest/ErrorHandling/HttpResponseMessageErrorHandlingExtensions.cs @@ -2,8 +2,9 @@ using System.Linq; using System.Net; using System.Net.Http; +using System.Text.Json; +using System.Text.Json.Serialization; using System.Threading.Tasks; -using Newtonsoft.Json; namespace Signhost.APIClient.Rest.ErrorHandling { @@ -60,15 +61,10 @@ public static async Task EnsureSignhostSuccessStatusCodeAsy string responsejson = await response.Content.ReadAsStringAsync() .ConfigureAwait(false); - var error = JsonConvert.DeserializeAnonymousType( - responsejson, - new { - Type = string.Empty, - Message = string.Empty, - }); + var error = JsonSerializer.Deserialize(responsejson); - errorType = error.Type; - errorMessage = error.Message; + errorType = error?.Type ?? string.Empty; + errorMessage = error?.Message ?? "Unknown Signhost error"; } switch (response.StatusCode) { @@ -96,8 +92,15 @@ public static async Task EnsureSignhostSuccessStatusCodeAsy throw new SignhostRestApiClientException( errorMessage); } + } + + private class ErrorResponse + { + [JsonPropertyName("type")] + public string Type { get; set; } - System.Diagnostics.Debug.Fail("Should not be reached"); + [JsonPropertyName("message")] + public string Message { get; set; } } } } diff --git a/src/SignhostAPIClient/Rest/HttpContentJsonExtensions.cs b/src/SignhostAPIClient/Rest/HttpContentJsonExtensions.cs index e205e41a..b7e2836e 100644 --- a/src/SignhostAPIClient/Rest/HttpContentJsonExtensions.cs +++ b/src/SignhostAPIClient/Rest/HttpContentJsonExtensions.cs @@ -1,6 +1,6 @@ using System.Net.Http; +using System.Text.Json; using System.Threading.Tasks; -using Newtonsoft.Json; namespace Signhost.APIClient.Rest { @@ -25,7 +25,7 @@ internal static async Task FromJsonAsync( var json = await httpContent.ReadAsStringAsync() .ConfigureAwait(false); - return JsonConvert.DeserializeObject(json); + return JsonSerializer.Deserialize(json, SignhostJsonSerializerOptions.Default); } } } diff --git a/src/SignhostAPIClient/Rest/ISignHostApiClient.cs b/src/SignhostAPIClient/Rest/ISignHostApiClient.cs index f4546fd8..79c5a885 100644 --- a/src/SignhostAPIClient/Rest/ISignHostApiClient.cs +++ b/src/SignhostAPIClient/Rest/ISignHostApiClient.cs @@ -8,7 +8,7 @@ namespace Signhost.APIClient.Rest /// /// Interface abstracting the available Signhost API calls. /// - public interface ISignHostApiClient + public interface ISignhostApiClient { /// /// Creates a new transaction. diff --git a/src/SignhostAPIClient/Rest/ISignhostApiClientSettings.cs b/src/SignhostAPIClient/Rest/ISignhostApiClientSettings.cs index 439dc127..34c7c920 100644 --- a/src/SignhostAPIClient/Rest/ISignhostApiClientSettings.cs +++ b/src/SignhostAPIClient/Rest/ISignhostApiClientSettings.cs @@ -4,7 +4,7 @@ namespace Signhost.APIClient.Rest { public delegate void AddHeaders(string name, string value); - public interface ISignHostApiClientSettings + public interface ISignhostApiClientSettings { /// /// Gets the usertoken identifying an authorized user. diff --git a/src/SignhostAPIClient/Rest/JsonContent.cs b/src/SignhostAPIClient/Rest/JsonContent.cs index 54e72b4c..295054aa 100644 --- a/src/SignhostAPIClient/Rest/JsonContent.cs +++ b/src/SignhostAPIClient/Rest/JsonContent.cs @@ -1,6 +1,6 @@ using System.Net.Http; using System.Net.Http.Headers; -using Newtonsoft.Json; +using System.Text.Json; namespace Signhost.APIClient.Rest { @@ -40,7 +40,7 @@ public JsonContent(T value) private static string ToJson(T value) { - return JsonConvert.SerializeObject(value); + return JsonSerializer.Serialize(value, SignhostJsonSerializerOptions.Default); } } } diff --git a/src/SignhostAPIClient/Rest/JsonConverters/JsonBaseConverter.cs b/src/SignhostAPIClient/Rest/JsonConverters/JsonBaseConverter.cs deleted file mode 100644 index ff5642bd..00000000 --- a/src/SignhostAPIClient/Rest/JsonConverters/JsonBaseConverter.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Reflection; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace Signhost.APIClient.Rest.JsonConverters -{ - public abstract class JsonBaseConverter - : JsonConverter - { - public override bool CanConvert(Type objectType) - => typeof(T) -#if TYPEINFO - .GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo()); -#else - .IsAssignableFrom(objectType); -#endif - - public override object ReadJson( - JsonReader reader, - Type objectType, - object existingValue, - JsonSerializer serializer) - { - var jsonObject = JObject.Load(reader); - var target = Create(objectType, jsonObject); - serializer.Populate(jsonObject.CreateReader(), target); - return target; - } - - protected abstract T Create(Type objectType, JObject jsonObject); - } -} diff --git a/src/SignhostAPIClient/Rest/JsonConverters/JsonVerificationConverter.cs b/src/SignhostAPIClient/Rest/JsonConverters/JsonVerificationConverter.cs deleted file mode 100644 index 4e1f9fa6..00000000 --- a/src/SignhostAPIClient/Rest/JsonConverters/JsonVerificationConverter.cs +++ /dev/null @@ -1,93 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using Signhost.APIClient.Rest.DataObjects; - -namespace Signhost.APIClient.Rest.JsonConverters -{ - internal class JsonVerificationConverter - : JsonBaseConverter - { -#if TYPEINFO - private static readonly IDictionary VerificationTypes = -#else - private static readonly IDictionary VerificationTypes = -#endif - CreateVerificationTypeMap(); - - public override bool CanWrite - => false; - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - => new NotImplementedException(); - - /// - /// Adds an additional verification type to the - /// map. - /// - /// - internal static void RegisterVerification() - where T : IVerification - { - var verification = (IVerification)Activator.CreateInstance(typeof(T)); - - VerificationTypes[verification.Type] = -#if TYPEINFO - typeof(T).GetTypeInfo(); -#else - typeof(T); -#endif - } - - protected override IVerification Create( - Type objectType, - JObject jsonObject) - { - var typeName = jsonObject["Type"]?.ToString(); - - if (VerificationTypes.TryGetValue(typeName, out var verificationType)) { -#if TYPEINFO - return (IVerification)Activator.CreateInstance(verificationType.AsType()); -#else - return (IVerification)Activator.CreateInstance(verificationType); -#endif - } - - return new UnknownVerification(); - } - -#if TYPEINFO - private static Dictionary CreateVerificationTypeMap() - { - return typeof(JsonVerificationConverter).GetTypeInfo().Assembly.ExportedTypes - .Select(t => t.GetTypeInfo()) - .Where(t => typeof(IVerification).GetTypeInfo().IsAssignableFrom(t)) - .Where(t => !t.IsInterface && !t.IsAbstract) -#pragma warning disable SA1008 // Opening parenthesis must be spaced correctly - .Select(t => ( - typeInfo: t, - instance: (IVerification)Activator.CreateInstance(t.AsType()))) -#pragma warning restore SA1008 // Opening parenthesis must be spaced correctly - .Where(t => t.instance.Type != null) - .ToDictionary(t => t.instance.Type, t => t.typeInfo); - } -#else - private static Dictionary CreateVerificationTypeMap() - { - return typeof(JsonVerificationConverter).Assembly.ExportedTypes - .Where(t => typeof(IVerification).IsAssignableFrom(t)) - .Where(t => !t.IsInterface && !t.IsAbstract) -#pragma warning disable SA1008 // Opening parenthesis must be spaced correctly - .Select(t => ( - type: t, - instance: (IVerification)Activator.CreateInstance(t))) -#pragma warning restore SA1008 // Opening parenthesis must be spaced correctly - .Where(t => t.instance.Type is not null) - .ToDictionary(t => t.instance.Type, t => t.type); - } -#endif - } -} diff --git a/src/SignhostAPIClient/Rest/JsonConverters/LevelEnumConverter.cs b/src/SignhostAPIClient/Rest/JsonConverters/LevelEnumConverter.cs index e0e5aeed..07c20313 100644 --- a/src/SignhostAPIClient/Rest/JsonConverters/LevelEnumConverter.cs +++ b/src/SignhostAPIClient/Rest/JsonConverters/LevelEnumConverter.cs @@ -1,69 +1,56 @@ using System; -using System.Reflection; -using Newtonsoft.Json; +using System.Text.Json; +using System.Text.Json.Serialization; using Signhost.APIClient.Rest.DataObjects; namespace Signhost.APIClient.Rest.JsonConverters { /// - /// JSON converter for converting the enum. + /// JSON converter factory for converting the enum. /// Invalid values are mapped to . /// internal class LevelEnumConverter - : JsonConverter + : JsonConverter { - /// - public override bool CanWrite => false; - - /// - public override bool CanConvert(Type objectType) - => IsLevelEnum(GetUnderlyingType(objectType)); - - /// - public override object ReadJson( - JsonReader reader, - Type objectType, - object existingValue, - JsonSerializer serializer) + public override Level? Read( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options) { - var value = reader.Value as string; + if (reader.TokenType == JsonTokenType.Null) { + return null; + } - if (value != null) { - if (Enum.TryParse(value, out Level level)) { + if (reader.TokenType == JsonTokenType.String) { + var value = reader.GetString() ?? string.Empty; + if (Enum.TryParse(value, out var level)) { return level; } return Level.Unknown; } - return null; - } - - /// - public override void WriteJson( - JsonWriter writer, - object value, - JsonSerializer serializer) - => throw new NotImplementedException(); + if (reader.TokenType == JsonTokenType.Number) { + int value = reader.GetInt32(); + if (Enum.IsDefined(typeof(Level), value)) { + return (Level)value; + } + } - private static Type GetUnderlyingType(Type type) - => -#if TYPEINFO - type.GetTypeInfo().IsGenericType && -#else - type.IsGenericType && -#endif - type.GetGenericTypeDefinition() == typeof(Nullable<>) - ? Nullable.GetUnderlyingType(type) - : type; + return Level.Unknown; + } - private static bool IsLevelEnum(Type type) - => -#if TYPEINFO - type.GetTypeInfo().IsEnum && -#else - type.IsEnum && -#endif - type == typeof(Level); + public override void Write( + Utf8JsonWriter writer, + Level? value, + JsonSerializerOptions options) + { + if (value is null) { + writer.WriteNullValue(); + } + else { + writer.WriteStringValue(value.ToString()); + } + } } } diff --git a/src/SignhostAPIClient/Rest/SignHostApiClient.cs b/src/SignhostAPIClient/Rest/SignHostApiClient.cs index dd2e3a89..780aa1ba 100644 --- a/src/SignhostAPIClient/Rest/SignHostApiClient.cs +++ b/src/SignhostAPIClient/Rest/SignHostApiClient.cs @@ -12,43 +12,43 @@ namespace Signhost.APIClient.Rest { /// - /// Implements the interface which provides + /// Implements the interface which provides /// an signhost api client implementation. /// - public class SignHostApiClient - : ISignHostApiClient + public class SignhostApiClient + : ISignhostApiClient , IDisposable { private const string ApiVersion = "v1"; - private static readonly string Version = typeof(SignHostApiClient) + private static readonly string Version = typeof(SignhostApiClient) #if TYPEINFO .GetTypeInfo() #endif .Assembly.GetCustomAttribute() .Version; - private readonly ISignHostApiClientSettings settings; + private readonly ISignhostApiClientSettings settings; private readonly HttpClient client; /// - /// Initializes a new instance of the class. - /// Set your usertoken and APPKey by creating a . + /// Initializes a new instance of the class. + /// Set your usertoken and APPKey by creating a . /// - /// - public SignHostApiClient(ISignHostApiClientSettings settings) + /// + public SignhostApiClient(ISignhostApiClientSettings settings) : this(settings, new HttpClient()) { } /// - /// Initializes a new instance of the class. - /// Set your usertoken and APPKey by creating a . + /// Initializes a new instance of the class. + /// Set your usertoken and APPKey by creating a . /// - /// + /// /// to use for all http calls. - public SignHostApiClient( - ISignHostApiClientSettings settings, + public SignhostApiClient( + ISignhostApiClientSettings settings, HttpClient httpClient) { this.settings = settings; @@ -75,16 +75,6 @@ private string ApplicationHeader private string AuthorizationHeader => $"APIKey {settings.UserToken}"; - /// - /// Globally register an additional verification type. - /// - /// to - public static void RegisterVerification() - where T : IVerification - { - JsonConverters.JsonVerificationConverter.RegisterVerification(); - } - /// public async Task CreateTransactionAsync( Transaction transaction) diff --git a/src/SignhostAPIClient/Rest/SignHostApiClientSettings.cs b/src/SignhostAPIClient/Rest/SignHostApiClientSettings.cs index f93a6c9b..b4afed65 100644 --- a/src/SignhostAPIClient/Rest/SignHostApiClientSettings.cs +++ b/src/SignhostAPIClient/Rest/SignHostApiClientSettings.cs @@ -2,18 +2,18 @@ namespace Signhost.APIClient.Rest { - public class SignHostApiClientSettings - : ISignHostApiClientSettings + public class SignhostApiClientSettings + : ISignhostApiClientSettings { public const string DefaultEndpoint = "https://api.signhost.com/api/"; - public SignHostApiClientSettings(string appkey, string userToken) + public SignhostApiClientSettings(string appkey, string userToken) { APPKey = appkey; UserToken = userToken; } - public SignHostApiClientSettings(string appkey) + public SignhostApiClientSettings(string appkey) { APPKey = appkey; } diff --git a/src/SignhostAPIClient/Rest/SignhostApiReceiver.cs b/src/SignhostAPIClient/Rest/SignhostApiReceiver.cs index a3bfde6a..bdffe930 100644 --- a/src/SignhostAPIClient/Rest/SignhostApiReceiver.cs +++ b/src/SignhostAPIClient/Rest/SignhostApiReceiver.cs @@ -3,7 +3,7 @@ using System.Linq; using System.Security.Cryptography; using System.Text; -using Newtonsoft.Json; +using System.Text.Json; using Signhost.APIClient.Rest; using Signhost.APIClient.Rest.DataObjects; @@ -64,12 +64,10 @@ private string CalculateChecksumFromPostback(PostbackTransaction postback) } } - private PostbackTransaction DeserializeToPostbackTransaction(string body) - { - return JsonConvert.DeserializeObject(body); - } - - private string GetChecksumFromHeadersOrPostback( + private PostbackTransaction DeserializeToPostbackTransaction(string body) + { + return JsonSerializer.Deserialize(body, SignhostJsonSerializerOptions.Default); + } private string GetChecksumFromHeadersOrPostback( IDictionary headers, PostbackTransaction postback) { diff --git a/src/SignhostAPIClient/Rest/SignhostJsonSerializerOptions.cs b/src/SignhostAPIClient/Rest/SignhostJsonSerializerOptions.cs new file mode 100644 index 00000000..37845021 --- /dev/null +++ b/src/SignhostAPIClient/Rest/SignhostJsonSerializerOptions.cs @@ -0,0 +1,23 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Signhost.APIClient.Rest +{ + /// + /// Centralized JSON serialization options for Signhost API. + /// + public static class SignhostJsonSerializerOptions + { + /// + /// Gets the default JSON serializer options. + /// + public static JsonSerializerOptions Default { get; } = new JsonSerializerOptions + { + PropertyNameCaseInsensitive = true, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + Converters = { + new JsonStringEnumConverter(), + }, + }; + } +} diff --git a/src/SignhostAPIClient/SignhostAPIClient.csproj b/src/SignhostAPIClient/SignhostAPIClient.csproj index 8c6a83a0..7309d334 100644 --- a/src/SignhostAPIClient/SignhostAPIClient.csproj +++ b/src/SignhostAPIClient/SignhostAPIClient.csproj @@ -42,7 +42,7 @@ - + From ff56ee3b6bac0f1dc8bb52e7b33fd972e1eaba69 Mon Sep 17 00:00:00 2001 From: Anthony Timmers Date: Fri, 21 Nov 2025 18:55:04 +0100 Subject: [PATCH 3/7] Remove NCrunch --- .gitattributes | 3 -- .gitignore | 5 ---- .../SignhostAPIClient.Tests.v2.ncrunchproject | 26 ----------------- src/SignhostAPIClient.v2.ncrunchsolution | 14 --------- src/SignhostAPIClient.v3.ncrunchsolution | 6 ---- .../SignhostAPIClient.v2.ncrunchproject | 29 ------------------- 6 files changed, 83 deletions(-) delete mode 100644 src/SignhostAPIClient.Tests/SignhostAPIClient.Tests.v2.ncrunchproject delete mode 100644 src/SignhostAPIClient.v2.ncrunchsolution delete mode 100644 src/SignhostAPIClient.v3.ncrunchsolution delete mode 100644 src/SignhostAPIClient/SignhostAPIClient.v2.ncrunchproject diff --git a/.gitattributes b/.gitattributes index 4eb59c0a..48d3a289 100644 --- a/.gitattributes +++ b/.gitattributes @@ -16,9 +16,6 @@ *.edmx text *.resx text -*.ncrunchproject text -*.ncrunchsolution text - # Custom for Visual Studio *.sln text eol=crlf merge=union *.csproj text diff --git a/.gitignore b/.gitignore index 7494d73c..0e70063f 100644 --- a/.gitignore +++ b/.gitignore @@ -104,11 +104,6 @@ _TeamCity* # DotCover is a Code Coverage Tool *.dotCover -# NCrunch -_NCrunch_* -.*crunch*.local.xml -*.v3.ncrunchsolution.user - # MightyMoose *.mm.* AutoTest.Net/ diff --git a/src/SignhostAPIClient.Tests/SignhostAPIClient.Tests.v2.ncrunchproject b/src/SignhostAPIClient.Tests/SignhostAPIClient.Tests.v2.ncrunchproject deleted file mode 100644 index 1f00ab7c..00000000 --- a/src/SignhostAPIClient.Tests/SignhostAPIClient.Tests.v2.ncrunchproject +++ /dev/null @@ -1,26 +0,0 @@ - - true - 1000 - false - false - false - true - false - false - false - false - false - true - true - false - true - true - true - 60000 - - - - AutoDetect - STA - x86 - \ No newline at end of file diff --git a/src/SignhostAPIClient.v2.ncrunchsolution b/src/SignhostAPIClient.v2.ncrunchsolution deleted file mode 100644 index b98737f1..00000000 --- a/src/SignhostAPIClient.v2.ncrunchsolution +++ /dev/null @@ -1,14 +0,0 @@ - - 1 - false - false - true - UseDynamicAnalysis - UseStaticAnalysis - UseStaticAnalysis - UseStaticAnalysis - UseDynamicAnalysis - - - - \ No newline at end of file diff --git a/src/SignhostAPIClient.v3.ncrunchsolution b/src/SignhostAPIClient.v3.ncrunchsolution deleted file mode 100644 index ff7af7e3..00000000 --- a/src/SignhostAPIClient.v3.ncrunchsolution +++ /dev/null @@ -1,6 +0,0 @@ - - - True - True - - diff --git a/src/SignhostAPIClient/SignhostAPIClient.v2.ncrunchproject b/src/SignhostAPIClient/SignhostAPIClient.v2.ncrunchproject deleted file mode 100644 index 3f48b966..00000000 --- a/src/SignhostAPIClient/SignhostAPIClient.v2.ncrunchproject +++ /dev/null @@ -1,29 +0,0 @@ - - true - 1000 - false - false - false - true - false - false - false - false - false - true - true - false - true - true - true - 60000 - - - - AutoDetect - STA - x86 - - - - \ No newline at end of file From a8f7d3218387baceb0e08e45e0db18aa2206a6f1 Mon Sep 17 00:00:00 2001 From: Anthony Timmers Date: Fri, 21 Nov 2025 18:57:58 +0100 Subject: [PATCH 4/7] Remove unused using directives --- src/SignhostAPIClient.Tests/SignhostApiClientTests.cs | 1 - src/SignhostAPIClient.Tests/SignhostApiReceiverTests.cs | 8 +------- src/SignhostAPIClient/Rest/ApiResponse.cs | 5 +---- src/SignhostAPIClient/Rest/DataObjects/ActivityType.cs | 6 +----- .../Rest/DataObjects/ConsentVerification.cs | 6 +----- .../Rest/DataObjects/IPAddressVerification.cs | 4 ---- .../Rest/DataObjects/PostbackTransaction.cs | 2 -- .../Rest/DataObjects/SurfnetVerification.cs | 4 +--- src/SignhostAPIClient/Rest/DataObjects/Transaction.cs | 1 - .../Rest/ErrorHandling/BadAuthorizationException.cs | 5 ----- .../Rest/ErrorHandling/BadRequestException.cs | 1 - .../Rest/ErrorHandling/DefaultSignhostException.cs | 1 - src/SignhostAPIClient/Rest/ErrorHandling/GoneException.cs | 1 - .../Rest/ErrorHandling/InternalServerErrorException.cs | 1 - .../Rest/ErrorHandling/NotFoundException.cs | 1 - .../Rest/ErrorHandling/SignhostException.cs | 1 - .../Rest/ErrorHandling/SignhostRestApiClientException.cs | 1 - src/SignhostAPIClient/Rest/FileDigestOptions.cs | 6 +----- src/SignhostAPIClient/Rest/ISignhostApiReceiver.cs | 3 --- src/SignhostAPIClient/Rest/SignhostApiReceiverSettings.cs | 4 +--- 20 files changed, 7 insertions(+), 55 deletions(-) diff --git a/src/SignhostAPIClient.Tests/SignhostApiClientTests.cs b/src/SignhostAPIClient.Tests/SignhostApiClientTests.cs index 0e5f1e9b..fc3c085a 100644 --- a/src/SignhostAPIClient.Tests/SignhostApiClientTests.cs +++ b/src/SignhostAPIClient.Tests/SignhostApiClientTests.cs @@ -9,7 +9,6 @@ using RichardSzalay.MockHttp; using System.Net; using SignhostAPIClient.Tests.JSON; -using System.Text.Json.Serialization; namespace Signhost.APIClient.Rest.Tests { diff --git a/src/SignhostAPIClient.Tests/SignhostApiReceiverTests.cs b/src/SignhostAPIClient.Tests/SignhostApiReceiverTests.cs index ba6dd32a..198f95bf 100644 --- a/src/SignhostAPIClient.Tests/SignhostApiReceiverTests.cs +++ b/src/SignhostAPIClient.Tests/SignhostApiReceiverTests.cs @@ -1,13 +1,7 @@ -using System; -using System.Threading.Tasks; -using System.Net.Http; -using System.IO; -using Xunit; +using Xunit; using Signhost.APIClient.Rest.DataObjects; using FluentAssertions; using System.Collections.Generic; -using RichardSzalay.MockHttp; -using System.Net; using SignhostAPIClient.Tests.JSON; namespace Signhost.APIClient.Rest.Tests diff --git a/src/SignhostAPIClient/Rest/ApiResponse.cs b/src/SignhostAPIClient/Rest/ApiResponse.cs index f6c6c128..00db9de5 100644 --- a/src/SignhostAPIClient/Rest/ApiResponse.cs +++ b/src/SignhostAPIClient/Rest/ApiResponse.cs @@ -1,8 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Net; +using System.Net; using System.Net.Http; -using System.Text; namespace Signhost.APIClient.Rest { diff --git a/src/SignhostAPIClient/Rest/DataObjects/ActivityType.cs b/src/SignhostAPIClient/Rest/DataObjects/ActivityType.cs index e954356a..2da49276 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/ActivityType.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/ActivityType.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Signhost.APIClient.Rest.DataObjects +namespace Signhost.APIClient.Rest.DataObjects { /// /// type. diff --git a/src/SignhostAPIClient/Rest/DataObjects/ConsentVerification.cs b/src/SignhostAPIClient/Rest/DataObjects/ConsentVerification.cs index ec51d087..00289618 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/ConsentVerification.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/ConsentVerification.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Signhost.APIClient.Rest.DataObjects +namespace Signhost.APIClient.Rest.DataObjects { /// /// Adds a consent verification screen diff --git a/src/SignhostAPIClient/Rest/DataObjects/IPAddressVerification.cs b/src/SignhostAPIClient/Rest/DataObjects/IPAddressVerification.cs index 5e789549..cb68fcda 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/IPAddressVerification.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/IPAddressVerification.cs @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Text; - namespace Signhost.APIClient.Rest.DataObjects { /// diff --git a/src/SignhostAPIClient/Rest/DataObjects/PostbackTransaction.cs b/src/SignhostAPIClient/Rest/DataObjects/PostbackTransaction.cs index 76a2726e..ea57648d 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/PostbackTransaction.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/PostbackTransaction.cs @@ -1,5 +1,3 @@ -using System; -using System.Collections.Generic; using System.Text.Json.Serialization; namespace Signhost.APIClient.Rest.DataObjects diff --git a/src/SignhostAPIClient/Rest/DataObjects/SurfnetVerification.cs b/src/SignhostAPIClient/Rest/DataObjects/SurfnetVerification.cs index 7700edc8..ec1a4abe 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/SurfnetVerification.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/SurfnetVerification.cs @@ -1,6 +1,4 @@ -using System.Text.Json.Serialization; - -namespace Signhost.APIClient.Rest.DataObjects +namespace Signhost.APIClient.Rest.DataObjects { public class SurfnetVerification : IVerification diff --git a/src/SignhostAPIClient/Rest/DataObjects/Transaction.cs b/src/SignhostAPIClient/Rest/DataObjects/Transaction.cs index 35dbb133..66166334 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/Transaction.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/Transaction.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Text.Json.Serialization; namespace Signhost.APIClient.Rest.DataObjects { diff --git a/src/SignhostAPIClient/Rest/ErrorHandling/BadAuthorizationException.cs b/src/SignhostAPIClient/Rest/ErrorHandling/BadAuthorizationException.cs index 04bc32b1..9d78b27d 100644 --- a/src/SignhostAPIClient/Rest/ErrorHandling/BadAuthorizationException.cs +++ b/src/SignhostAPIClient/Rest/ErrorHandling/BadAuthorizationException.cs @@ -1,9 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.Serialization; -using System.Text; -using System.Threading.Tasks; namespace Signhost.APIClient.Rest.ErrorHandling { diff --git a/src/SignhostAPIClient/Rest/ErrorHandling/BadRequestException.cs b/src/SignhostAPIClient/Rest/ErrorHandling/BadRequestException.cs index 8fb0d528..d6041abf 100644 --- a/src/SignhostAPIClient/Rest/ErrorHandling/BadRequestException.cs +++ b/src/SignhostAPIClient/Rest/ErrorHandling/BadRequestException.cs @@ -1,5 +1,4 @@ using System; -using System.Runtime.Serialization; namespace Signhost.APIClient.Rest.ErrorHandling { diff --git a/src/SignhostAPIClient/Rest/ErrorHandling/DefaultSignhostException.cs b/src/SignhostAPIClient/Rest/ErrorHandling/DefaultSignhostException.cs index ca6fb125..8c9a0542 100644 --- a/src/SignhostAPIClient/Rest/ErrorHandling/DefaultSignhostException.cs +++ b/src/SignhostAPIClient/Rest/ErrorHandling/DefaultSignhostException.cs @@ -1,5 +1,4 @@ using System; -using System.Runtime.Serialization; namespace Signhost.APIClient.Rest.ErrorHandling { diff --git a/src/SignhostAPIClient/Rest/ErrorHandling/GoneException.cs b/src/SignhostAPIClient/Rest/ErrorHandling/GoneException.cs index b902fe62..08e8ce8c 100644 --- a/src/SignhostAPIClient/Rest/ErrorHandling/GoneException.cs +++ b/src/SignhostAPIClient/Rest/ErrorHandling/GoneException.cs @@ -1,5 +1,4 @@ using System; -using System.Runtime.Serialization; namespace Signhost.APIClient.Rest.ErrorHandling { diff --git a/src/SignhostAPIClient/Rest/ErrorHandling/InternalServerErrorException.cs b/src/SignhostAPIClient/Rest/ErrorHandling/InternalServerErrorException.cs index 927c49f2..0100e317 100644 --- a/src/SignhostAPIClient/Rest/ErrorHandling/InternalServerErrorException.cs +++ b/src/SignhostAPIClient/Rest/ErrorHandling/InternalServerErrorException.cs @@ -1,6 +1,5 @@ using System; using System.Net.Http.Headers; -using System.Runtime.Serialization; namespace Signhost.APIClient.Rest.ErrorHandling { diff --git a/src/SignhostAPIClient/Rest/ErrorHandling/NotFoundException.cs b/src/SignhostAPIClient/Rest/ErrorHandling/NotFoundException.cs index ff21de45..6c9eda47 100644 --- a/src/SignhostAPIClient/Rest/ErrorHandling/NotFoundException.cs +++ b/src/SignhostAPIClient/Rest/ErrorHandling/NotFoundException.cs @@ -1,5 +1,4 @@ using System; -using System.Runtime.Serialization; namespace Signhost.APIClient.Rest.ErrorHandling { diff --git a/src/SignhostAPIClient/Rest/ErrorHandling/SignhostException.cs b/src/SignhostAPIClient/Rest/ErrorHandling/SignhostException.cs index fd06b202..30391104 100644 --- a/src/SignhostAPIClient/Rest/ErrorHandling/SignhostException.cs +++ b/src/SignhostAPIClient/Rest/ErrorHandling/SignhostException.cs @@ -1,5 +1,4 @@ using System; -using System.Runtime.Serialization; namespace Signhost.APIClient.Rest.ErrorHandling { diff --git a/src/SignhostAPIClient/Rest/ErrorHandling/SignhostRestApiClientException.cs b/src/SignhostAPIClient/Rest/ErrorHandling/SignhostRestApiClientException.cs index 600a3c53..68765691 100644 --- a/src/SignhostAPIClient/Rest/ErrorHandling/SignhostRestApiClientException.cs +++ b/src/SignhostAPIClient/Rest/ErrorHandling/SignhostRestApiClientException.cs @@ -1,5 +1,4 @@ using System; -using System.Runtime.Serialization; namespace Signhost.APIClient.Rest.ErrorHandling { diff --git a/src/SignhostAPIClient/Rest/FileDigestOptions.cs b/src/SignhostAPIClient/Rest/FileDigestOptions.cs index 02d42487..b71e0eb7 100644 --- a/src/SignhostAPIClient/Rest/FileDigestOptions.cs +++ b/src/SignhostAPIClient/Rest/FileDigestOptions.cs @@ -1,8 +1,4 @@ -using System; -using System.IO; -using System.Security.Cryptography; - -namespace Signhost.APIClient.Rest +namespace Signhost.APIClient.Rest { /// /// File digest options for file uploads diff --git a/src/SignhostAPIClient/Rest/ISignhostApiReceiver.cs b/src/SignhostAPIClient/Rest/ISignhostApiReceiver.cs index ac8441a7..7778debe 100644 --- a/src/SignhostAPIClient/Rest/ISignhostApiReceiver.cs +++ b/src/SignhostAPIClient/Rest/ISignhostApiReceiver.cs @@ -1,7 +1,4 @@ -using System; using System.Collections.Generic; -using System.Threading.Tasks; -using Signhost.APIClient.Rest; using Signhost.APIClient.Rest.DataObjects; namespace Signhost.APIClient.Rest diff --git a/src/SignhostAPIClient/Rest/SignhostApiReceiverSettings.cs b/src/SignhostAPIClient/Rest/SignhostApiReceiverSettings.cs index cb8fd629..d3d962aa 100644 --- a/src/SignhostAPIClient/Rest/SignhostApiReceiverSettings.cs +++ b/src/SignhostAPIClient/Rest/SignhostApiReceiverSettings.cs @@ -1,6 +1,4 @@ -using System; - -namespace Signhost.APIClient.Rest +namespace Signhost.APIClient.Rest { /// /// Registers the necessary settings for the class. From 41ad8a095b67f6395885c73047cf424644d731cd Mon Sep 17 00:00:00 2001 From: Anthony Timmers Date: Fri, 21 Nov 2025 19:06:48 +0100 Subject: [PATCH 5/7] Fix or suppress StyleCop Analyzer warnings --- src/SignhostAPIClient/Rest/JsonContent.cs | 10 +++++----- src/SignhostAPIClient/Rest/SignHostApiClient.cs | 5 +++-- src/SignhostAPIClient/Rest/SignhostApiReceiver.cs | 14 +++++++++----- src/signhost.ruleset | 4 ++++ 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/SignhostAPIClient/Rest/JsonContent.cs b/src/SignhostAPIClient/Rest/JsonContent.cs index 295054aa..837d627e 100644 --- a/src/SignhostAPIClient/Rest/JsonContent.cs +++ b/src/SignhostAPIClient/Rest/JsonContent.cs @@ -5,16 +5,16 @@ namespace Signhost.APIClient.Rest { /// - /// Helper class + /// See the helper class. /// internal static class JsonContent { /// /// Creates a new . /// - /// Type to serialize - /// Value to serialize - /// + /// Type to serialize. + /// Value to serialize. + /// . internal static JsonContent From(T value) { return new JsonContent(value); @@ -31,7 +31,7 @@ internal class JsonContent /// /// Initializes a new instance of the class. /// - /// Value to serialize + /// Value to serialize. public JsonContent(T value) : base(ToJson(value)) { diff --git a/src/SignhostAPIClient/Rest/SignHostApiClient.cs b/src/SignhostAPIClient/Rest/SignHostApiClient.cs index 780aa1ba..a453f2cb 100644 --- a/src/SignhostAPIClient/Rest/SignHostApiClient.cs +++ b/src/SignhostAPIClient/Rest/SignHostApiClient.cs @@ -35,7 +35,7 @@ public class SignhostApiClient /// Initializes a new instance of the class. /// Set your usertoken and APPKey by creating a . /// - /// + /// . public SignhostApiClient(ISignhostApiClientSettings settings) : this(settings, new HttpClient()) { @@ -45,7 +45,7 @@ public SignhostApiClient(ISignhostApiClientSettings settings) /// Initializes a new instance of the class. /// Set your usertoken and APPKey by creating a . /// - /// + /// . /// to use for all http calls. public SignhostApiClient( ISignhostApiClientSettings settings, @@ -153,6 +153,7 @@ public async Task GetTransactionAsync( return response.Value; } + /// public async Task DeleteTransactionAsync( string transactionId, CancellationToken cancellationToken = default) diff --git a/src/SignhostAPIClient/Rest/SignhostApiReceiver.cs b/src/SignhostAPIClient/Rest/SignhostApiReceiver.cs index bdffe930..da6c1899 100644 --- a/src/SignhostAPIClient/Rest/SignhostApiReceiver.cs +++ b/src/SignhostAPIClient/Rest/SignhostApiReceiver.cs @@ -22,7 +22,9 @@ public class SignhostApiReceiver /// Initializes a new instance of the class. /// Set your SharedSecret by creating a . /// - /// + /// + /// Settings for the receiver. + /// public SignhostApiReceiver(SignhostApiReceiverSettings receiverSettings) { this.settings = receiverSettings; @@ -64,10 +66,12 @@ private string CalculateChecksumFromPostback(PostbackTransaction postback) } } - private PostbackTransaction DeserializeToPostbackTransaction(string body) - { - return JsonSerializer.Deserialize(body, SignhostJsonSerializerOptions.Default); - } private string GetChecksumFromHeadersOrPostback( + private PostbackTransaction DeserializeToPostbackTransaction(string body) + { + return JsonSerializer.Deserialize(body, SignhostJsonSerializerOptions.Default); + } + + private string GetChecksumFromHeadersOrPostback( IDictionary headers, PostbackTransaction postback) { diff --git a/src/signhost.ruleset b/src/signhost.ruleset index 6d703aa7..51c9a98e 100644 --- a/src/signhost.ruleset +++ b/src/signhost.ruleset @@ -6,7 +6,11 @@ + + + + From f22fc4b17fcae720bcacdcb31dd76c1dcc564383 Mon Sep 17 00:00:00 2001 From: Anthony Timmers Date: Fri, 21 Nov 2025 19:07:22 +0100 Subject: [PATCH 6/7] Reformat use file-scoped namespaces --- .../LevelEnumConverterTests.cs | 103 +- src/SignhostAPIClient.Tests/PostbackTests.cs | 209 ++-- .../SignhostApiClientTests.cs | 1003 ++++++++--------- .../SignhostApiReceiverTests.cs | 115 +- src/SignhostAPIClient/Rest/ApiResponse.cs | 35 +- .../Rest/DataObjects/Activity.cs | 15 +- .../Rest/DataObjects/ActivityType.cs | 263 +++-- .../Rest/DataObjects/ConsentVerification.cs | 15 +- .../DataObjects/DeleteTransactionOptions.cs | 25 +- .../Rest/DataObjects/DigidVerification.cs | 11 +- .../DataObjects/EidasLoginVerification.cs | 61 +- .../Rest/DataObjects/Field.cs | 13 +- .../Rest/DataObjects/FileEntry.cs | 11 +- .../Rest/DataObjects/FileLink.cs | 13 +- .../Rest/DataObjects/FileMeta.cs | 33 +- .../Rest/DataObjects/FileSignerMeta.cs | 9 +- .../Rest/DataObjects/IPAddressVerification.cs | 19 +- .../Rest/DataObjects/IVerification.cs | 33 +- .../Rest/DataObjects/IdealVerification.cs | 15 +- .../Rest/DataObjects/IdinVerification.cs | 19 +- .../ItsmeIdentificationVerification.cs | 19 +- .../Rest/DataObjects/ItsmeSignVerification.cs | 15 +- .../Rest/DataObjects/Level.cs | 41 +- .../Rest/DataObjects/Location.cs | 25 +- .../DataObjects/PhoneNumberVerification.cs | 11 +- .../Rest/DataObjects/PostbackTransaction.cs | 13 +- .../Rest/DataObjects/Receiver.cs | 39 +- .../Rest/DataObjects/ScribbleVerification.cs | 15 +- .../Rest/DataObjects/Signer.cs | 77 +- .../SigningCertificateVerification.cs | 17 +- .../Rest/DataObjects/SurfnetVerification.cs | 9 +- .../Rest/DataObjects/Transaction.cs | 65 +- .../Rest/DataObjects/TransactionStatus.cs | 89 +- .../BadAuthorizationException.cs | 51 +- .../Rest/ErrorHandling/BadRequestException.cs | 51 +- .../ErrorHandling/DefaultSignhostException.cs | 41 +- .../Rest/ErrorHandling/GoneException.cs | 95 +- ...pResponseMessageErrorHandlingExtensions.cs | 161 ++- .../InternalServerErrorException.cs | 63 +- .../Rest/ErrorHandling/NotFoundException.cs | 47 +- .../ErrorHandling/OutOfCreditsException.cs | 25 +- .../Rest/ErrorHandling/SignhostException.cs | 49 +- .../SignhostRestApiClientException.cs | 51 +- .../Rest/FileDigestOptions.cs | 41 +- .../Rest/FileUploadOptions.cs | 19 +- .../Rest/HttpContentJsonExtensions.cs | 39 +- .../Rest/ISignHostApiClient.cs | 483 ++++---- .../Rest/ISignhostApiClientSettings.cs | 37 +- .../Rest/ISignhostApiReceiver.cs | 31 +- src/SignhostAPIClient/Rest/JsonContent.cs | 59 +- .../Rest/JsonConverters/LevelEnumConverter.cs | 77 +- .../Rest/SignHostApiClient.cs | 809 +++++++------ .../Rest/SignHostApiClientSettings.cs | 37 +- .../Rest/SignhostApiReceiver.cs | 131 ++- .../Rest/SignhostApiReceiverSettings.cs | 29 +- .../Rest/SignhostJsonSerializerOptions.cs | 29 +- .../StreamContentDigestOptionsExtensions.cs | 135 ++- .../Rest/UriPathExtensions.cs | 31 +- 58 files changed, 2509 insertions(+), 2567 deletions(-) diff --git a/src/SignhostAPIClient.Tests/LevelEnumConverterTests.cs b/src/SignhostAPIClient.Tests/LevelEnumConverterTests.cs index 534d5484..92ca645a 100644 --- a/src/SignhostAPIClient.Tests/LevelEnumConverterTests.cs +++ b/src/SignhostAPIClient.Tests/LevelEnumConverterTests.cs @@ -6,74 +6,73 @@ using System.Collections.Generic; using Xunit; -namespace Signhost.APIClient.Rest.Tests +namespace Signhost.APIClient.Rest.Tests; + +public class LevelEnumConverterTests { - public class LevelEnumConverterTests + [Fact] + public void when_Level_is_null_should_deserialize_to_null() { - [Fact] - public void when_Level_is_null_should_deserialize_to_null() - { - // Arrange - const string json = "{\"Type\":\"eIDAS Login\",\"Level\":null}"; + // Arrange + const string json = "{\"Type\":\"eIDAS Login\",\"Level\":null}"; - // Act - var eidasLogin = JsonSerializer.Deserialize(json, SignhostJsonSerializerOptions.Default); + // Act + var eidasLogin = JsonSerializer.Deserialize(json, SignhostJsonSerializerOptions.Default); - // Assert - eidasLogin.Level.Should().Be(null); - } + // Assert + eidasLogin.Level.Should().Be(null); + } - [Fact] - public void when_Level_is_not_supplied_should_deserialize_to_null() - { - // Arrange - const string json = "{\"Type\":\"eIDAS Login\"}"; + [Fact] + public void when_Level_is_not_supplied_should_deserialize_to_null() + { + // Arrange + const string json = "{\"Type\":\"eIDAS Login\"}"; - // Act - var eidasLogin = JsonSerializer.Deserialize(json, SignhostJsonSerializerOptions.Default); + // Act + var eidasLogin = JsonSerializer.Deserialize(json, SignhostJsonSerializerOptions.Default); - // Assert - eidasLogin.Level.Should().Be(null); - } + // Assert + eidasLogin.Level.Should().Be(null); + } - [Fact] - public void when_Level_is_unknown_should_deserialize_to_Unknown_Level() - { - // Arrange - const string json = "{\"Type\":\"eIDAS Login\",\"Level\":\"foobar\"}"; + [Fact] + public void when_Level_is_unknown_should_deserialize_to_Unknown_Level() + { + // Arrange + const string json = "{\"Type\":\"eIDAS Login\",\"Level\":\"foobar\"}"; - // Act - var eidasLogin = JsonSerializer.Deserialize(json, SignhostJsonSerializerOptions.Default); + // Act + var eidasLogin = JsonSerializer.Deserialize(json, SignhostJsonSerializerOptions.Default); - // Assert - eidasLogin.Level.Should().Be(Level.Unknown); - } + // Assert + eidasLogin.Level.Should().Be(Level.Unknown); + } - [Theory] - [ClassData(typeof(LevelTestData))] - public void when_Level_is_valid_should_deserialize_to_correct_value(Level level) - { - // Arrange - string json = $"{{\"Type\":\"eIDAS Login\",\"Level\":\"{level}\"}}"; + [Theory] + [ClassData(typeof(LevelTestData))] + public void when_Level_is_valid_should_deserialize_to_correct_value(Level level) + { + // Arrange + string json = $"{{\"Type\":\"eIDAS Login\",\"Level\":\"{level}\"}}"; - // Act - var eidasLogin = JsonSerializer.Deserialize(json, SignhostJsonSerializerOptions.Default); + // Act + var eidasLogin = JsonSerializer.Deserialize(json, SignhostJsonSerializerOptions.Default); - // Assert - eidasLogin.Level.Should().Be(level); - } + // Assert + eidasLogin.Level.Should().Be(level); + } - private class LevelTestData - : IEnumerable + private class LevelTestData + : IEnumerable + { + public IEnumerator GetEnumerator() { - public IEnumerator GetEnumerator() - { - foreach (var value in Enum.GetValues(typeof(Level))) { - yield return new[] { value }; - } + foreach (var value in Enum.GetValues(typeof(Level))) { + yield return new[] { value }; } - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } } diff --git a/src/SignhostAPIClient.Tests/PostbackTests.cs b/src/SignhostAPIClient.Tests/PostbackTests.cs index 7a005953..8d3314cd 100644 --- a/src/SignhostAPIClient.Tests/PostbackTests.cs +++ b/src/SignhostAPIClient.Tests/PostbackTests.cs @@ -6,112 +6,111 @@ using SignhostAPIClient.Tests.JSON; using Xunit; -namespace Signhost.APIClient.Rest.Tests +namespace Signhost.APIClient.Rest.Tests; + +public class PostbackTests { - public class PostbackTests + [Fact] + public void PostbackTransaction_should_get_serialized_correctly() { - [Fact] - public void PostbackTransaction_should_get_serialized_correctly() - { - string json = JsonResources.MockPostbackValid; - var postbackTransaction = JsonSerializer.Deserialize(json, SignhostJsonSerializerOptions.Default); - - postbackTransaction.Id .Should().Be("b10ae331-af78-4e79-a39e-5b64693b6b68"); - postbackTransaction.Status .Should().Be(TransactionStatus.InProgress); - postbackTransaction.Seal .Should().BeTrue(); - postbackTransaction.Reference .Should().Be("Contract #123"); - postbackTransaction.PostbackUrl .Should().Be("https://example.com/postback.php"); - postbackTransaction.SignRequestMode .Should().Be(2); - postbackTransaction.DaysToExpire .Should().Be(30); - postbackTransaction.SendEmailNotifications.Should().BeTrue(); - postbackTransaction.CreatedDateTime .Should().Be(DateTimeOffset.Parse("2016-08-31T21:22:56.2467731+02:00")); - postbackTransaction.CanceledDateTime .Should().BeNull(); - (postbackTransaction.Context is null) .Should().BeTrue(); - postbackTransaction.Checksum .Should().Be("cdc09eee2ed6df2846dcc193aedfef59f2834f8d"); - - var signers = postbackTransaction.Signers; - signers.Should().HaveCount(1); - - var signer = signers.Single(); - signer.Id .Should().Be("fa95495d-6c59-48e0-962a-a4552f8d6b85"); - signer.Expires .Should().BeNull(); - signer.Email .Should().Be("user@example.com"); - signer.SendSignRequest .Should().BeTrue(); - signer.SendSignConfirmation.Should().BeNull(); - signer.SignRequestMessage .Should().Be("Hello, could you please sign this document? Best regards, John Doe"); - signer.DaysToRemind .Should().Be(15); - signer.Language .Should().Be("en-US"); - signer.ScribbleName .Should().Be("John Doe"); - signer.ScribbleNameFixed .Should().BeFalse(); - signer.Reference .Should().Be("Client #123"); - signer.ReturnUrl .Should().Be("https://signhost.com"); - signer.RejectReason .Should().BeNull(); - signer.SignUrl .Should().Be("https://view.signhost.com/sign/d3c93bd6-f1ce-48e7-8c9c-c2babfdd4034"); - (signer.Context is null) .Should().BeTrue(); - - var verifications = signer.Verifications; - verifications.Should().HaveCount(3); - - var phoneNumberVerification = verifications[0] as PhoneNumberVerification; - phoneNumberVerification .Should().NotBeNull(); - phoneNumberVerification.Number.Should().Be("+31612345678"); - - var scribbleVerification = verifications[1] as ScribbleVerification; - scribbleVerification .Should().NotBeNull(); - scribbleVerification.RequireHandsignature.Should().BeFalse(); - scribbleVerification.ScribbleNameFixed .Should().BeFalse(); - scribbleVerification.ScribbleName .Should().Be("John Doe"); - - var ipAddressVerification = verifications[2] as IPAddressVerification; - ipAddressVerification .Should().NotBeNull(); - ipAddressVerification.IPAddress.Should().Be("1.2.3.4"); - - var activities = signer.Activities; - activities.Should().HaveCount(3); - - var openedActivity = activities[0]; - openedActivity.Id .Should().Be("bcba44a9-c201-4494-9920-2c1f7baebcf0"); - openedActivity.Code .Should().Be(ActivityType.Opened); - openedActivity.Info .Should().BeNull(); - openedActivity.CreatedDateTime.Should().Be(DateTimeOffset.Parse("2016-06-15T23:33:04.1965465+02:00")); - - var documentOpenedActivity = activities[1]; - documentOpenedActivity.Id .Should().Be("7aacf96a-5c2f-475d-98a5-726e41bfc5d3"); - documentOpenedActivity.Code .Should().Be(ActivityType.DocumentOpened); - documentOpenedActivity.Info .Should().Be("file1"); - documentOpenedActivity.CreatedDateTime.Should().Be(DateTimeOffset.Parse("2020-01-30T16:31:05.6679583+01:00")); - - var signedActivity = activities[2]; - signedActivity.Id .Should().Be("de94cf6e-e1a3-4c33-93bf-2013b036daaf"); - signedActivity.Code .Should().Be(ActivityType.Signed); - signedActivity.Info .Should().BeNull(); - signedActivity.CreatedDateTime.Should().Be(DateTimeOffset.Parse("2016-06-15T23:38:04.1965465+02:00")); - - var receivers = postbackTransaction.Receivers; - receivers.Should().HaveCount(1); - - var receiver = receivers.Single(); - receiver.Name .Should().Be("John Doe"); - receiver.Email .Should().Be("user@example.com"); - receiver.Language .Should().Be("en-US"); - receiver.Message .Should().Be("Hello, please find enclosed the digital signed document. Best regards, John Doe"); - receiver.Reference .Should().BeNull(); - receiver.Activities .Should().BeNull(); - (receiver.Context is null).Should().BeTrue(); - - var files = postbackTransaction.Files; - files.Should().HaveCount(1); - - var file = files["file1"]; - file.DisplayName.Should().Be("Sample File"); - - var links = file.Links; - links.Should().HaveCount(1); - - var link = links.Single(); - link.Rel .Should().Be("file"); - link.Type.Should().Be("application/pdf"); - link.Link.Should().Be("https://api.signhost.com/api/transaction/b10ae331-af78-4e79-a39e-5b64693b6b68/file/file1"); - } + string json = JsonResources.MockPostbackValid; + var postbackTransaction = JsonSerializer.Deserialize(json, SignhostJsonSerializerOptions.Default); + + postbackTransaction.Id .Should().Be("b10ae331-af78-4e79-a39e-5b64693b6b68"); + postbackTransaction.Status .Should().Be(TransactionStatus.InProgress); + postbackTransaction.Seal .Should().BeTrue(); + postbackTransaction.Reference .Should().Be("Contract #123"); + postbackTransaction.PostbackUrl .Should().Be("https://example.com/postback.php"); + postbackTransaction.SignRequestMode .Should().Be(2); + postbackTransaction.DaysToExpire .Should().Be(30); + postbackTransaction.SendEmailNotifications.Should().BeTrue(); + postbackTransaction.CreatedDateTime .Should().Be(DateTimeOffset.Parse("2016-08-31T21:22:56.2467731+02:00")); + postbackTransaction.CanceledDateTime .Should().BeNull(); + (postbackTransaction.Context is null) .Should().BeTrue(); + postbackTransaction.Checksum .Should().Be("cdc09eee2ed6df2846dcc193aedfef59f2834f8d"); + + var signers = postbackTransaction.Signers; + signers.Should().HaveCount(1); + + var signer = signers.Single(); + signer.Id .Should().Be("fa95495d-6c59-48e0-962a-a4552f8d6b85"); + signer.Expires .Should().BeNull(); + signer.Email .Should().Be("user@example.com"); + signer.SendSignRequest .Should().BeTrue(); + signer.SendSignConfirmation.Should().BeNull(); + signer.SignRequestMessage .Should().Be("Hello, could you please sign this document? Best regards, John Doe"); + signer.DaysToRemind .Should().Be(15); + signer.Language .Should().Be("en-US"); + signer.ScribbleName .Should().Be("John Doe"); + signer.ScribbleNameFixed .Should().BeFalse(); + signer.Reference .Should().Be("Client #123"); + signer.ReturnUrl .Should().Be("https://signhost.com"); + signer.RejectReason .Should().BeNull(); + signer.SignUrl .Should().Be("https://view.signhost.com/sign/d3c93bd6-f1ce-48e7-8c9c-c2babfdd4034"); + (signer.Context is null) .Should().BeTrue(); + + var verifications = signer.Verifications; + verifications.Should().HaveCount(3); + + var phoneNumberVerification = verifications[0] as PhoneNumberVerification; + phoneNumberVerification .Should().NotBeNull(); + phoneNumberVerification.Number.Should().Be("+31612345678"); + + var scribbleVerification = verifications[1] as ScribbleVerification; + scribbleVerification .Should().NotBeNull(); + scribbleVerification.RequireHandsignature.Should().BeFalse(); + scribbleVerification.ScribbleNameFixed .Should().BeFalse(); + scribbleVerification.ScribbleName .Should().Be("John Doe"); + + var ipAddressVerification = verifications[2] as IPAddressVerification; + ipAddressVerification .Should().NotBeNull(); + ipAddressVerification.IPAddress.Should().Be("1.2.3.4"); + + var activities = signer.Activities; + activities.Should().HaveCount(3); + + var openedActivity = activities[0]; + openedActivity.Id .Should().Be("bcba44a9-c201-4494-9920-2c1f7baebcf0"); + openedActivity.Code .Should().Be(ActivityType.Opened); + openedActivity.Info .Should().BeNull(); + openedActivity.CreatedDateTime.Should().Be(DateTimeOffset.Parse("2016-06-15T23:33:04.1965465+02:00")); + + var documentOpenedActivity = activities[1]; + documentOpenedActivity.Id .Should().Be("7aacf96a-5c2f-475d-98a5-726e41bfc5d3"); + documentOpenedActivity.Code .Should().Be(ActivityType.DocumentOpened); + documentOpenedActivity.Info .Should().Be("file1"); + documentOpenedActivity.CreatedDateTime.Should().Be(DateTimeOffset.Parse("2020-01-30T16:31:05.6679583+01:00")); + + var signedActivity = activities[2]; + signedActivity.Id .Should().Be("de94cf6e-e1a3-4c33-93bf-2013b036daaf"); + signedActivity.Code .Should().Be(ActivityType.Signed); + signedActivity.Info .Should().BeNull(); + signedActivity.CreatedDateTime.Should().Be(DateTimeOffset.Parse("2016-06-15T23:38:04.1965465+02:00")); + + var receivers = postbackTransaction.Receivers; + receivers.Should().HaveCount(1); + + var receiver = receivers.Single(); + receiver.Name .Should().Be("John Doe"); + receiver.Email .Should().Be("user@example.com"); + receiver.Language .Should().Be("en-US"); + receiver.Message .Should().Be("Hello, please find enclosed the digital signed document. Best regards, John Doe"); + receiver.Reference .Should().BeNull(); + receiver.Activities .Should().BeNull(); + (receiver.Context is null).Should().BeTrue(); + + var files = postbackTransaction.Files; + files.Should().HaveCount(1); + + var file = files["file1"]; + file.DisplayName.Should().Be("Sample File"); + + var links = file.Links; + links.Should().HaveCount(1); + + var link = links.Single(); + link.Rel .Should().Be("file"); + link.Type.Should().Be("application/pdf"); + link.Link.Should().Be("https://api.signhost.com/api/transaction/b10ae331-af78-4e79-a39e-5b64693b6b68/file/file1"); } } diff --git a/src/SignhostAPIClient.Tests/SignhostApiClientTests.cs b/src/SignhostAPIClient.Tests/SignhostApiClientTests.cs index fc3c085a..aee6ccff 100644 --- a/src/SignhostAPIClient.Tests/SignhostApiClientTests.cs +++ b/src/SignhostAPIClient.Tests/SignhostApiClientTests.cs @@ -10,661 +10,660 @@ using System.Net; using SignhostAPIClient.Tests.JSON; -namespace Signhost.APIClient.Rest.Tests +namespace Signhost.APIClient.Rest.Tests; + +public class SignhostApiClientTests { - public class SignhostApiClientTests - { - private readonly SignhostApiClientSettings settings = new("AppKey", "Usertoken") { - Endpoint = "http://localhost/api/" - }; + private readonly SignhostApiClientSettings settings = new("AppKey", "Usertoken") { + Endpoint = "http://localhost/api/" + }; - private readonly SignhostApiClientSettings oauthSettings = new("AppKey") { - Endpoint = "http://localhost/api/" - }; + private readonly SignhostApiClientSettings oauthSettings = new("AppKey") { + Endpoint = "http://localhost/api/" + }; - [Fact] - public async Task when_AddOrReplaceFileMetaToTransaction_is_called_then_the_request_body_should_contain_the_serialized_file_meta() - { - var mockHttp = new MockHttpMessageHandler(); + [Fact] + public async Task when_AddOrReplaceFileMetaToTransaction_is_called_then_the_request_body_should_contain_the_serialized_file_meta() + { + var mockHttp = new MockHttpMessageHandler(); - mockHttp.Expect(HttpMethod.Put, "http://localhost/api/transaction/transactionId/file/fileId") - .WithContent(JsonResources.AddOrReplaceFileMetaToTransaction) - .Respond(HttpStatusCode.OK); + mockHttp.Expect(HttpMethod.Put, "http://localhost/api/transaction/transactionId/file/fileId") + .WithContent(JsonResources.AddOrReplaceFileMetaToTransaction) + .Respond(HttpStatusCode.OK); - using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignhostApiClient(settings, httpClient); + using (var httpClient = mockHttp.ToHttpClient()) { + var signhostApiClient = new SignhostApiClient(settings, httpClient); - var fileSignerMeta = new FileSignerMeta - { - FormSets = new string[] { "SampleFormSet" } - }; + var fileSignerMeta = new FileSignerMeta + { + FormSets = new string[] { "SampleFormSet" } + }; - var field = new Field + var field = new Field + { + Type = "Check", + Value = "I agree", + Location = new Location { - Type = "Check", - Value = "I agree", - Location = new Location - { - Search = "test" - } - }; + Search = "test" + } + }; - FileMeta fileMeta = new FileMeta + FileMeta fileMeta = new FileMeta + { + Signers = new Dictionary { - Signers = new Dictionary - { - { "someSignerId", fileSignerMeta } - }, - FormSets = new Dictionary> - { - { "SampleFormSet", new Dictionary - { - { "SampleCheck", field } - } + { "someSignerId", fileSignerMeta } + }, + FormSets = new Dictionary> + { + { "SampleFormSet", new Dictionary + { + { "SampleCheck", field } } } - }; - - await signhostApiClient.AddOrReplaceFileMetaToTransactionAsync(fileMeta, "transactionId", "fileId"); - } + } + }; - mockHttp.VerifyNoOutstandingExpectation(); + await signhostApiClient.AddOrReplaceFileMetaToTransactionAsync(fileMeta, "transactionId", "fileId"); } - [Fact] - public async Task when_a_GetTransaction_is_called_then_we_should_have_called_the_transaction_get_once() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "http://localhost/api/transaction/transaction Id") - .Respond(HttpStatusCode.OK, new StringContent(JsonResources.GetTransaction)); + mockHttp.VerifyNoOutstandingExpectation(); + } - using (var httpClient = mockHttp.ToHttpClient()) { + [Fact] + public async Task when_a_GetTransaction_is_called_then_we_should_have_called_the_transaction_get_once() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Get, "http://localhost/api/transaction/transaction Id") + .Respond(HttpStatusCode.OK, new StringContent(JsonResources.GetTransaction)); - var signhostApiClient = new SignhostApiClient(settings, httpClient); + using (var httpClient = mockHttp.ToHttpClient()) { - var result = await signhostApiClient.GetTransactionAsync("transaction Id"); - result.Id.Should().Be("c487be92-0255-40c7-bd7d-20805a65e7d9"); - } + var signhostApiClient = new SignhostApiClient(settings, httpClient); - mockHttp.VerifyNoOutstandingExpectation(); + var result = await signhostApiClient.GetTransactionAsync("transaction Id"); + result.Id.Should().Be("c487be92-0255-40c7-bd7d-20805a65e7d9"); } - [Fact] - public async Task when_GetTransaction_is_called_and_the_authorization_is_bad_then_we_should_get_a_BadAuthorizationException() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "http://localhost/api/transaction/transaction Id") - .Respond(HttpStatusCode.Unauthorized, new StringContent(""" - { - "message": "unauthorized" - } - """)); + mockHttp.VerifyNoOutstandingExpectation(); + } - using (var httpClient = mockHttp.ToHttpClient()) { + [Fact] + public async Task when_GetTransaction_is_called_and_the_authorization_is_bad_then_we_should_get_a_BadAuthorizationException() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Get, "http://localhost/api/transaction/transaction Id") + .Respond(HttpStatusCode.Unauthorized, new StringContent(""" + { + "message": "unauthorized" + } + """)); - var signhostApiClient = new SignhostApiClient(settings, httpClient); + using (var httpClient = mockHttp.ToHttpClient()) { - Func getTransaction = () => signhostApiClient.GetTransactionAsync("transaction Id"); - await getTransaction.Should().ThrowAsync(); - } + var signhostApiClient = new SignhostApiClient(settings, httpClient); - mockHttp.VerifyNoOutstandingExpectation(); + Func getTransaction = () => signhostApiClient.GetTransactionAsync("transaction Id"); + await getTransaction.Should().ThrowAsync(); } - [Fact] - public async Task when_GetTransaction_is_called_and_request_is_bad_then_we_should_get_a_BadRequestException() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "http://localhost/api/transaction/transaction Id") - .Respond(HttpStatusCode.BadRequest, new StringContent(""" - { - "message": "Bad Request" - } - """)); + mockHttp.VerifyNoOutstandingExpectation(); + } - using (var httpClient = mockHttp.ToHttpClient()) { + [Fact] + public async Task when_GetTransaction_is_called_and_request_is_bad_then_we_should_get_a_BadRequestException() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Get, "http://localhost/api/transaction/transaction Id") + .Respond(HttpStatusCode.BadRequest, new StringContent(""" + { + "message": "Bad Request" + } + """)); - var signhostApiClient = new SignhostApiClient(settings, httpClient); + using (var httpClient = mockHttp.ToHttpClient()) { - Func getTransaction = () => signhostApiClient.GetTransactionAsync("transaction Id"); - await getTransaction.Should().ThrowAsync(); - } + var signhostApiClient = new SignhostApiClient(settings, httpClient); - mockHttp.VerifyNoOutstandingExpectation(); + Func getTransaction = () => signhostApiClient.GetTransactionAsync("transaction Id"); + await getTransaction.Should().ThrowAsync(); } - [Fact] - public async Task when_GetTransaction_is_called_and_credits_have_run_out_then_we_should_get_a_OutOfCreditsException() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "http://localhost/api/transaction/transaction Id") - .Respond(HttpStatusCode.PaymentRequired, new StringContent(""" - { - "type": "https://api.signhost.com/problem/subscription/out-of-credits" - } - """)); + mockHttp.VerifyNoOutstandingExpectation(); + } - using (var httpClient = mockHttp.ToHttpClient()) { + [Fact] + public async Task when_GetTransaction_is_called_and_credits_have_run_out_then_we_should_get_a_OutOfCreditsException() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Get, "http://localhost/api/transaction/transaction Id") + .Respond(HttpStatusCode.PaymentRequired, new StringContent(""" + { + "type": "https://api.signhost.com/problem/subscription/out-of-credits" + } + """)); - var signhostApiClient = new SignhostApiClient(settings, httpClient); + using (var httpClient = mockHttp.ToHttpClient()) { - Func getTransaction = () => signhostApiClient.GetTransactionAsync("transaction Id"); - await getTransaction.Should().ThrowAsync(); - } + var signhostApiClient = new SignhostApiClient(settings, httpClient); - mockHttp.VerifyNoOutstandingExpectation(); + Func getTransaction = () => signhostApiClient.GetTransactionAsync("transaction Id"); + await getTransaction.Should().ThrowAsync(); } - [Fact] - public async Task when_GetTransaction_is_called_and_not_found_then_we_should_get_a_NotFoundException() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "http://localhost/api/transaction/transaction Id") - .Respond(HttpStatusCode.NotFound, new StringContent(""" - { - "message": "Not Found" - } - """)); + mockHttp.VerifyNoOutstandingExpectation(); + } - using (var httpClient = mockHttp.ToHttpClient()) { + [Fact] + public async Task when_GetTransaction_is_called_and_not_found_then_we_should_get_a_NotFoundException() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Get, "http://localhost/api/transaction/transaction Id") + .Respond(HttpStatusCode.NotFound, new StringContent(""" + { + "message": "Not Found" + } + """)); - var signhostApiClient = new SignhostApiClient(settings, httpClient); + using (var httpClient = mockHttp.ToHttpClient()) { - Func getTransaction = () => signhostApiClient.GetTransactionAsync("transaction Id"); + var signhostApiClient = new SignhostApiClient(settings, httpClient); - await getTransaction.Should().ThrowAsync().WithMessage("Not Found"); - } + Func getTransaction = () => signhostApiClient.GetTransactionAsync("transaction Id"); - mockHttp.VerifyNoOutstandingExpectation(); + await getTransaction.Should().ThrowAsync().WithMessage("Not Found"); } - [Fact] - public async Task when_GetTransaction_is_called_and_unkownerror_like_418_occures_then_we_should_get_a_SignhostException() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "http://localhost/api/transaction/transaction Id") - .Respond((HttpStatusCode)418, new StringContent(""" - { - "message": "418 I'm a teapot" - } - """)); + mockHttp.VerifyNoOutstandingExpectation(); + } - using (var httpClient = mockHttp.ToHttpClient()) { + [Fact] + public async Task when_GetTransaction_is_called_and_unkownerror_like_418_occures_then_we_should_get_a_SignhostException() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Get, "http://localhost/api/transaction/transaction Id") + .Respond((HttpStatusCode)418, new StringContent(""" + { + "message": "418 I'm a teapot" + } + """)); - var signhostApiClient = new SignhostApiClient(settings, httpClient); + using (var httpClient = mockHttp.ToHttpClient()) { - Func getTransaction = () => signhostApiClient.GetTransactionAsync("transaction Id"); - await getTransaction.Should().ThrowAsync() - .WithMessage("*418*"); - } + var signhostApiClient = new SignhostApiClient(settings, httpClient); - mockHttp.VerifyNoOutstandingExpectation(); + Func getTransaction = () => signhostApiClient.GetTransactionAsync("transaction Id"); + await getTransaction.Should().ThrowAsync() + .WithMessage("*418*"); } - [Fact] - public async Task when_GetTransaction_is_called_and_there_is_an_InternalServerError_then_we_should_get_a_InternalServerErrorException() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "http://localhost/api/transaction/transaction Id") - .Respond(HttpStatusCode.InternalServerError, new StringContent(""" - { - "message": "Internal Server Error" - } - """)); + mockHttp.VerifyNoOutstandingExpectation(); + } - using (var httpClient = mockHttp.ToHttpClient()) { + [Fact] + public async Task when_GetTransaction_is_called_and_there_is_an_InternalServerError_then_we_should_get_a_InternalServerErrorException() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Get, "http://localhost/api/transaction/transaction Id") + .Respond(HttpStatusCode.InternalServerError, new StringContent(""" + { + "message": "Internal Server Error" + } + """)); - var signhostApiClient = new SignhostApiClient(settings, httpClient); + using (var httpClient = mockHttp.ToHttpClient()) { - Func getTransaction = () => signhostApiClient.GetTransactionAsync("transaction Id"); - await getTransaction.Should().ThrowAsync(); - } + var signhostApiClient = new SignhostApiClient(settings, httpClient); - mockHttp.VerifyNoOutstandingExpectation(); + Func getTransaction = () => signhostApiClient.GetTransactionAsync("transaction Id"); + await getTransaction.Should().ThrowAsync(); } - [Fact] - public async Task When_GetTransaction_is_called_on_gone_transaction_we_shoud_get_a_GoneException() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "http://localhost/api/transaction/transaction Id") - .Respond(HttpStatusCode.Gone, new StringContent(JsonResources.GetTransaction)); + mockHttp.VerifyNoOutstandingExpectation(); + } - using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignhostApiClient(settings, httpClient); + [Fact] + public async Task When_GetTransaction_is_called_on_gone_transaction_we_shoud_get_a_GoneException() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Get, "http://localhost/api/transaction/transaction Id") + .Respond(HttpStatusCode.Gone, new StringContent(JsonResources.GetTransaction)); - Func getTransaction = () => signhostApiClient.GetTransactionAsync("transaction Id"); - await getTransaction.Should().ThrowAsync>(); - } + using (var httpClient = mockHttp.ToHttpClient()) { + var signhostApiClient = new SignhostApiClient(settings, httpClient); - mockHttp.VerifyNoOutstandingExpectation(); + Func getTransaction = () => signhostApiClient.GetTransactionAsync("transaction Id"); + await getTransaction.Should().ThrowAsync>(); } - [Fact] - public async Task When_GetTransaction_is_called_and_gone_is_expected_we_should_get_a_transaction() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "http://localhost/api/transaction/transaction Id") - .Respond(HttpStatusCode.Gone, new StringContent(JsonResources.GetTransaction)); + mockHttp.VerifyNoOutstandingExpectation(); + } - using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignhostApiClient(settings, httpClient); + [Fact] + public async Task When_GetTransaction_is_called_and_gone_is_expected_we_should_get_a_transaction() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Get, "http://localhost/api/transaction/transaction Id") + .Respond(HttpStatusCode.Gone, new StringContent(JsonResources.GetTransaction)); - Func getTransaction = () => signhostApiClient.GetTransactionResponseAsync("transaction Id"); - await getTransaction.Should().NotThrowAsync(); - } + using (var httpClient = mockHttp.ToHttpClient()) { + var signhostApiClient = new SignhostApiClient(settings, httpClient); - mockHttp.VerifyNoOutstandingExpectation(); + Func getTransaction = () => signhostApiClient.GetTransactionResponseAsync("transaction Id"); + await getTransaction.Should().NotThrowAsync(); } - [Fact] - public async Task when_a_CreateTransaction_is_called_then_we_should_have_called_the_transaction_Post_once() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Post, "http://localhost/api/transaction") - .Respond(HttpStatusCode.OK, new StringContent(JsonResources.AddTransaction)); + mockHttp.VerifyNoOutstandingExpectation(); + } - using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignhostApiClient(settings, httpClient); + [Fact] + public async Task when_a_CreateTransaction_is_called_then_we_should_have_called_the_transaction_Post_once() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Post, "http://localhost/api/transaction") + .Respond(HttpStatusCode.OK, new StringContent(JsonResources.AddTransaction)); - Signer testSigner = new Signer(); - testSigner.Email = "firstname.lastname@gmail.com"; + using (var httpClient = mockHttp.ToHttpClient()) { + var signhostApiClient = new SignhostApiClient(settings, httpClient); - Transaction testTransaction = new Transaction(); - testTransaction.Signers.Add(testSigner); + Signer testSigner = new Signer(); + testSigner.Email = "firstname.lastname@gmail.com"; - var result = await signhostApiClient.CreateTransactionAsync(testTransaction); - result.Id.Should().Be("c487be92-0255-40c7-bd7d-20805a65e7d9"); - } + Transaction testTransaction = new Transaction(); + testTransaction.Signers.Add(testSigner); - mockHttp.VerifyNoOutstandingExpectation(); + var result = await signhostApiClient.CreateTransactionAsync(testTransaction); + result.Id.Should().Be("c487be92-0255-40c7-bd7d-20805a65e7d9"); } - [Fact] - public async Task when_a_CreateTransaction_is_called_we_can_add_custom_http_headers() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Post, "http://localhost/api/transaction") - .WithHeaders("X-Forwarded-For", "localhost") - .With(matcher => matcher.Headers.UserAgent.ToString().Contains("SignhostClientLibrary")) - .Respond(HttpStatusCode.OK, new StringContent(JsonResources.AddTransaction)); + mockHttp.VerifyNoOutstandingExpectation(); + } - using (var httpClient = mockHttp.ToHttpClient()) { - settings.AddHeader = (AddHeaders a) => a("X-Forwarded-For", "localhost"); + [Fact] + public async Task when_a_CreateTransaction_is_called_we_can_add_custom_http_headers() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Post, "http://localhost/api/transaction") + .WithHeaders("X-Forwarded-For", "localhost") + .With(matcher => matcher.Headers.UserAgent.ToString().Contains("SignhostClientLibrary")) + .Respond(HttpStatusCode.OK, new StringContent(JsonResources.AddTransaction)); - var signhostApiClient = new SignhostApiClient(settings, httpClient); + using (var httpClient = mockHttp.ToHttpClient()) { + settings.AddHeader = (AddHeaders a) => a("X-Forwarded-For", "localhost"); - Transaction testTransaction = new Transaction(); + var signhostApiClient = new SignhostApiClient(settings, httpClient); - var result = await signhostApiClient.CreateTransactionAsync(testTransaction); - } + Transaction testTransaction = new Transaction(); - mockHttp.VerifyNoOutstandingExpectation(); + var result = await signhostApiClient.CreateTransactionAsync(testTransaction); } - [Fact] - public async Task when_CreateTransaction_is_called_with_invalid_email_then_we_should_get_a_BadRequestException() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Post, "http://localhost/api/transaction") - .WithHeaders("Content-Type", "application/json") - .Respond(HttpStatusCode.BadRequest, new StringContent(""" - { - "message": "Bad Request" - } - """)); + mockHttp.VerifyNoOutstandingExpectation(); + } - using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignhostApiClient(settings, httpClient); + [Fact] + public async Task when_CreateTransaction_is_called_with_invalid_email_then_we_should_get_a_BadRequestException() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Post, "http://localhost/api/transaction") + .WithHeaders("Content-Type", "application/json") + .Respond(HttpStatusCode.BadRequest, new StringContent(""" + { + "message": "Bad Request" + } + """)); - Signer testSigner = new Signer(); - testSigner.Email = "firstname.lastnamegmail.com"; + using (var httpClient = mockHttp.ToHttpClient()) { + var signhostApiClient = new SignhostApiClient(settings, httpClient); - Transaction testTransaction = new Transaction(); - testTransaction.Signers.Add(testSigner); + Signer testSigner = new Signer(); + testSigner.Email = "firstname.lastnamegmail.com"; - Func getTransaction = () => signhostApiClient.CreateTransactionAsync(testTransaction); - await getTransaction.Should().ThrowAsync(); - } + Transaction testTransaction = new Transaction(); + testTransaction.Signers.Add(testSigner); - mockHttp.VerifyNoOutstandingExpectation(); + Func getTransaction = () => signhostApiClient.CreateTransactionAsync(testTransaction); + await getTransaction.Should().ThrowAsync(); } - [Fact] - public async Task when_a_function_is_called_with_a_wrong_endpoint_we_should_get_a_SignhostRestApiClientException() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "http://localhost/api/transaction/transaction Id") - .Respond(HttpStatusCode.BadGateway, new StringContent(""" - { - "message": "Bad Gateway" - } - """)); - - using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignhostApiClient(settings, httpClient); + mockHttp.VerifyNoOutstandingExpectation(); + } - Func getTransaction = () => signhostApiClient.GetTransactionAsync("transaction Id"); - await getTransaction.Should().ThrowAsync() - .WithMessage("Bad Gateway"); + [Fact] + public async Task when_a_function_is_called_with_a_wrong_endpoint_we_should_get_a_SignhostRestApiClientException() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Get, "http://localhost/api/transaction/transaction Id") + .Respond(HttpStatusCode.BadGateway, new StringContent(""" + { + "message": "Bad Gateway" } + """)); - mockHttp.VerifyNoOutstandingExpectation(); + using (var httpClient = mockHttp.ToHttpClient()) { + var signhostApiClient = new SignhostApiClient(settings, httpClient); + + Func getTransaction = () => signhostApiClient.GetTransactionAsync("transaction Id"); + await getTransaction.Should().ThrowAsync() + .WithMessage("Bad Gateway"); } - [Fact] - public async Task when_a_DeleteTransaction_is_called_then_we_should_have_called_the_transaction_delete_once() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Delete, "http://localhost/api/transaction/transaction Id") - .Respond(HttpStatusCode.OK, new StringContent(JsonResources.DeleteTransaction)); + mockHttp.VerifyNoOutstandingExpectation(); + } - using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignhostApiClient(settings, httpClient); + [Fact] + public async Task when_a_DeleteTransaction_is_called_then_we_should_have_called_the_transaction_delete_once() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Delete, "http://localhost/api/transaction/transaction Id") + .Respond(HttpStatusCode.OK, new StringContent(JsonResources.DeleteTransaction)); - await signhostApiClient.DeleteTransactionAsync("transaction Id"); - } + using (var httpClient = mockHttp.ToHttpClient()) { + var signhostApiClient = new SignhostApiClient(settings, httpClient); - mockHttp.VerifyNoOutstandingExpectation(); + await signhostApiClient.DeleteTransactionAsync("transaction Id"); } - [Fact] - public async Task when_a_DeleteTransaction_with_notification_is_called_then_we_should_have_called_the_transaction_delete_once() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Delete, "http://localhost/api/transaction/transaction Id") - .WithHeaders("Content-Type", "application/json") - //.With(matcher => matcher.Content.ToString().Contains("'SendNotifications': true")) - .Respond(HttpStatusCode.OK, new StringContent(JsonResources.DeleteTransaction)); - - using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignhostApiClient(settings, httpClient); - - await signhostApiClient.DeleteTransactionAsync( - "transaction Id", - new DeleteTransactionOptions { SendNotifications = true }); - } + mockHttp.VerifyNoOutstandingExpectation(); + } - mockHttp.VerifyNoOutstandingExpectation(); + [Fact] + public async Task when_a_DeleteTransaction_with_notification_is_called_then_we_should_have_called_the_transaction_delete_once() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Delete, "http://localhost/api/transaction/transaction Id") + .WithHeaders("Content-Type", "application/json") + //.With(matcher => matcher.Content.ToString().Contains("'SendNotifications': true")) + .Respond(HttpStatusCode.OK, new StringContent(JsonResources.DeleteTransaction)); + + using (var httpClient = mockHttp.ToHttpClient()) { + var signhostApiClient = new SignhostApiClient(settings, httpClient); + + await signhostApiClient.DeleteTransactionAsync( + "transaction Id", + new DeleteTransactionOptions { SendNotifications = true }); } - [Fact] - public async Task when_AddOrReplaceFileToTransaction_is_called_then_we_should_have_called_the_file_put_once() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Put, "http://localhost/api/transaction/transaction Id/file/file Id") - .WithHeaders("Content-Type", "application/pdf") - .WithHeaders("Digest", "SHA-256=47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=") - .Respond(HttpStatusCode.OK); - - using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignhostApiClient(settings, httpClient); - - // Create a 0 sized file - using (Stream file = System.IO.File.Create("unittestdocument.pdf")) { - await signhostApiClient.AddOrReplaceFileToTransaction(file, "transaction Id", "file Id"); - } - } + mockHttp.VerifyNoOutstandingExpectation(); + } - mockHttp.VerifyNoOutstandingExpectation(); + [Fact] + public async Task when_AddOrReplaceFileToTransaction_is_called_then_we_should_have_called_the_file_put_once() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Put, "http://localhost/api/transaction/transaction Id/file/file Id") + .WithHeaders("Content-Type", "application/pdf") + .WithHeaders("Digest", "SHA-256=47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=") + .Respond(HttpStatusCode.OK); + + using (var httpClient = mockHttp.ToHttpClient()) { + var signhostApiClient = new SignhostApiClient(settings, httpClient); + + // Create a 0 sized file + using (Stream file = System.IO.File.Create("unittestdocument.pdf")) { + await signhostApiClient.AddOrReplaceFileToTransaction(file, "transaction Id", "file Id"); + } } - [Fact] - public async Task when_AddOrReplaceFileToTransaction_is_called_default_digest_is_sha256() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Put, "http://localhost/api/transaction/transaction Id/file/file Id") - .WithHeaders("Digest", "SHA-256=47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=") - .Respond(HttpStatusCode.OK); + mockHttp.VerifyNoOutstandingExpectation(); + } - using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignhostApiClient(settings, httpClient); + [Fact] + public async Task when_AddOrReplaceFileToTransaction_is_called_default_digest_is_sha256() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Put, "http://localhost/api/transaction/transaction Id/file/file Id") + .WithHeaders("Digest", "SHA-256=47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=") + .Respond(HttpStatusCode.OK); - await signhostApiClient.AddOrReplaceFileToTransaction(new MemoryStream(), "transaction Id", "file Id"); - } + using (var httpClient = mockHttp.ToHttpClient()) { + var signhostApiClient = new SignhostApiClient(settings, httpClient); - mockHttp.VerifyNoOutstandingExpectation(); + await signhostApiClient.AddOrReplaceFileToTransaction(new MemoryStream(), "transaction Id", "file Id"); } - [Fact] - public async Task when_AddOrReplaceFileToTransaction_with_sha512_is_called_default_digest_is_sha512() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Put, "http://localhost/api/transaction/transaction Id/file/file Id") - .WithHeaders("Digest", "SHA-512=z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYXysP+DGNKHfuwvY7kxvUdBeoGlODJ6+SfaPg==") - .Respond(HttpStatusCode.OK); - - using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignhostApiClient(settings, httpClient); - - await signhostApiClient.AddOrReplaceFileToTransactionAsync( - new MemoryStream(), - "transaction Id", - "file Id", - new FileUploadOptions{ - DigestOptions = new FileDigestOptions - { - DigestHashAlgorithm = "SHA-512" - } - }); - } + mockHttp.VerifyNoOutstandingExpectation(); + } - mockHttp.VerifyNoOutstandingExpectation(); + [Fact] + public async Task when_AddOrReplaceFileToTransaction_with_sha512_is_called_default_digest_is_sha512() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Put, "http://localhost/api/transaction/transaction Id/file/file Id") + .WithHeaders("Digest", "SHA-512=z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYXysP+DGNKHfuwvY7kxvUdBeoGlODJ6+SfaPg==") + .Respond(HttpStatusCode.OK); + + using (var httpClient = mockHttp.ToHttpClient()) { + var signhostApiClient = new SignhostApiClient(settings, httpClient); + + await signhostApiClient.AddOrReplaceFileToTransactionAsync( + new MemoryStream(), + "transaction Id", + "file Id", + new FileUploadOptions{ + DigestOptions = new FileDigestOptions + { + DigestHashAlgorithm = "SHA-512" + } + }); } - [Fact] - public async Task when_AddOrReplaceFileToTransaction_with_digest_value_is_used_as_is() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Put, "http://localhost/api/transaction/transaction Id/file/file Id") - .WithHeaders("Digest", "SHA-1=AAEC") - .Respond(HttpStatusCode.OK); - - using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignhostApiClient(settings, httpClient); - - await signhostApiClient.AddOrReplaceFileToTransactionAsync( - new MemoryStream(), - "transaction Id", - "file Id", - new FileUploadOptions - { - DigestOptions = new FileDigestOptions - { - DigestHashAlgorithm = "SHA-1", - DigestHashValue = new byte[] { 0x00, 0x01, 0x02 } - } - }); - } + mockHttp.VerifyNoOutstandingExpectation(); + } - mockHttp.VerifyNoOutstandingExpectation(); + [Fact] + public async Task when_AddOrReplaceFileToTransaction_with_digest_value_is_used_as_is() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Put, "http://localhost/api/transaction/transaction Id/file/file Id") + .WithHeaders("Digest", "SHA-1=AAEC") + .Respond(HttpStatusCode.OK); + + using (var httpClient = mockHttp.ToHttpClient()) { + var signhostApiClient = new SignhostApiClient(settings, httpClient); + + await signhostApiClient.AddOrReplaceFileToTransactionAsync( + new MemoryStream(), + "transaction Id", + "file Id", + new FileUploadOptions + { + DigestOptions = new FileDigestOptions + { + DigestHashAlgorithm = "SHA-1", + DigestHashValue = new byte[] { 0x00, 0x01, 0x02 } + } + }); } - [Fact] - public async Task when_StartTransaction_is_called_then_we_should_have_called_the_transaction_put_once() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp.Expect("http://localhost/api/transaction/transaction Id/start") - .Respond(HttpStatusCode.NoContent); + mockHttp.VerifyNoOutstandingExpectation(); + } - using (var httpClient = mockHttp.ToHttpClient()) { + [Fact] + public async Task when_StartTransaction_is_called_then_we_should_have_called_the_transaction_put_once() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp.Expect("http://localhost/api/transaction/transaction Id/start") + .Respond(HttpStatusCode.NoContent); - var signhostApiClient = new SignhostApiClient(settings, httpClient); + using (var httpClient = mockHttp.ToHttpClient()) { - await signhostApiClient.StartTransactionAsync("transaction Id"); - } + var signhostApiClient = new SignhostApiClient(settings, httpClient); - mockHttp.VerifyNoOutstandingExpectation(); + await signhostApiClient.StartTransactionAsync("transaction Id"); } - [Fact] - public async Task when_GetReceipt_is_called_then_we_should_have_called_the_filereceipt_get_once() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp.Expect("http://localhost/api/file/receipt/transaction ID") - .Respond(HttpStatusCode.OK); + mockHttp.VerifyNoOutstandingExpectation(); + } - using (var httpClient = mockHttp.ToHttpClient()) { - var signhostApiClient = new SignhostApiClient(settings, httpClient); + [Fact] + public async Task when_GetReceipt_is_called_then_we_should_have_called_the_filereceipt_get_once() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp.Expect("http://localhost/api/file/receipt/transaction ID") + .Respond(HttpStatusCode.OK); - var receipt = await signhostApiClient.GetReceiptAsync("transaction ID"); - } + using (var httpClient = mockHttp.ToHttpClient()) { + var signhostApiClient = new SignhostApiClient(settings, httpClient); - mockHttp.VerifyNoOutstandingExpectation(); + var receipt = await signhostApiClient.GetReceiptAsync("transaction ID"); } - [Fact] - public async Task when_GetDocument_is_called_then_we_should_have_called_the_file_get_once() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp.Expect(HttpMethod.Get, "http://localhost/api/transaction/*/file/file Id") - .Respond(HttpStatusCode.OK, new StringContent(string.Empty)); + mockHttp.VerifyNoOutstandingExpectation(); + } - using (var httpClient = mockHttp.ToHttpClient()) { + [Fact] + public async Task when_GetDocument_is_called_then_we_should_have_called_the_file_get_once() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp.Expect(HttpMethod.Get, "http://localhost/api/transaction/*/file/file Id") + .Respond(HttpStatusCode.OK, new StringContent(string.Empty)); - var signhostApiClient = new SignhostApiClient(settings, httpClient); + using (var httpClient = mockHttp.ToHttpClient()) { - var document = await signhostApiClient.GetDocumentAsync("transaction Id", "file Id"); - } + var signhostApiClient = new SignhostApiClient(settings, httpClient); - mockHttp.VerifyNoOutstandingExpectation(); + var document = await signhostApiClient.GetDocumentAsync("transaction Id", "file Id"); } - [Fact] - public async Task When_a_transaction_json_is_returned_it_is_deserialized_correctly() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp.Expect(HttpMethod.Post, "http://localhost/api/transaction") - .Respond(HttpStatusCode.OK, new StringContent(JsonResources.TransactionSingleSignerJson)); + mockHttp.VerifyNoOutstandingExpectation(); + } - using (var httpClient = mockHttp.ToHttpClient()) { + [Fact] + public async Task When_a_transaction_json_is_returned_it_is_deserialized_correctly() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp.Expect(HttpMethod.Post, "http://localhost/api/transaction") + .Respond(HttpStatusCode.OK, new StringContent(JsonResources.TransactionSingleSignerJson)); - var signhostApiClient = new SignhostApiClient(settings, httpClient); + using (var httpClient = mockHttp.ToHttpClient()) { - var result = await signhostApiClient.CreateTransactionAsync(new Transaction - { - Signers = new List{ - new Signer + var signhostApiClient = new SignhostApiClient(settings, httpClient); + + var result = await signhostApiClient.CreateTransactionAsync(new Transaction + { + Signers = new List{ + new Signer + { + Verifications = new List { - Verifications = new List + new PhoneNumberVerification { - new PhoneNumberVerification - { - Number = "31615087075" - } + Number = "31615087075" } } } - }); + } + }); + + result.Id.Should().Be("50262c3f-9744-45bf-a4c6-8a3whatever"); + result.CanceledDateTime.Should().HaveYear(2017); + result.Status.Should().Be(TransactionStatus.WaitingForDocument); + result.Signers.Should().HaveCount(1); + result.Receivers.Should().HaveCount(0); + result.Reference.Should().Be("Contract #123"); + result.SignRequestMode.Should().Be(2); + result.DaysToExpire.Should().Be(14); + result.Signers[0].Id.Should().Be("Signer1"); + result.Signers[0].Email.Should().Be("test1@example.com"); + result.Signers[0].Verifications.Should().HaveCount(1); + result.Signers[0].Verifications[0].Should().BeOfType() + .And.Subject.Should().BeEquivalentTo(new PhoneNumberVerification { + Number = "+31615123456" + }); + result.Signers[0].Activities.Should().HaveCount(3); + result.Signers[0].Activities[0].Should().BeEquivalentTo(new Activity + { + Id = "Activity1", + Code = ActivityType.Opened, + CreatedDateTime = DateTimeOffset.Parse("2017-05-31T22:15:17.6409005+02:00") + }); + } - result.Id.Should().Be("50262c3f-9744-45bf-a4c6-8a3whatever"); - result.CanceledDateTime.Should().HaveYear(2017); - result.Status.Should().Be(TransactionStatus.WaitingForDocument); - result.Signers.Should().HaveCount(1); - result.Receivers.Should().HaveCount(0); - result.Reference.Should().Be("Contract #123"); - result.SignRequestMode.Should().Be(2); - result.DaysToExpire.Should().Be(14); - result.Signers[0].Id.Should().Be("Signer1"); - result.Signers[0].Email.Should().Be("test1@example.com"); - result.Signers[0].Verifications.Should().HaveCount(1); - result.Signers[0].Verifications[0].Should().BeOfType() - .And.Subject.Should().BeEquivalentTo(new PhoneNumberVerification { - Number = "+31615123456" - }); - result.Signers[0].Activities.Should().HaveCount(3); - result.Signers[0].Activities[0].Should().BeEquivalentTo(new Activity - { - Id = "Activity1", - Code = ActivityType.Opened, - CreatedDateTime = DateTimeOffset.Parse("2017-05-31T22:15:17.6409005+02:00") - }); + mockHttp.VerifyNoOutstandingExpectation(); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public async Task When_a_complete_transaction_flow_is_created_headers_are_not_set_multiple_times( + bool isOauth) + { + MockedRequest AddHeaders(MockedRequest request) + { + if (!isOauth) { + request = request.WithHeaders("Authorization", "APIKey Usertoken"); } - mockHttp.VerifyNoOutstandingExpectation(); + return request + .WithHeaders("Application", "APPKey AppKey") + .WithHeaders("X-Custom", "test"); } - [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task When_a_complete_transaction_flow_is_created_headers_are_not_set_multiple_times( - bool isOauth) - { - MockedRequest AddHeaders(MockedRequest request) - { - if (!isOauth) { - request = request.WithHeaders("Authorization", "APIKey Usertoken"); - } - - return request - .WithHeaders("Application", "APPKey AppKey") - .WithHeaders("X-Custom", "test"); + var mockHttp = new MockHttpMessageHandler(); + AddHeaders(mockHttp.Expect(HttpMethod.Post, "http://localhost/api/transaction")) + .Respond(new StringContent(JsonResources.TransactionSingleSignerJson)); + AddHeaders(mockHttp.Expect(HttpMethod.Put, "http://localhost/api/transaction/*/file/somefileid")) + .Respond(HttpStatusCode.Accepted, new StringContent(JsonResources.AddOrReplaceFileMetaToTransaction)); + AddHeaders(mockHttp.Expect(HttpMethod.Put, "http://localhost/api/transaction/*/file/somefileid")) + .Respond(HttpStatusCode.Created); + AddHeaders(mockHttp.Expect(HttpMethod.Put, "http://localhost/api/transaction/*/start")) + .Respond(HttpStatusCode.NoContent); + + using (var httpClient = mockHttp.ToHttpClient()) { + var clientSettings = isOauth ? oauthSettings : settings; + clientSettings.AddHeader = add => add("X-Custom", "test"); + var signhostApiClient = new SignhostApiClient(clientSettings, httpClient); + + var result = await signhostApiClient.CreateTransactionAsync(new Transaction()); + await signhostApiClient.AddOrReplaceFileMetaToTransactionAsync(new FileMeta(), result.Id, "somefileid"); + using (Stream file = System.IO.File.Create("unittestdocument.pdf")) { + await signhostApiClient.AddOrReplaceFileToTransaction(file, result.Id, "somefileid"); } + await signhostApiClient.StartTransactionAsync(result.Id); + } - var mockHttp = new MockHttpMessageHandler(); - AddHeaders(mockHttp.Expect(HttpMethod.Post, "http://localhost/api/transaction")) - .Respond(new StringContent(JsonResources.TransactionSingleSignerJson)); - AddHeaders(mockHttp.Expect(HttpMethod.Put, "http://localhost/api/transaction/*/file/somefileid")) - .Respond(HttpStatusCode.Accepted, new StringContent(JsonResources.AddOrReplaceFileMetaToTransaction)); - AddHeaders(mockHttp.Expect(HttpMethod.Put, "http://localhost/api/transaction/*/file/somefileid")) - .Respond(HttpStatusCode.Created); - AddHeaders(mockHttp.Expect(HttpMethod.Put, "http://localhost/api/transaction/*/start")) - .Respond(HttpStatusCode.NoContent); - - using (var httpClient = mockHttp.ToHttpClient()) { - var clientSettings = isOauth ? oauthSettings : settings; - clientSettings.AddHeader = add => add("X-Custom", "test"); - var signhostApiClient = new SignhostApiClient(clientSettings, httpClient); - - var result = await signhostApiClient.CreateTransactionAsync(new Transaction()); - await signhostApiClient.AddOrReplaceFileMetaToTransactionAsync(new FileMeta(), result.Id, "somefileid"); - using (Stream file = System.IO.File.Create("unittestdocument.pdf")) { - await signhostApiClient.AddOrReplaceFileToTransaction(file, result.Id, "somefileid"); - } - await signhostApiClient.StartTransactionAsync(result.Id); - } + mockHttp.VerifyNoOutstandingExpectation(); + mockHttp.VerifyNoOutstandingRequest(); + } - mockHttp.VerifyNoOutstandingExpectation(); - mockHttp.VerifyNoOutstandingRequest(); - } + [Fact] + public async Task When_a_minimal_response_is_retrieved_list_and_dictionaries_are_not_null() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Get, "http://localhost/api/transaction/c487be92-0255-40c7-bd7d-20805a65e7d9") + .Respond(new StringContent(JsonResources.MinimalTransactionResponse)); - [Fact] - public async Task When_a_minimal_response_is_retrieved_list_and_dictionaries_are_not_null() + using (var httpClient = mockHttp.ToHttpClient()) { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "http://localhost/api/transaction/c487be92-0255-40c7-bd7d-20805a65e7d9") - .Respond(new StringContent(JsonResources.MinimalTransactionResponse)); + var signhostApiClient = new SignhostApiClient(settings, httpClient); - using (var httpClient = mockHttp.ToHttpClient()) - { - var signhostApiClient = new SignhostApiClient(settings, httpClient); + var result = await signhostApiClient.GetTransactionAsync("c487be92-0255-40c7-bd7d-20805a65e7d9"); - var result = await signhostApiClient.GetTransactionAsync("c487be92-0255-40c7-bd7d-20805a65e7d9"); - - result.Signers.Should().BeEmpty(); - result.Receivers.Should().BeEmpty(); - result.Files.Should().BeEmpty(); - } + result.Signers.Should().BeEmpty(); + result.Receivers.Should().BeEmpty(); + result.Files.Should().BeEmpty(); } } } diff --git a/src/SignhostAPIClient.Tests/SignhostApiReceiverTests.cs b/src/SignhostAPIClient.Tests/SignhostApiReceiverTests.cs index 198f95bf..4bab87eb 100644 --- a/src/SignhostAPIClient.Tests/SignhostApiReceiverTests.cs +++ b/src/SignhostAPIClient.Tests/SignhostApiReceiverTests.cs @@ -4,76 +4,75 @@ using System.Collections.Generic; using SignhostAPIClient.Tests.JSON; -namespace Signhost.APIClient.Rest.Tests +namespace Signhost.APIClient.Rest.Tests; + +public class SignhostApiReceiverTests { - public class SignhostApiReceiverTests - { - private SignhostApiReceiverSettings receiverSettings = new SignhostApiReceiverSettings("SharedSecret"); + private SignhostApiReceiverSettings receiverSettings = new SignhostApiReceiverSettings("SharedSecret"); - [Fact] - public void when_IsPostbackChecksumValid_is_called_with_valid_postback_in_body_then_true_is_returned() - { - // Arrange - IDictionary headers = new Dictionary { { "Content-Type", new[] { "application/json" } } }; - string body = JsonResources.MockPostbackValid; + [Fact] + public void when_IsPostbackChecksumValid_is_called_with_valid_postback_in_body_then_true_is_returned() + { + // Arrange + IDictionary headers = new Dictionary { { "Content-Type", new[] { "application/json" } } }; + string body = JsonResources.MockPostbackValid; - // Act - SignhostApiReceiver signhostApiReceiver = new SignhostApiReceiver(receiverSettings); - bool result = signhostApiReceiver.IsPostbackChecksumValid(headers, body, out Transaction transaction); + // Act + SignhostApiReceiver signhostApiReceiver = new SignhostApiReceiver(receiverSettings); + bool result = signhostApiReceiver.IsPostbackChecksumValid(headers, body, out Transaction transaction); - // Assert - result.Should().BeTrue(); - } + // Assert + result.Should().BeTrue(); + } - [Fact] - public void when_IsPostbackChecksumValid_is_called_with_invalid_postback_in_body_then_false_is_returned() - { - // Arrange - IDictionary headers = new Dictionary { { "Content-Type", new[] { "application/json" } } }; - string body = JsonResources.MockPostbackInvalid; + [Fact] + public void when_IsPostbackChecksumValid_is_called_with_invalid_postback_in_body_then_false_is_returned() + { + // Arrange + IDictionary headers = new Dictionary { { "Content-Type", new[] { "application/json" } } }; + string body = JsonResources.MockPostbackInvalid; - // Act - SignhostApiReceiver signhostApiReceiver = new SignhostApiReceiver(receiverSettings); - bool result = signhostApiReceiver.IsPostbackChecksumValid(headers, body, out Transaction transaction); + // Act + SignhostApiReceiver signhostApiReceiver = new SignhostApiReceiver(receiverSettings); + bool result = signhostApiReceiver.IsPostbackChecksumValid(headers, body, out Transaction transaction); - // Assert - result.Should().BeFalse(); - } + // Assert + result.Should().BeFalse(); + } - [Fact] - public void when_IsPostbackChecksumValid_is_called_with_valid_postback_in_header_then_true_is_returned() - { - // Arrange - IDictionary headers = new Dictionary { - { "Content-Type", new[] { "application/json" }}, - {"Checksum", new[] {"cdc09eee2ed6df2846dcc193aedfef59f2834f8d"}} - }; - string body = JsonResources.MockPostbackValid; + [Fact] + public void when_IsPostbackChecksumValid_is_called_with_valid_postback_in_header_then_true_is_returned() + { + // Arrange + IDictionary headers = new Dictionary { + { "Content-Type", new[] { "application/json" }}, + {"Checksum", new[] {"cdc09eee2ed6df2846dcc193aedfef59f2834f8d"}} + }; + string body = JsonResources.MockPostbackValid; - // Act - SignhostApiReceiver signhostApiReceiver = new SignhostApiReceiver(receiverSettings); - bool result = signhostApiReceiver.IsPostbackChecksumValid(headers, body, out Transaction transaction); + // Act + SignhostApiReceiver signhostApiReceiver = new SignhostApiReceiver(receiverSettings); + bool result = signhostApiReceiver.IsPostbackChecksumValid(headers, body, out Transaction transaction); - // Assert - result.Should().BeTrue(); - } + // Assert + result.Should().BeTrue(); + } - [Fact] - public void when_IsPostbackChecksumValid_is_called_with_invalid_postback_in_header_then_false_is_returned() - { - // Arrange - IDictionary headers = new Dictionary { - { "Content-Type", new[] { "application/json" }}, - {"Checksum", new[] {"70dda90616f744797972c0d2f787f86643a60c83"}} - }; - string body = JsonResources.MockPostbackValid; + [Fact] + public void when_IsPostbackChecksumValid_is_called_with_invalid_postback_in_header_then_false_is_returned() + { + // Arrange + IDictionary headers = new Dictionary { + { "Content-Type", new[] { "application/json" }}, + {"Checksum", new[] {"70dda90616f744797972c0d2f787f86643a60c83"}} + }; + string body = JsonResources.MockPostbackValid; - // Act - SignhostApiReceiver signhostApiReceiver = new SignhostApiReceiver(receiverSettings); - bool result = signhostApiReceiver.IsPostbackChecksumValid(headers, body, out Transaction transaction); + // Act + SignhostApiReceiver signhostApiReceiver = new SignhostApiReceiver(receiverSettings); + bool result = signhostApiReceiver.IsPostbackChecksumValid(headers, body, out Transaction transaction); - // Assert - result.Should().BeFalse(); - } + // Assert + result.Should().BeFalse(); } } diff --git a/src/SignhostAPIClient/Rest/ApiResponse.cs b/src/SignhostAPIClient/Rest/ApiResponse.cs index 00db9de5..bb984c42 100644 --- a/src/SignhostAPIClient/Rest/ApiResponse.cs +++ b/src/SignhostAPIClient/Rest/ApiResponse.cs @@ -1,29 +1,28 @@ using System.Net; using System.Net.Http; -namespace Signhost.APIClient.Rest +namespace Signhost.APIClient.Rest; + +public class ApiResponse { - public class ApiResponse - { - private readonly HttpResponseMessage httpResponse; + private readonly HttpResponseMessage httpResponse; - public ApiResponse(HttpResponseMessage httpResponse, TValue value) - { - this.httpResponse = httpResponse; - this.Value = value; - } + public ApiResponse(HttpResponseMessage httpResponse, TValue value) + { + this.httpResponse = httpResponse; + this.Value = value; + } - public TValue Value { get; private set; } + public TValue Value { get; private set; } - public HttpStatusCode HttpStatusCode => httpResponse.StatusCode; + public HttpStatusCode HttpStatusCode => httpResponse.StatusCode; - public void EnsureAvailableStatusCode() - { - if (HttpStatusCode == HttpStatusCode.Gone) { - throw new ErrorHandling.GoneException( - httpResponse.ReasonPhrase, - Value); - } + public void EnsureAvailableStatusCode() + { + if (HttpStatusCode == HttpStatusCode.Gone) { + throw new ErrorHandling.GoneException( + httpResponse.ReasonPhrase, + Value); } } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/Activity.cs b/src/SignhostAPIClient/Rest/DataObjects/Activity.cs index dccf8caa..a8d82fb9 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/Activity.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/Activity.cs @@ -1,15 +1,14 @@ using System; -namespace Signhost.APIClient.Rest.DataObjects +namespace Signhost.APIClient.Rest.DataObjects; + +public class Activity { - public class Activity - { - public string Id { get; set; } + public string Id { get; set; } - public ActivityType Code { get; set; } + public ActivityType Code { get; set; } - public string Info { get; set; } + public string Info { get; set; } - public DateTimeOffset CreatedDateTime { get; set; } - } + public DateTimeOffset CreatedDateTime { get; set; } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/ActivityType.cs b/src/SignhostAPIClient/Rest/DataObjects/ActivityType.cs index 2da49276..ecd9aad2 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/ActivityType.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/ActivityType.cs @@ -1,135 +1,134 @@ -namespace Signhost.APIClient.Rest.DataObjects +namespace Signhost.APIClient.Rest.DataObjects; + +/// +/// type. +/// +public enum ActivityType { /// - /// type. - /// - public enum ActivityType - { - /// - /// The invitation mail was sent. - /// - InvitationSent = 101, - - /// - /// The invitation mail was received. - /// - InvitationReceived = 102, - - /// - /// The sign url was opened. - /// - Opened = 103, - - /// - /// An invitation reminder mail was sent. - /// - InvitationReminderResent = 104, - - /// - /// The document was opened. - /// The contains the fileId of the opened - /// document. - /// - DocumentOpened = 105, - - /// - /// Consumer Signing identity approved. - /// - IdentityApproved = 110, - - /// - /// Consumer Signing identity failed. - /// - IdentityFailed = 111, - - /// - /// Cancelled. - /// - Cancelled = 201, - - /// - /// The signer rejected the sign request. - /// - Rejected = 202, - - /// - /// The signer signed the documents. - /// - Signed = 203, - - /// - /// The signer delegated signing to a different signer. - /// - SignerDelegated = 204, - - /// - /// Signed document sent. - /// - SignedDocumentSent = 301, - - /// - /// Signed document opened. - /// - SignedDocumentOpened = 302, - - /// - /// Signed document downloaded. - /// - SignedDocumentDownloaded = 303, - - /// - /// Receipt sent. - /// - ReceiptSent = 401, - - /// - /// Receipt opened. - /// - ReceiptOpened = 402, - - /// - /// Receipt downloaded. - /// - ReceiptDownloaded = 403, - - /// - /// Finished. - /// - Finished = 500, - - /// - /// Deleted. - /// - Deleted = 600, - - /// - /// Expired. - /// - Expired = 700, - - /// - /// Email bounce - hard. - /// - EmailBounceHard = 901, - - /// - /// Email bounce - soft. - /// - EmailBounceSoft = 902, - - /// - /// Email bounce - blocked. - /// - EmailBounceBlocked = 903, - - /// - /// Email bounce - undetermined. - /// - EmailBounceUndetermined = 904, - - /// - /// Operation failed. - /// - Failed = 999, - } + /// The invitation mail was sent. + /// + InvitationSent = 101, + + /// + /// The invitation mail was received. + /// + InvitationReceived = 102, + + /// + /// The sign url was opened. + /// + Opened = 103, + + /// + /// An invitation reminder mail was sent. + /// + InvitationReminderResent = 104, + + /// + /// The document was opened. + /// The contains the fileId of the opened + /// document. + /// + DocumentOpened = 105, + + /// + /// Consumer Signing identity approved. + /// + IdentityApproved = 110, + + /// + /// Consumer Signing identity failed. + /// + IdentityFailed = 111, + + /// + /// Cancelled. + /// + Cancelled = 201, + + /// + /// The signer rejected the sign request. + /// + Rejected = 202, + + /// + /// The signer signed the documents. + /// + Signed = 203, + + /// + /// The signer delegated signing to a different signer. + /// + SignerDelegated = 204, + + /// + /// Signed document sent. + /// + SignedDocumentSent = 301, + + /// + /// Signed document opened. + /// + SignedDocumentOpened = 302, + + /// + /// Signed document downloaded. + /// + SignedDocumentDownloaded = 303, + + /// + /// Receipt sent. + /// + ReceiptSent = 401, + + /// + /// Receipt opened. + /// + ReceiptOpened = 402, + + /// + /// Receipt downloaded. + /// + ReceiptDownloaded = 403, + + /// + /// Finished. + /// + Finished = 500, + + /// + /// Deleted. + /// + Deleted = 600, + + /// + /// Expired. + /// + Expired = 700, + + /// + /// Email bounce - hard. + /// + EmailBounceHard = 901, + + /// + /// Email bounce - soft. + /// + EmailBounceSoft = 902, + + /// + /// Email bounce - blocked. + /// + EmailBounceBlocked = 903, + + /// + /// Email bounce - undetermined. + /// + EmailBounceUndetermined = 904, + + /// + /// Operation failed. + /// + Failed = 999, } diff --git a/src/SignhostAPIClient/Rest/DataObjects/ConsentVerification.cs b/src/SignhostAPIClient/Rest/DataObjects/ConsentVerification.cs index 00289618..6a045ce3 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/ConsentVerification.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/ConsentVerification.cs @@ -1,10 +1,9 @@ -namespace Signhost.APIClient.Rest.DataObjects +namespace Signhost.APIClient.Rest.DataObjects; + +/// +/// Adds a consent verification screen +/// +public class ConsentVerification + : IVerification { - /// - /// Adds a consent verification screen - /// - public class ConsentVerification - : IVerification - { - } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/DeleteTransactionOptions.cs b/src/SignhostAPIClient/Rest/DataObjects/DeleteTransactionOptions.cs index 19ad295d..ae3ecc5a 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/DeleteTransactionOptions.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/DeleteTransactionOptions.cs @@ -1,16 +1,15 @@ -namespace Signhost.APIClient.Rest.DataObjects +namespace Signhost.APIClient.Rest.DataObjects; + +public class DeleteTransactionOptions { - public class DeleteTransactionOptions - { - /// - /// Gets or sets a value indicating whether - /// e-mail notifications should be send to the awaiting signers. - /// - public bool SendNotifications { get; set; } + /// + /// Gets or sets a value indicating whether + /// e-mail notifications should be send to the awaiting signers. + /// + public bool SendNotifications { get; set; } - /// - /// Gets or sets the reason of cancellation. - /// - public string Reason { get; set; } - } + /// + /// Gets or sets the reason of cancellation. + /// + public string Reason { get; set; } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/DigidVerification.cs b/src/SignhostAPIClient/Rest/DataObjects/DigidVerification.cs index 3de0acfc..798d37c0 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/DigidVerification.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/DigidVerification.cs @@ -1,8 +1,7 @@ -namespace Signhost.APIClient.Rest.DataObjects +namespace Signhost.APIClient.Rest.DataObjects; + +public class DigidVerification + : IVerification { - public class DigidVerification - : IVerification - { - public string Bsn { get; set; } - } + public string Bsn { get; set; } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/EidasLoginVerification.cs b/src/SignhostAPIClient/Rest/DataObjects/EidasLoginVerification.cs index 18ac4afa..3d54b0ef 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/EidasLoginVerification.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/EidasLoginVerification.cs @@ -3,43 +3,42 @@ using System.Text.Json.Serialization; using Signhost.APIClient.Rest.JsonConverters; -namespace Signhost.APIClient.Rest.DataObjects +namespace Signhost.APIClient.Rest.DataObjects; + +/// +/// Verification object for eIDAS. +/// +public class EidasLoginVerification + : IVerification { /// - /// Verification object for eIDAS. + /// Gets or sets the uid. /// - public class EidasLoginVerification - : IVerification - { - /// - /// Gets or sets the uid. - /// - public string Uid { get; set; } + public string Uid { get; set; } - /// - /// Gets or sets the level. - /// - [JsonConverter(typeof(LevelEnumConverter))] - public Level? Level { get; set; } + /// + /// Gets or sets the level. + /// + [JsonConverter(typeof(LevelEnumConverter))] + public Level? Level { get; set; } - /// - /// Gets or sets the first name. - /// - public string FirstName { get; set; } + /// + /// Gets or sets the first name. + /// + public string FirstName { get; set; } - /// - /// Gets or sets the last name. - /// - public string LastName { get; set; } + /// + /// Gets or sets the last name. + /// + public string LastName { get; set; } - /// - /// Gets or sets the date of birth. - /// - public DateTime? DateOfBirth { get; set; } + /// + /// Gets or sets the date of birth. + /// + public DateTime? DateOfBirth { get; set; } - /// - /// Gets or sets the eIDAS attributes. - /// - public IDictionary Attributes { get; set; } - } + /// + /// Gets or sets the eIDAS attributes. + /// + public IDictionary Attributes { get; set; } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/Field.cs b/src/SignhostAPIClient/Rest/DataObjects/Field.cs index 2c2482bc..1c83d030 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/Field.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/Field.cs @@ -1,11 +1,10 @@ -namespace Signhost.APIClient.Rest.DataObjects +namespace Signhost.APIClient.Rest.DataObjects; + +public class Field { - public class Field - { - public string Type { get; set; } + public string Type { get; set; } - public string Value { get; set; } + public string Value { get; set; } - public Location Location { get; set; } - } + public Location Location { get; set; } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/FileEntry.cs b/src/SignhostAPIClient/Rest/DataObjects/FileEntry.cs index 5a3cc1bf..f1565e5e 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/FileEntry.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/FileEntry.cs @@ -1,11 +1,10 @@ using System.Collections.Generic; -namespace Signhost.APIClient.Rest.DataObjects +namespace Signhost.APIClient.Rest.DataObjects; + +public class FileEntry { - public class FileEntry - { - public IList Links { get; set; } + public IList Links { get; set; } - public string DisplayName { get; set; } - } + public string DisplayName { get; set; } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/FileLink.cs b/src/SignhostAPIClient/Rest/DataObjects/FileLink.cs index d1fb0323..f503d5ae 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/FileLink.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/FileLink.cs @@ -1,11 +1,10 @@ -namespace Signhost.APIClient.Rest.DataObjects +namespace Signhost.APIClient.Rest.DataObjects; + +public class FileLink { - public class FileLink - { - public string Rel { get; set; } + public string Rel { get; set; } - public string Type { get; set; } + public string Type { get; set; } - public string Link { get; set; } - } + public string Link { get; set; } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/FileMeta.cs b/src/SignhostAPIClient/Rest/DataObjects/FileMeta.cs index 6cbda5a0..b20b72e5 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/FileMeta.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/FileMeta.cs @@ -1,27 +1,26 @@ using System.Collections.Generic; using System.Text.Json.Serialization; -namespace Signhost.APIClient.Rest.DataObjects +namespace Signhost.APIClient.Rest.DataObjects; + +public class FileMeta { - public class FileMeta - { - public int? DisplayOrder { get; set; } + public int? DisplayOrder { get; set; } - public string DisplayName { get; set; } + public string DisplayName { get; set; } - public string Description { get; set; } + public string Description { get; set; } - public IDictionary Signers { get; set; } + public IDictionary Signers { get; set; } - public IDictionary> FormSets { get; set; } + public IDictionary> FormSets { get; set; } - /// - /// Gets or sets whether to use the scribble signature as a paraph - /// on each non-signed page. - /// Don't use this setting unless you are really sure this is what you - /// want and know the side-effects. - /// - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public bool? SetParaph { get; set; } - } + /// + /// Gets or sets whether to use the scribble signature as a paraph + /// on each non-signed page. + /// Don't use this setting unless you are really sure this is what you + /// want and know the side-effects. + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public bool? SetParaph { get; set; } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/FileSignerMeta.cs b/src/SignhostAPIClient/Rest/DataObjects/FileSignerMeta.cs index 1c39aa83..7adfc404 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/FileSignerMeta.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/FileSignerMeta.cs @@ -1,7 +1,6 @@ -namespace Signhost.APIClient.Rest.DataObjects +namespace Signhost.APIClient.Rest.DataObjects; + +public class FileSignerMeta { - public class FileSignerMeta - { - public string[] FormSets { get; set; } - } + public string[] FormSets { get; set; } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/IPAddressVerification.cs b/src/SignhostAPIClient/Rest/DataObjects/IPAddressVerification.cs index cb68fcda..b1fb67f3 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/IPAddressVerification.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/IPAddressVerification.cs @@ -1,14 +1,13 @@ -namespace Signhost.APIClient.Rest.DataObjects +namespace Signhost.APIClient.Rest.DataObjects; + +/// +/// Adds a consent verification screen +/// +public class IPAddressVerification + : IVerification { /// - /// Adds a consent verification screen + /// Gets or sets the IP Address used by the signer while signing the documents. /// - public class IPAddressVerification - : IVerification - { - /// - /// Gets or sets the IP Address used by the signer while signing the documents. - /// - public string IPAddress { get; set; } - } + public string IPAddress { get; set; } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/IVerification.cs b/src/SignhostAPIClient/Rest/DataObjects/IVerification.cs index a2712718..6a18aa03 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/IVerification.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/IVerification.cs @@ -1,21 +1,20 @@ using System.Text.Json.Serialization; -namespace Signhost.APIClient.Rest.DataObjects +namespace Signhost.APIClient.Rest.DataObjects; + +[JsonPolymorphic(TypeDiscriminatorPropertyName = "Type")] +[JsonDerivedType(typeof(ConsentVerification), "Consent")] +[JsonDerivedType(typeof(DigidVerification), "DigiD")] +[JsonDerivedType(typeof(EidasLoginVerification), "eIDAS Login")] +[JsonDerivedType(typeof(IdealVerification), "iDeal")] +[JsonDerivedType(typeof(IdinVerification), "iDIN")] +[JsonDerivedType(typeof(IPAddressVerification), "IPAddress")] +[JsonDerivedType(typeof(ItsmeIdentificationVerification), "itsme Identification")] +[JsonDerivedType(typeof(ItsmeSignVerification), "itsme sign")] +[JsonDerivedType(typeof(PhoneNumberVerification), "PhoneNumber")] +[JsonDerivedType(typeof(ScribbleVerification), "Scribble")] +[JsonDerivedType(typeof(SigningCertificateVerification), "SigningCertificate")] +[JsonDerivedType(typeof(SurfnetVerification), "SURFnet")] +public interface IVerification { - [JsonPolymorphic(TypeDiscriminatorPropertyName = "Type")] - [JsonDerivedType(typeof(ConsentVerification), "Consent")] - [JsonDerivedType(typeof(DigidVerification), "DigiD")] - [JsonDerivedType(typeof(EidasLoginVerification), "eIDAS Login")] - [JsonDerivedType(typeof(IdealVerification), "iDeal")] - [JsonDerivedType(typeof(IdinVerification), "iDIN")] - [JsonDerivedType(typeof(IPAddressVerification), "IPAddress")] - [JsonDerivedType(typeof(ItsmeIdentificationVerification), "itsme Identification")] - [JsonDerivedType(typeof(ItsmeSignVerification), "itsme sign")] - [JsonDerivedType(typeof(PhoneNumberVerification), "PhoneNumber")] - [JsonDerivedType(typeof(ScribbleVerification), "Scribble")] - [JsonDerivedType(typeof(SigningCertificateVerification), "SigningCertificate")] - [JsonDerivedType(typeof(SurfnetVerification), "SURFnet")] - public interface IVerification - { - } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/IdealVerification.cs b/src/SignhostAPIClient/Rest/DataObjects/IdealVerification.cs index 5267f284..55f1bc95 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/IdealVerification.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/IdealVerification.cs @@ -1,12 +1,11 @@ -namespace Signhost.APIClient.Rest.DataObjects +namespace Signhost.APIClient.Rest.DataObjects; + +public class IdealVerification + : IVerification { - public class IdealVerification - : IVerification - { - public string Iban { get; set; } + public string Iban { get; set; } - public string AccountHolderName { get; set; } + public string AccountHolderName { get; set; } - public string AccountHolderCity { get; set; } - } + public string AccountHolderCity { get; set; } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/IdinVerification.cs b/src/SignhostAPIClient/Rest/DataObjects/IdinVerification.cs index 38adcd92..150f398b 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/IdinVerification.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/IdinVerification.cs @@ -1,19 +1,18 @@ using System; using System.Collections.Generic; -namespace Signhost.APIClient.Rest.DataObjects +namespace Signhost.APIClient.Rest.DataObjects; + +public class IdinVerification + : IVerification { - public class IdinVerification - : IVerification - { - public string AccountHolderName { get; set; } + public string AccountHolderName { get; set; } - public string AccountHolderAddress1 { get; set; } + public string AccountHolderAddress1 { get; set; } - public string AccountHolderAddress2 { get; set; } + public string AccountHolderAddress2 { get; set; } - public DateTime AccountHolderDateOfBirth { get; set; } + public DateTime AccountHolderDateOfBirth { get; set; } - public IDictionary Attributes { get; set; } - } + public IDictionary Attributes { get; set; } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/ItsmeIdentificationVerification.cs b/src/SignhostAPIClient/Rest/DataObjects/ItsmeIdentificationVerification.cs index eeae90b8..914665e4 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/ItsmeIdentificationVerification.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/ItsmeIdentificationVerification.cs @@ -1,14 +1,13 @@ -namespace Signhost.APIClient.Rest.DataObjects +namespace Signhost.APIClient.Rest.DataObjects; + +/// +/// Verification object for itsme Identification. +/// +public class ItsmeIdentificationVerification + : IVerification { /// - /// Verification object for itsme Identification. + /// Gets or sets the phonenumber. /// - public class ItsmeIdentificationVerification - : IVerification - { - /// - /// Gets or sets the phonenumber. - /// - public string PhoneNumber { get; set; } - } + public string PhoneNumber { get; set; } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/ItsmeSignVerification.cs b/src/SignhostAPIClient/Rest/DataObjects/ItsmeSignVerification.cs index 5f988c20..66941355 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/ItsmeSignVerification.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/ItsmeSignVerification.cs @@ -1,10 +1,9 @@ -namespace Signhost.APIClient.Rest.DataObjects +namespace Signhost.APIClient.Rest.DataObjects; + +/// +/// Verification object for itsme sign. +/// +public class ItsmeSignVerification + : IVerification { - /// - /// Verification object for itsme sign. - /// - public class ItsmeSignVerification - : IVerification - { - } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/Level.cs b/src/SignhostAPIClient/Rest/DataObjects/Level.cs index 93f223b1..a96cd7f5 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/Level.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/Level.cs @@ -1,28 +1,27 @@ -namespace Signhost.APIClient.Rest.DataObjects +namespace Signhost.APIClient.Rest.DataObjects; + +/// +/// Level of Assurance. +/// +public enum Level { /// - /// Level of Assurance. + /// Unknown. /// - public enum Level - { - /// - /// Unknown. - /// - Unknown = 0, + Unknown = 0, - /// - /// Low. - /// - Low, + /// + /// Low. + /// + Low, - /// - /// Substantial. - /// - Substantial, + /// + /// Substantial. + /// + Substantial, - /// - /// High. - /// - High, - } + /// + /// High. + /// + High, } diff --git a/src/SignhostAPIClient/Rest/DataObjects/Location.cs b/src/SignhostAPIClient/Rest/DataObjects/Location.cs index d7288d99..1799ad6b 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/Location.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/Location.cs @@ -1,23 +1,22 @@ -namespace Signhost.APIClient.Rest.DataObjects +namespace Signhost.APIClient.Rest.DataObjects; + +public class Location { - public class Location - { - public string Search { get; set; } + public string Search { get; set; } - public int? Occurence { get; set; } + public int? Occurence { get; set; } - public int? Top { get; set; } + public int? Top { get; set; } - public int? Right { get; set; } + public int? Right { get; set; } - public int? Bottom { get; set; } + public int? Bottom { get; set; } - public int? Left { get; set; } + public int? Left { get; set; } - public int? Width { get; set; } + public int? Width { get; set; } - public int? Height { get; set; } + public int? Height { get; set; } - public int? PageNumber { get; set; } - } + public int? PageNumber { get; set; } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/PhoneNumberVerification.cs b/src/SignhostAPIClient/Rest/DataObjects/PhoneNumberVerification.cs index fad44c4a..85f1fe25 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/PhoneNumberVerification.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/PhoneNumberVerification.cs @@ -1,8 +1,7 @@ -namespace Signhost.APIClient.Rest.DataObjects +namespace Signhost.APIClient.Rest.DataObjects; + +public class PhoneNumberVerification + : IVerification { - public class PhoneNumberVerification - : IVerification - { - public string Number { get; set; } - } + public string Number { get; set; } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/PostbackTransaction.cs b/src/SignhostAPIClient/Rest/DataObjects/PostbackTransaction.cs index ea57648d..cffc6ebb 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/PostbackTransaction.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/PostbackTransaction.cs @@ -1,11 +1,10 @@ using System.Text.Json.Serialization; -namespace Signhost.APIClient.Rest.DataObjects +namespace Signhost.APIClient.Rest.DataObjects; + +public class PostbackTransaction + : Transaction { - public class PostbackTransaction - : Transaction - { - [JsonPropertyName("Checksum")] - public string Checksum { get; set; } - } + [JsonPropertyName("Checksum")] + public string Checksum { get; set; } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/Receiver.cs b/src/SignhostAPIClient/Rest/DataObjects/Receiver.cs index 5afaeb1c..cf8a3642 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/Receiver.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/Receiver.cs @@ -1,35 +1,34 @@ using System.Collections.Generic; using System.Text.Json.Serialization; -namespace Signhost.APIClient.Rest.DataObjects +namespace Signhost.APIClient.Rest.DataObjects; + +public class Receiver { - public class Receiver + public Receiver() { - public Receiver() - { - } + } - [JsonConstructor] - private Receiver(IReadOnlyList activities) - { - Activities = activities; - } + [JsonConstructor] + private Receiver(IReadOnlyList activities) + { + Activities = activities; + } - public string Name { get; set; } + public string Name { get; set; } - public string Email { get; set; } + public string Email { get; set; } - public string Language { get; set; } + public string Language { get; set; } - public string Subject { get; set; } + public string Subject { get; set; } - public string Message { get; set; } + public string Message { get; set; } - public string Reference { get; set; } + public string Reference { get; set; } - public IReadOnlyList Activities { get; set; } = - new List().AsReadOnly(); + public IReadOnlyList Activities { get; set; } = + new List().AsReadOnly(); - public dynamic Context { get; set; } - } + public dynamic Context { get; set; } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/ScribbleVerification.cs b/src/SignhostAPIClient/Rest/DataObjects/ScribbleVerification.cs index fadb57af..5556f0b5 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/ScribbleVerification.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/ScribbleVerification.cs @@ -1,12 +1,11 @@ -namespace Signhost.APIClient.Rest.DataObjects +namespace Signhost.APIClient.Rest.DataObjects; + +public class ScribbleVerification + : IVerification { - public class ScribbleVerification - : IVerification - { - public bool RequireHandsignature { get; set; } + public bool RequireHandsignature { get; set; } - public bool ScribbleNameFixed { get; set; } + public bool ScribbleNameFixed { get; set; } - public string ScribbleName { get; set; } - } + public string ScribbleName { get; set; } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/Signer.cs b/src/SignhostAPIClient/Rest/DataObjects/Signer.cs index e1d7f660..e9a4517d 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/Signer.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/Signer.cs @@ -2,71 +2,70 @@ using System.Collections.Generic; using System.Text.Json.Serialization; -namespace Signhost.APIClient.Rest.DataObjects +namespace Signhost.APIClient.Rest.DataObjects; + +public class Signer { - public class Signer + public Signer() { - public Signer() - { - } + } - [JsonConstructor] - private Signer(IReadOnlyList activities) - { - Activities = activities; - } + [JsonConstructor] + private Signer(IReadOnlyList activities) + { + Activities = activities; + } - public string Id { get; set; } + public string Id { get; set; } - public DateTimeOffset? Expires { get; set; } + public DateTimeOffset? Expires { get; set; } - public string Email { get; set; } + public string Email { get; set; } - public string IntroText { get; set; } + public string IntroText { get; set; } - public string SignRequestSubject { get; set; } + public string SignRequestSubject { get; set; } - public string SignRequestMessage { get; set; } + public string SignRequestMessage { get; set; } - public IList Authentications { get; set; } - = new List(); + public IList Authentications { get; set; } + = new List(); - public IList Verifications { get; set; } - = new List(); + public IList Verifications { get; set; } + = new List(); - public bool SendSignRequest { get; set; } + public bool SendSignRequest { get; set; } - public bool? SendSignConfirmation { get; set; } + public bool? SendSignConfirmation { get; set; } - public int? DaysToRemind { get; set; } + public int? DaysToRemind { get; set; } - public string Language { get; set; } + public string Language { get; set; } - public string ScribbleName { get; set; } + public string ScribbleName { get; set; } - public bool ScribbleNameFixed { get; set; } + public bool ScribbleNameFixed { get; set; } - public string Reference { get; set; } + public string Reference { get; set; } - public string ReturnUrl { get; set; } + public string ReturnUrl { get; set; } - public string RejectReason { get; set; } + public string RejectReason { get; set; } - public string SignUrl { get; set; } + public string SignUrl { get; set; } - public bool AllowDelegation { get; set; } + public bool AllowDelegation { get; set; } - public string DelegateSignUrl { get; set; } + public string DelegateSignUrl { get; set; } - public string DelegateReason { get; set; } + public string DelegateReason { get; set; } - public string DelegateSignerEmail { get; set; } + public string DelegateSignerEmail { get; set; } - public string DelegateSignerName { get; set; } + public string DelegateSignerName { get; set; } - public IReadOnlyList Activities { get; private set; } = - new List().AsReadOnly(); + public IReadOnlyList Activities { get; private set; } = + new List().AsReadOnly(); - public dynamic Context { get; set; } - } + public dynamic Context { get; set; } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/SigningCertificateVerification.cs b/src/SignhostAPIClient/Rest/DataObjects/SigningCertificateVerification.cs index b6f9735f..f9420a4f 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/SigningCertificateVerification.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/SigningCertificateVerification.cs @@ -1,11 +1,10 @@ -namespace Signhost.APIClient.Rest.DataObjects +namespace Signhost.APIClient.Rest.DataObjects; + +/// +/// Represents a verification method using a signers signing certificate +/// for example a qualified certificate. +/// +public class SigningCertificateVerification + : IVerification { - /// - /// Represents a verification method using a signers signing certificate - /// for example a qualified certificate. - /// - public class SigningCertificateVerification - : IVerification - { - } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/SurfnetVerification.cs b/src/SignhostAPIClient/Rest/DataObjects/SurfnetVerification.cs index ec1a4abe..72abf3cf 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/SurfnetVerification.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/SurfnetVerification.cs @@ -1,7 +1,6 @@ -namespace Signhost.APIClient.Rest.DataObjects +namespace Signhost.APIClient.Rest.DataObjects; + +public class SurfnetVerification + : IVerification { - public class SurfnetVerification - : IVerification - { - } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/Transaction.cs b/src/SignhostAPIClient/Rest/DataObjects/Transaction.cs index 66166334..7ac62205 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/Transaction.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/Transaction.cs @@ -1,53 +1,52 @@ using System; using System.Collections.Generic; -namespace Signhost.APIClient.Rest.DataObjects +namespace Signhost.APIClient.Rest.DataObjects; + +public class Transaction { - public class Transaction - { - public string Id { get; set; } + public string Id { get; set; } - /// - /// Gets the when the was created. - /// - public DateTimeOffset? CreatedDateTime { get; set; } + /// + /// Gets the when the was created. + /// + public DateTimeOffset? CreatedDateTime { get; set; } - /// - /// Gets the when the was cancelled. - /// Returns null if the transaction was not cancelled. - /// - public DateTimeOffset? CanceledDateTime { get; set; } + /// + /// Gets the when the was cancelled. + /// Returns null if the transaction was not cancelled. + /// + public DateTimeOffset? CanceledDateTime { get; set; } - /// - /// Gets the cancellation reason when the was cancelled. - /// - public string CancellationReason { get; set; } + /// + /// Gets the cancellation reason when the was cancelled. + /// + public string CancellationReason { get; set; } - public IReadOnlyDictionary Files { get; set; } = - new Dictionary(); + public IReadOnlyDictionary Files { get; set; } = + new Dictionary(); - public TransactionStatus Status { get; set; } + public TransactionStatus Status { get; set; } - public bool Seal { get; set; } + public bool Seal { get; set; } - public IList Signers { get; set; } - = new List(); + public IList Signers { get; set; } + = new List(); - public IList Receivers { get; set; } - = new List(); + public IList Receivers { get; set; } + = new List(); - public string Reference { get; set; } + public string Reference { get; set; } - public string PostbackUrl { get; set; } + public string PostbackUrl { get; set; } - public int SignRequestMode { get; set; } + public int SignRequestMode { get; set; } - public int DaysToExpire { get; set; } + public int DaysToExpire { get; set; } - public string Language { get; set; } + public string Language { get; set; } - public bool SendEmailNotifications { get; set; } + public bool SendEmailNotifications { get; set; } - public dynamic Context { get; set; } - } + public dynamic Context { get; set; } } diff --git a/src/SignhostAPIClient/Rest/DataObjects/TransactionStatus.cs b/src/SignhostAPIClient/Rest/DataObjects/TransactionStatus.cs index 2c9b80a9..7485bf10 100644 --- a/src/SignhostAPIClient/Rest/DataObjects/TransactionStatus.cs +++ b/src/SignhostAPIClient/Rest/DataObjects/TransactionStatus.cs @@ -1,47 +1,46 @@ -namespace Signhost.APIClient.Rest.DataObjects +namespace Signhost.APIClient.Rest.DataObjects; + +public enum TransactionStatus { - public enum TransactionStatus - { - /// - /// Transaction has not yet been started and is waiting for its - /// documents. - /// - WaitingForDocument = 5, - - /// - /// The transaction was started and is waiting for one or more signers - /// to sign the transaction. - /// - WaitingForSigner = 10, - - /// - /// In progress - /// - InProgress = 20, - - /// - /// The transaction was succesfully completed. - /// - Signed = 30, - - /// - /// The transaction was rejected by one or more of the signers. - /// - Rejected = 40, - - /// - /// The transaction was not signed before it expired. - /// - Expired = 50, - - /// - /// The transaction was cancelled by the sender. - /// - Cancelled = 60, - - /// - /// The transaction could not be completed. - /// - Failed = 70, - } + /// + /// Transaction has not yet been started and is waiting for its + /// documents. + /// + WaitingForDocument = 5, + + /// + /// The transaction was started and is waiting for one or more signers + /// to sign the transaction. + /// + WaitingForSigner = 10, + + /// + /// In progress + /// + InProgress = 20, + + /// + /// The transaction was succesfully completed. + /// + Signed = 30, + + /// + /// The transaction was rejected by one or more of the signers. + /// + Rejected = 40, + + /// + /// The transaction was not signed before it expired. + /// + Expired = 50, + + /// + /// The transaction was cancelled by the sender. + /// + Cancelled = 60, + + /// + /// The transaction could not be completed. + /// + Failed = 70, } diff --git a/src/SignhostAPIClient/Rest/ErrorHandling/BadAuthorizationException.cs b/src/SignhostAPIClient/Rest/ErrorHandling/BadAuthorizationException.cs index 9d78b27d..18260ac2 100644 --- a/src/SignhostAPIClient/Rest/ErrorHandling/BadAuthorizationException.cs +++ b/src/SignhostAPIClient/Rest/ErrorHandling/BadAuthorizationException.cs @@ -1,36 +1,35 @@ using System; -namespace Signhost.APIClient.Rest.ErrorHandling +namespace Signhost.APIClient.Rest.ErrorHandling; + +[Serializable] +public class BadAuthorizationException + : SignhostRestApiClientException { - [Serializable] - public class BadAuthorizationException - : SignhostRestApiClientException + public BadAuthorizationException() + : base("API call returned a 401 error code. Please check your request headers.") { - public BadAuthorizationException() - : base("API call returned a 401 error code. Please check your request headers.") - { - HelpLink = "https://api.signhost.com/Help"; - } + HelpLink = "https://api.signhost.com/Help"; + } - public BadAuthorizationException(string message) - : base(message) - { - } + public BadAuthorizationException(string message) + : base(message) + { + } - public BadAuthorizationException( - string message, - Exception innerException) - : base(message, innerException) - { - } + public BadAuthorizationException( + string message, + Exception innerException) + : base(message, innerException) + { + } #if SERIALIZABLE - protected BadAuthorizationException( - SerializationInfo info, - StreamingContext context) - : base(info, context) - { - } -#endif + protected BadAuthorizationException( + SerializationInfo info, + StreamingContext context) + : base(info, context) + { } +#endif } diff --git a/src/SignhostAPIClient/Rest/ErrorHandling/BadRequestException.cs b/src/SignhostAPIClient/Rest/ErrorHandling/BadRequestException.cs index d6041abf..d449b02b 100644 --- a/src/SignhostAPIClient/Rest/ErrorHandling/BadRequestException.cs +++ b/src/SignhostAPIClient/Rest/ErrorHandling/BadRequestException.cs @@ -1,36 +1,35 @@ using System; -namespace Signhost.APIClient.Rest.ErrorHandling +namespace Signhost.APIClient.Rest.ErrorHandling; + +[Serializable] +public class BadRequestException + : SignhostRestApiClientException { - [Serializable] - public class BadRequestException - : SignhostRestApiClientException + public BadRequestException() + : base() { - public BadRequestException() - : base() - { - } + } - public BadRequestException(string message) - : base(message) - { - } + public BadRequestException(string message) + : base(message) + { + } - public BadRequestException( - string message, - Exception innerException) - : base(message, innerException) - { - HelpLink = "https://api.signhost.com/Help"; - } + public BadRequestException( + string message, + Exception innerException) + : base(message, innerException) + { + HelpLink = "https://api.signhost.com/Help"; + } #if SERIALIZABLE - protected BadRequestException( - SerializationInfo info, - StreamingContext context) - : base(info, context) - { - } -#endif + protected BadRequestException( + SerializationInfo info, + StreamingContext context) + : base(info, context) + { } +#endif } diff --git a/src/SignhostAPIClient/Rest/ErrorHandling/DefaultSignhostException.cs b/src/SignhostAPIClient/Rest/ErrorHandling/DefaultSignhostException.cs index 8c9a0542..b7db21ab 100644 --- a/src/SignhostAPIClient/Rest/ErrorHandling/DefaultSignhostException.cs +++ b/src/SignhostAPIClient/Rest/ErrorHandling/DefaultSignhostException.cs @@ -1,30 +1,29 @@ using System; -namespace Signhost.APIClient.Rest.ErrorHandling +namespace Signhost.APIClient.Rest.ErrorHandling; + +[Serializable] +public class DefaultSignhostException : Exception { - [Serializable] - public class DefaultSignhostException : Exception + public DefaultSignhostException(string message) + : base(message) { - public DefaultSignhostException(string message) - : base(message) - { - HelpLink = "https://api.signhost.com/Help"; - } + HelpLink = "https://api.signhost.com/Help"; + } - public DefaultSignhostException( - string message, - Exception innerException) - : base(message, innerException) - { - } + public DefaultSignhostException( + string message, + Exception innerException) + : base(message, innerException) + { + } #if SERIALIZABLE - protected DefaultSignhostException( - SerializationInfo info, - StreamingContext context) - : base(info, context) - { - } -#endif + protected DefaultSignhostException( + SerializationInfo info, + StreamingContext context) + : base(info, context) + { } +#endif } diff --git a/src/SignhostAPIClient/Rest/ErrorHandling/GoneException.cs b/src/SignhostAPIClient/Rest/ErrorHandling/GoneException.cs index 08e8ce8c..5aad3757 100644 --- a/src/SignhostAPIClient/Rest/ErrorHandling/GoneException.cs +++ b/src/SignhostAPIClient/Rest/ErrorHandling/GoneException.cs @@ -1,62 +1,61 @@ using System; -namespace Signhost.APIClient.Rest.ErrorHandling +namespace Signhost.APIClient.Rest.ErrorHandling; + +/// +/// Thrown when a transaction is deleted / cancelled. +/// +[Serializable] +public class GoneException + : SignhostRestApiClientException { /// - /// Thrown when a transaction is deleted / cancelled. + /// Initializes a new instance of the class. /// - [Serializable] - public class GoneException - : SignhostRestApiClientException + public GoneException() + : base() { - /// - /// Initializes a new instance of the class. - /// - public GoneException() - : base() - { - } + } - /// - /// Initializes a new instance of the class. - /// - /// Additional information - public GoneException(string message) - : base(message) - { - } + /// + /// Initializes a new instance of the class. + /// + /// Additional information + public GoneException(string message) + : base(message) + { + } - public GoneException(string message, TResult result) - : base(message) - { - Result = result; - } + public GoneException(string message, TResult result) + : base(message) + { + Result = result; + } - /// - /// Initializes a new instance of the class. - /// - /// Additional information - /// Inner exception - public GoneException(string message, Exception innerException) - : base(message, innerException) - { - HelpLink = "https://api.signhost.com/Help"; - } + /// + /// Initializes a new instance of the class. + /// + /// Additional information + /// Inner exception + public GoneException(string message, Exception innerException) + : base(message, innerException) + { + HelpLink = "https://api.signhost.com/Help"; + } #if SERIALIZABLE - protected GoneException( - SerializationInfo info, - StreamingContext context) - : base(info, context) - { - } + protected GoneException( + SerializationInfo info, + StreamingContext context) + : base(info, context) + { + } #endif - /// - /// Gets the api / transaction details which are still available. - /// Please note that this no longer contains the full transaction - /// details as most data is removed. - /// - public TResult Result { get; private set; } - } + /// + /// Gets the api / transaction details which are still available. + /// Please note that this no longer contains the full transaction + /// details as most data is removed. + /// + public TResult Result { get; private set; } } diff --git a/src/SignhostAPIClient/Rest/ErrorHandling/HttpResponseMessageErrorHandlingExtensions.cs b/src/SignhostAPIClient/Rest/ErrorHandling/HttpResponseMessageErrorHandlingExtensions.cs index 1d5bcb4d..35edbd3e 100644 --- a/src/SignhostAPIClient/Rest/ErrorHandling/HttpResponseMessageErrorHandlingExtensions.cs +++ b/src/SignhostAPIClient/Rest/ErrorHandling/HttpResponseMessageErrorHandlingExtensions.cs @@ -6,101 +6,100 @@ using System.Text.Json.Serialization; using System.Threading.Tasks; -namespace Signhost.APIClient.Rest.ErrorHandling +namespace Signhost.APIClient.Rest.ErrorHandling; + +/// +/// Error handling around s. +/// +public static class HttpResponseMessageErrorHandlingExtensions { /// - /// Error handling around s. + /// Throws an exception if the + /// has an error code. /// - public static class HttpResponseMessageErrorHandlingExtensions + /// + /// Returns if the call is succesful. + /// List of which should + /// not be handled as an error. + /// + /// When the api authentication failed. + /// + /// + /// When the API request was an invalid request for your account. + /// + /// + /// When your organisation has run out of credits. + /// + /// + /// When the request resource (ie transaction id or file id) was not found. + /// + /// + /// When the API was unable to proces the request at the moment, + /// a RetryAfter property is set if available. + /// + /// + /// An other unknown API error occured. + /// + public static async Task EnsureSignhostSuccessStatusCodeAsync( + this Task responseTask, + params HttpStatusCode[] expectedStatusCodes) { - /// - /// Throws an exception if the - /// has an error code. - /// - /// - /// Returns if the call is succesful. - /// List of which should - /// not be handled as an error. - /// - /// When the api authentication failed. - /// - /// - /// When the API request was an invalid request for your account. - /// - /// - /// When your organisation has run out of credits. - /// - /// - /// When the request resource (ie transaction id or file id) was not found. - /// - /// - /// When the API was unable to proces the request at the moment, - /// a RetryAfter property is set if available. - /// - /// - /// An other unknown API error occured. - /// - public static async Task EnsureSignhostSuccessStatusCodeAsync( - this Task responseTask, - params HttpStatusCode[] expectedStatusCodes) - { - var response = await responseTask.ConfigureAwait(false); + var response = await responseTask.ConfigureAwait(false); - if (response.IsSuccessStatusCode) { - return response; - } + if (response.IsSuccessStatusCode) { + return response; + } - if (expectedStatusCodes.Contains(response.StatusCode)) { - return response; - } + if (expectedStatusCodes.Contains(response.StatusCode)) { + return response; + } - string errorType = string.Empty; - string errorMessage = "Unknown Signhost error"; + string errorType = string.Empty; + string errorMessage = "Unknown Signhost error"; - if (response.Content != null) { - string responsejson = await response.Content.ReadAsStringAsync() - .ConfigureAwait(false); + if (response.Content != null) { + string responsejson = await response.Content.ReadAsStringAsync() + .ConfigureAwait(false); - var error = JsonSerializer.Deserialize(responsejson); + var error = JsonSerializer.Deserialize(responsejson); - errorType = error?.Type ?? string.Empty; - errorMessage = error?.Message ?? "Unknown Signhost error"; - } + errorType = error?.Type ?? string.Empty; + errorMessage = error?.Message ?? "Unknown Signhost error"; + } - switch (response.StatusCode) { - case HttpStatusCode.Unauthorized: - throw new System.UnauthorizedAccessException( - errorMessage); - case HttpStatusCode.BadRequest: - throw new BadRequestException( - errorMessage); - case HttpStatusCode.PaymentRequired - when errorType == "https://api.signhost.com/problem/subscription/out-of-credits": - if (string.IsNullOrEmpty(errorMessage)) { - errorMessage = "The credit bundle has been exceeded."; - } + switch (response.StatusCode) { + case HttpStatusCode.Unauthorized: + throw new System.UnauthorizedAccessException( + errorMessage); + case HttpStatusCode.BadRequest: + throw new BadRequestException( + errorMessage); + case HttpStatusCode.PaymentRequired + when errorType == "https://api.signhost.com/problem/subscription/out-of-credits": + if (string.IsNullOrEmpty(errorMessage)) { + errorMessage = "The credit bundle has been exceeded."; + } - throw new OutOfCreditsException( - errorMessage); - case HttpStatusCode.NotFound: - throw new NotFoundException( - errorMessage); - case HttpStatusCode.InternalServerError: - throw new InternalServerErrorException( - errorMessage, response.Headers.RetryAfter); - default: - throw new SignhostRestApiClientException( - errorMessage); - } + throw new OutOfCreditsException( + errorMessage); + case HttpStatusCode.NotFound: + throw new NotFoundException( + errorMessage); + case HttpStatusCode.InternalServerError: + throw new InternalServerErrorException( + errorMessage, response.Headers.RetryAfter); + default: + throw new SignhostRestApiClientException( + errorMessage); } + } - private class ErrorResponse - { - [JsonPropertyName("type")] - public string Type { get; set; } + private class ErrorResponse + { + [JsonPropertyName("type")] + public string Type { get; set; } - [JsonPropertyName("message")] - public string Message { get; set; } - } + [JsonPropertyName("message")] + public string Message { get; set; } } } diff --git a/src/SignhostAPIClient/Rest/ErrorHandling/InternalServerErrorException.cs b/src/SignhostAPIClient/Rest/ErrorHandling/InternalServerErrorException.cs index 0100e317..265489f0 100644 --- a/src/SignhostAPIClient/Rest/ErrorHandling/InternalServerErrorException.cs +++ b/src/SignhostAPIClient/Rest/ErrorHandling/InternalServerErrorException.cs @@ -1,48 +1,47 @@ using System; using System.Net.Http.Headers; -namespace Signhost.APIClient.Rest.ErrorHandling +namespace Signhost.APIClient.Rest.ErrorHandling; + +[Serializable] +public class InternalServerErrorException + : SignhostRestApiClientException { - [Serializable] - public class InternalServerErrorException - : SignhostRestApiClientException + public InternalServerErrorException() + : base() { - public InternalServerErrorException() - : base() - { - } + } - public InternalServerErrorException(string message) - : base(message) - { - } + public InternalServerErrorException(string message) + : base(message) + { + } - public InternalServerErrorException( - string message, RetryConditionHeaderValue retryAfter) - : base(message) - { - HelpLink = "https://api.signhost.com/Help"; + public InternalServerErrorException( + string message, RetryConditionHeaderValue retryAfter) + : base(message) + { + HelpLink = "https://api.signhost.com/Help"; - if (retryAfter != null) { - if (retryAfter.Date != null) { - RetryAfter = retryAfter.Date; - } + if (retryAfter != null) { + if (retryAfter.Date != null) { + RetryAfter = retryAfter.Date; + } - if (retryAfter.Delta != null) { - RetryAfter = DateTime.Now + retryAfter.Delta; - } + if (retryAfter.Delta != null) { + RetryAfter = DateTime.Now + retryAfter.Delta; } } + } #if SERIALIZABLE - protected InternalServerErrorException( - SerializationInfo info, - StreamingContext context) - : base(info, context) - { - } + protected InternalServerErrorException( + SerializationInfo info, + StreamingContext context) + : base(info, context) + { + } #endif - private DateTimeOffset? RetryAfter { get; set; } - } + private DateTimeOffset? RetryAfter { get; set; } } diff --git a/src/SignhostAPIClient/Rest/ErrorHandling/NotFoundException.cs b/src/SignhostAPIClient/Rest/ErrorHandling/NotFoundException.cs index 6c9eda47..0b61c9e3 100644 --- a/src/SignhostAPIClient/Rest/ErrorHandling/NotFoundException.cs +++ b/src/SignhostAPIClient/Rest/ErrorHandling/NotFoundException.cs @@ -1,34 +1,33 @@ using System; -namespace Signhost.APIClient.Rest.ErrorHandling +namespace Signhost.APIClient.Rest.ErrorHandling; + +[Serializable] +public class NotFoundException + : SignhostRestApiClientException { - [Serializable] - public class NotFoundException - : SignhostRestApiClientException + public NotFoundException() + : base() { - public NotFoundException() - : base() - { - } + } - public NotFoundException(string message) - : base(message) - { - } + public NotFoundException(string message) + : base(message) + { + } - public NotFoundException(string message, Exception innerException) - : base(message, innerException) - { - HelpLink = "https://api.signhost.com/Help"; - } + public NotFoundException(string message, Exception innerException) + : base(message, innerException) + { + HelpLink = "https://api.signhost.com/Help"; + } #if SERIALIZABLE - protected NotFoundException( - SerializationInfo info, - StreamingContext context) - : base(info, context) - { - } -#endif + protected NotFoundException( + SerializationInfo info, + StreamingContext context) + : base(info, context) + { } +#endif } diff --git a/src/SignhostAPIClient/Rest/ErrorHandling/OutOfCreditsException.cs b/src/SignhostAPIClient/Rest/ErrorHandling/OutOfCreditsException.cs index a5cf42e7..7d8c89e6 100644 --- a/src/SignhostAPIClient/Rest/ErrorHandling/OutOfCreditsException.cs +++ b/src/SignhostAPIClient/Rest/ErrorHandling/OutOfCreditsException.cs @@ -1,21 +1,20 @@ using System; -namespace Signhost.APIClient.Rest.ErrorHandling +namespace Signhost.APIClient.Rest.ErrorHandling; + +/// +/// An exception which indicates payment is required when an API action is called. +/// +[Serializable] +public class OutOfCreditsException + : SignhostRestApiClientException { /// - /// An exception which indicates payment is required when an API action is called. + /// Initializes a new instance of the class. /// - [Serializable] - public class OutOfCreditsException - : SignhostRestApiClientException + /// The exception message. + public OutOfCreditsException(string message) + : base(message) { - /// - /// Initializes a new instance of the class. - /// - /// The exception message. - public OutOfCreditsException(string message) - : base(message) - { - } } } diff --git a/src/SignhostAPIClient/Rest/ErrorHandling/SignhostException.cs b/src/SignhostAPIClient/Rest/ErrorHandling/SignhostException.cs index 30391104..b24db3f6 100644 --- a/src/SignhostAPIClient/Rest/ErrorHandling/SignhostException.cs +++ b/src/SignhostAPIClient/Rest/ErrorHandling/SignhostException.cs @@ -1,35 +1,34 @@ using System; -namespace Signhost.APIClient.Rest.ErrorHandling +namespace Signhost.APIClient.Rest.ErrorHandling; + +[Serializable] +[Obsolete("Unused will be removed")] +public class SignhostException + : SignhostRestApiClientException { - [Serializable] - [Obsolete("Unused will be removed")] - public class SignhostException - : SignhostRestApiClientException + public SignhostException() + : base() { - public SignhostException() - : base() - { - } + } - public SignhostException(string message) - : base(message) - { - } + public SignhostException(string message) + : base(message) + { + } - public SignhostException(string message, Exception innerException) - : base(message, innerException) - { - HelpLink = "https://api.signhost.com/Help"; - } + public SignhostException(string message, Exception innerException) + : base(message, innerException) + { + HelpLink = "https://api.signhost.com/Help"; + } #if SERIALIZABLE - protected SignhostException( - SerializationInfo info, - StreamingContext context) - : base(info, context) - { - } -#endif + protected SignhostException( + SerializationInfo info, + StreamingContext context) + : base(info, context) + { } +#endif } diff --git a/src/SignhostAPIClient/Rest/ErrorHandling/SignhostRestApiClientException.cs b/src/SignhostAPIClient/Rest/ErrorHandling/SignhostRestApiClientException.cs index 68765691..f7c0b0d9 100644 --- a/src/SignhostAPIClient/Rest/ErrorHandling/SignhostRestApiClientException.cs +++ b/src/SignhostAPIClient/Rest/ErrorHandling/SignhostRestApiClientException.cs @@ -1,36 +1,35 @@ using System; -namespace Signhost.APIClient.Rest.ErrorHandling +namespace Signhost.APIClient.Rest.ErrorHandling; + +[Serializable] +public class SignhostRestApiClientException + : Exception { - [Serializable] - public class SignhostRestApiClientException - : Exception + public SignhostRestApiClientException() + : base() { - public SignhostRestApiClientException() - : base() - { - } + } - public SignhostRestApiClientException(string message) - : base(message) - { - } + public SignhostRestApiClientException(string message) + : base(message) + { + } - public SignhostRestApiClientException( - string message, - Exception innerException) - : base(message, innerException) - { - HelpLink = "https://api.signhost.com/Help"; - } + public SignhostRestApiClientException( + string message, + Exception innerException) + : base(message, innerException) + { + HelpLink = "https://api.signhost.com/Help"; + } #if SERIALIZABLE - protected SignhostRestApiClientException( - SerializationInfo info, - StreamingContext context) - : base(info, context) - { - } -#endif + protected SignhostRestApiClientException( + SerializationInfo info, + StreamingContext context) + : base(info, context) + { } +#endif } diff --git a/src/SignhostAPIClient/Rest/FileDigestOptions.cs b/src/SignhostAPIClient/Rest/FileDigestOptions.cs index b71e0eb7..bc0218b6 100644 --- a/src/SignhostAPIClient/Rest/FileDigestOptions.cs +++ b/src/SignhostAPIClient/Rest/FileDigestOptions.cs @@ -1,27 +1,26 @@ -namespace Signhost.APIClient.Rest +namespace Signhost.APIClient.Rest; + +/// +/// File digest options for file uploads +/// +public class FileDigestOptions { /// - /// File digest options for file uploads + /// Gets or sets whether to use the Digest header with a checksum of + /// the uploaded file. /// - public class FileDigestOptions - { - /// - /// Gets or sets whether to use the Digest header with a checksum of - /// the uploaded file. - /// - public bool UseFileDigesting { get; set; } = true; + public bool UseFileDigesting { get; set; } = true; - /// - /// Gets or sets the digest algorithm to use when calculating - /// the hash value or the digest algorithm that is used - /// to set the . - /// - public string DigestHashAlgorithm { get; set; } = "SHA-256"; + /// + /// Gets or sets the digest algorithm to use when calculating + /// the hash value or the digest algorithm that is used + /// to set the . + /// + public string DigestHashAlgorithm { get; set; } = "SHA-256"; - /// - /// Gets or sets the hash digest value, you can set this yourself - /// if you know the digest value in advance. - /// - public byte[] DigestHashValue { get; set; } - } + /// + /// Gets or sets the hash digest value, you can set this yourself + /// if you know the digest value in advance. + /// + public byte[] DigestHashValue { get; set; } } diff --git a/src/SignhostAPIClient/Rest/FileUploadOptions.cs b/src/SignhostAPIClient/Rest/FileUploadOptions.cs index 340ad1ec..4336b6d2 100644 --- a/src/SignhostAPIClient/Rest/FileUploadOptions.cs +++ b/src/SignhostAPIClient/Rest/FileUploadOptions.cs @@ -1,14 +1,13 @@ -namespace Signhost.APIClient.Rest +namespace Signhost.APIClient.Rest; + +/// +/// Options to be used during a file upload +/// +public class FileUploadOptions { /// - /// Options to be used during a file upload + /// Gets or sets the . /// - public class FileUploadOptions - { - /// - /// Gets or sets the . - /// - public FileDigestOptions DigestOptions { get; set; } - = new FileDigestOptions(); - } + public FileDigestOptions DigestOptions { get; set; } + = new FileDigestOptions(); } diff --git a/src/SignhostAPIClient/Rest/HttpContentJsonExtensions.cs b/src/SignhostAPIClient/Rest/HttpContentJsonExtensions.cs index b7e2836e..3dfa535f 100644 --- a/src/SignhostAPIClient/Rest/HttpContentJsonExtensions.cs +++ b/src/SignhostAPIClient/Rest/HttpContentJsonExtensions.cs @@ -2,30 +2,29 @@ using System.Text.Json; using System.Threading.Tasks; -namespace Signhost.APIClient.Rest +namespace Signhost.APIClient.Rest; + +/// +/// Extension methods around JSON Deserialization. +/// +internal static class HttpContentJsonExtensions { /// - /// Extension methods around JSON Deserialization. + /// Reads the JSON content and returns the deserialized value. /// - internal static class HttpContentJsonExtensions + /// Type to deserialize to + /// to read. + /// A deserialized value of + /// or default(T) if no content is available. + internal static async Task FromJsonAsync( + this HttpContent httpContent) { - /// - /// Reads the JSON content and returns the deserialized value. - /// - /// Type to deserialize to - /// to read. - /// A deserialized value of - /// or default(T) if no content is available. - internal static async Task FromJsonAsync( - this HttpContent httpContent) - { - if (httpContent == null) { - return default(T); - } - - var json = await httpContent.ReadAsStringAsync() - .ConfigureAwait(false); - return JsonSerializer.Deserialize(json, SignhostJsonSerializerOptions.Default); + if (httpContent == null) { + return default(T); } + + var json = await httpContent.ReadAsStringAsync() + .ConfigureAwait(false); + return JsonSerializer.Deserialize(json, SignhostJsonSerializerOptions.Default); } } diff --git a/src/SignhostAPIClient/Rest/ISignHostApiClient.cs b/src/SignhostAPIClient/Rest/ISignHostApiClient.cs index 79c5a885..d2ac880c 100644 --- a/src/SignhostAPIClient/Rest/ISignHostApiClient.cs +++ b/src/SignhostAPIClient/Rest/ISignHostApiClient.cs @@ -3,248 +3,247 @@ using System.Threading.Tasks; using Signhost.APIClient.Rest.DataObjects; -namespace Signhost.APIClient.Rest +namespace Signhost.APIClient.Rest; + +/// +/// Interface abstracting the available Signhost API calls. +/// +public interface ISignhostApiClient { /// - /// Interface abstracting the available Signhost API calls. - /// - public interface ISignhostApiClient - { - /// - /// Creates a new transaction. - /// - /// A transaction model. - /// A transaction object. - Task CreateTransactionAsync(Transaction transaction); - - /// - /// Creates a new transaction. - /// - /// A transaction model. - /// A cancellation token. - /// A transaction object. - Task CreateTransactionAsync( - Transaction transaction, - CancellationToken cancellationToken = default); - - /// - /// Adds meta data for a file to an existing transaction by providing a - /// file location and a transaction id. - /// - /// Meta data for the file. - /// A valid transaction Id of an existing transaction. - /// An Id for the file. Should be the same as the fileId in the . - /// A task. - /// Make sure to call this method before - /// . - Task AddOrReplaceFileMetaToTransactionAsync( - FileMeta fileMeta, - string transactionId, - string fileId); - - /// - /// Adds meta data for a file to an existing transaction by providing a - /// file location and a transaction id. - /// - /// Meta data for the file. - /// A valid transaction Id of an existing transaction. - /// An Id for the file. Should be the same as the fileId in the . - /// A cancellation token. - /// A task. - /// Make sure to call this method before - /// . - Task AddOrReplaceFileMetaToTransactionAsync( - FileMeta fileMeta, - string transactionId, - string fileId, - CancellationToken cancellationToken = default); - - /// - /// Add a file to a existing transaction by providing a file location - /// and a transaction id. - /// - /// A Stream containing the file to upload. - /// A valid transaction Id of an existing transaction. - /// A Id for the file. Using the file name is recommended. - /// If a file with the same fileId allready exists the file wil be replaced. - /// . - /// A Task. - Task AddOrReplaceFileToTransactionAsync( - Stream fileStream, - string transactionId, - string fileId, - FileUploadOptions uploadOptions); - - /// - /// Add a file to a existing transaction by providing a file location - /// and a transaction id. - /// - /// A Stream containing the file to upload. - /// A valid transaction Id of an existing transaction. - /// A Id for the file. Using the file name is recommended. - /// If a file with the same fileId allready exists the file wil be replaced. - /// . - /// A cancellation token. - /// A Task. - Task AddOrReplaceFileToTransactionAsync( - Stream fileStream, - string transactionId, - string fileId, - FileUploadOptions uploadOptions, - CancellationToken cancellationToken = default); - - /// - /// Add a file to a existing transaction by providing a file location - /// and a transaction id. - /// - /// A string representation of the file path. - /// A valid transaction Id of an existing transaction. - /// A Id for the file. Using the file name is recommended. - /// If a file with the same fileId allready exists the file wil be replaced. - /// Optional . - /// A Task. - Task AddOrReplaceFileToTransactionAsync( - string filePath, - string transactionId, - string fileId, - FileUploadOptions uploadOptions); - - /// - /// Add a file to a existing transaction by providing a file location - /// and a transaction id. - /// - /// A string representation of the file path. - /// A valid transaction Id of an existing transaction. - /// A Id for the file. Using the file name is recommended. - /// If a file with the same fileId allready exists the file wil be replaced. - /// Optional . - /// A cancellation token. - /// A Task. - Task AddOrReplaceFileToTransactionAsync( - string filePath, - string transactionId, - string fileId, - FileUploadOptions uploadOptions, - CancellationToken cancellationToken = default); - - /// - /// start a existing transaction by providing transaction id. - /// - /// A valid transaction Id of an existing transaction. - /// A Task. - Task StartTransactionAsync(string transactionId); - - /// - /// start a existing transaction by providing transaction id. - /// - /// A valid transaction Id of an existing transaction. - /// A cancellation token. - /// A Task. - Task StartTransactionAsync( - string transactionId, - CancellationToken cancellationToken = default); - - /// - /// Gets an exisiting transaction by providing a transaction id. - /// - /// A valid transaction id for an existing transaction. - /// A object. - Task GetTransactionAsync(string transactionId); - - /// - /// Gets an exisiting transaction by providing a transaction id. - /// - /// A valid transaction id for an existing transaction. - /// A cancellation token. - /// A object. - Task GetTransactionAsync( - string transactionId, - CancellationToken cancellationToken = default); - - /// - /// Gets a existing transaction by providing a transaction id. - /// - /// A valid transaction Id of an existing transaction. - /// A object. - Task> GetTransactionResponseAsync(string transactionId); - - /// - /// Gets a existing transaction by providing a transaction id. - /// - /// A valid transaction Id of an existing transaction. - /// A cancellation token. - /// A object. - Task> GetTransactionResponseAsync( - string transactionId, - CancellationToken cancellationToken = default); - - /// - /// Deletes a existing transaction by providing a transaction id. - /// - /// A valid transaction Id of an existing transaction. - /// A cancellation token. - /// A Task. - Task DeleteTransactionAsync( - string transactionId, - CancellationToken cancellationToken = default); - - /// - /// Deletes a existing transaction by providing a transaction id. - /// - /// A valid transaction Id of an existing transaction. - /// Optional . - /// A Task. - Task DeleteTransactionAsync( - string transactionId, - DeleteTransactionOptions options); - - /// - /// Deletes a existing transaction by providing a transaction id. - /// - /// A valid transaction Id of an existing transaction. - /// Optional . - /// A cancellation token. - /// A Task. - Task DeleteTransactionAsync( - string transactionId, - DeleteTransactionOptions options = default, - CancellationToken cancellationToken = default); - - /// - /// Gets the signed document of a finished transaction by providing transaction id. - /// - /// A valid transaction Id of an existing transaction. - /// A valid file Id of a signed document. - /// Returns a stream containing the signed document data. - Task GetDocumentAsync(string transactionId, string fileId); - - /// - /// Gets the signed document of a finished transaction by providing transaction id. - /// - /// A valid transaction Id of an existing transaction. - /// A valid file Id of a signed document. - /// A cancellation token. - /// Returns a stream containing the signed document data. - Task GetDocumentAsync( - string transactionId, - string fileId, - CancellationToken cancellationToken = default); - - /// - /// Gets the receipt of a finished transaction by providing transaction id. - /// - /// A valid transaction Id of an finnished transaction. - /// Returns a stream containing the receipt data. - Task GetReceiptAsync(string transactionId); - - /// - /// Gets the receipt of a finished transaction by providing transaction id. - /// - /// A valid transaction Id of an finnished transaction. - /// A cancellation token. - /// Returns a stream containing the receipt data. - Task GetReceiptAsync( - string transactionId, - CancellationToken cancellationToken = default); - } + /// Creates a new transaction. + /// + /// A transaction model. + /// A transaction object. + Task CreateTransactionAsync(Transaction transaction); + + /// + /// Creates a new transaction. + /// + /// A transaction model. + /// A cancellation token. + /// A transaction object. + Task CreateTransactionAsync( + Transaction transaction, + CancellationToken cancellationToken = default); + + /// + /// Adds meta data for a file to an existing transaction by providing a + /// file location and a transaction id. + /// + /// Meta data for the file. + /// A valid transaction Id of an existing transaction. + /// An Id for the file. Should be the same as the fileId in the . + /// A task. + /// Make sure to call this method before + /// . + Task AddOrReplaceFileMetaToTransactionAsync( + FileMeta fileMeta, + string transactionId, + string fileId); + + /// + /// Adds meta data for a file to an existing transaction by providing a + /// file location and a transaction id. + /// + /// Meta data for the file. + /// A valid transaction Id of an existing transaction. + /// An Id for the file. Should be the same as the fileId in the . + /// A cancellation token. + /// A task. + /// Make sure to call this method before + /// . + Task AddOrReplaceFileMetaToTransactionAsync( + FileMeta fileMeta, + string transactionId, + string fileId, + CancellationToken cancellationToken = default); + + /// + /// Add a file to a existing transaction by providing a file location + /// and a transaction id. + /// + /// A Stream containing the file to upload. + /// A valid transaction Id of an existing transaction. + /// A Id for the file. Using the file name is recommended. + /// If a file with the same fileId allready exists the file wil be replaced. + /// . + /// A Task. + Task AddOrReplaceFileToTransactionAsync( + Stream fileStream, + string transactionId, + string fileId, + FileUploadOptions uploadOptions); + + /// + /// Add a file to a existing transaction by providing a file location + /// and a transaction id. + /// + /// A Stream containing the file to upload. + /// A valid transaction Id of an existing transaction. + /// A Id for the file. Using the file name is recommended. + /// If a file with the same fileId allready exists the file wil be replaced. + /// . + /// A cancellation token. + /// A Task. + Task AddOrReplaceFileToTransactionAsync( + Stream fileStream, + string transactionId, + string fileId, + FileUploadOptions uploadOptions, + CancellationToken cancellationToken = default); + + /// + /// Add a file to a existing transaction by providing a file location + /// and a transaction id. + /// + /// A string representation of the file path. + /// A valid transaction Id of an existing transaction. + /// A Id for the file. Using the file name is recommended. + /// If a file with the same fileId allready exists the file wil be replaced. + /// Optional . + /// A Task. + Task AddOrReplaceFileToTransactionAsync( + string filePath, + string transactionId, + string fileId, + FileUploadOptions uploadOptions); + + /// + /// Add a file to a existing transaction by providing a file location + /// and a transaction id. + /// + /// A string representation of the file path. + /// A valid transaction Id of an existing transaction. + /// A Id for the file. Using the file name is recommended. + /// If a file with the same fileId allready exists the file wil be replaced. + /// Optional . + /// A cancellation token. + /// A Task. + Task AddOrReplaceFileToTransactionAsync( + string filePath, + string transactionId, + string fileId, + FileUploadOptions uploadOptions, + CancellationToken cancellationToken = default); + + /// + /// start a existing transaction by providing transaction id. + /// + /// A valid transaction Id of an existing transaction. + /// A Task. + Task StartTransactionAsync(string transactionId); + + /// + /// start a existing transaction by providing transaction id. + /// + /// A valid transaction Id of an existing transaction. + /// A cancellation token. + /// A Task. + Task StartTransactionAsync( + string transactionId, + CancellationToken cancellationToken = default); + + /// + /// Gets an exisiting transaction by providing a transaction id. + /// + /// A valid transaction id for an existing transaction. + /// A object. + Task GetTransactionAsync(string transactionId); + + /// + /// Gets an exisiting transaction by providing a transaction id. + /// + /// A valid transaction id for an existing transaction. + /// A cancellation token. + /// A object. + Task GetTransactionAsync( + string transactionId, + CancellationToken cancellationToken = default); + + /// + /// Gets a existing transaction by providing a transaction id. + /// + /// A valid transaction Id of an existing transaction. + /// A object. + Task> GetTransactionResponseAsync(string transactionId); + + /// + /// Gets a existing transaction by providing a transaction id. + /// + /// A valid transaction Id of an existing transaction. + /// A cancellation token. + /// A object. + Task> GetTransactionResponseAsync( + string transactionId, + CancellationToken cancellationToken = default); + + /// + /// Deletes a existing transaction by providing a transaction id. + /// + /// A valid transaction Id of an existing transaction. + /// A cancellation token. + /// A Task. + Task DeleteTransactionAsync( + string transactionId, + CancellationToken cancellationToken = default); + + /// + /// Deletes a existing transaction by providing a transaction id. + /// + /// A valid transaction Id of an existing transaction. + /// Optional . + /// A Task. + Task DeleteTransactionAsync( + string transactionId, + DeleteTransactionOptions options); + + /// + /// Deletes a existing transaction by providing a transaction id. + /// + /// A valid transaction Id of an existing transaction. + /// Optional . + /// A cancellation token. + /// A Task. + Task DeleteTransactionAsync( + string transactionId, + DeleteTransactionOptions options = default, + CancellationToken cancellationToken = default); + + /// + /// Gets the signed document of a finished transaction by providing transaction id. + /// + /// A valid transaction Id of an existing transaction. + /// A valid file Id of a signed document. + /// Returns a stream containing the signed document data. + Task GetDocumentAsync(string transactionId, string fileId); + + /// + /// Gets the signed document of a finished transaction by providing transaction id. + /// + /// A valid transaction Id of an existing transaction. + /// A valid file Id of a signed document. + /// A cancellation token. + /// Returns a stream containing the signed document data. + Task GetDocumentAsync( + string transactionId, + string fileId, + CancellationToken cancellationToken = default); + + /// + /// Gets the receipt of a finished transaction by providing transaction id. + /// + /// A valid transaction Id of an finnished transaction. + /// Returns a stream containing the receipt data. + Task GetReceiptAsync(string transactionId); + + /// + /// Gets the receipt of a finished transaction by providing transaction id. + /// + /// A valid transaction Id of an finnished transaction. + /// A cancellation token. + /// Returns a stream containing the receipt data. + Task GetReceiptAsync( + string transactionId, + CancellationToken cancellationToken = default); } diff --git a/src/SignhostAPIClient/Rest/ISignhostApiClientSettings.cs b/src/SignhostAPIClient/Rest/ISignhostApiClientSettings.cs index 34c7c920..22baf84a 100644 --- a/src/SignhostAPIClient/Rest/ISignhostApiClientSettings.cs +++ b/src/SignhostAPIClient/Rest/ISignhostApiClientSettings.cs @@ -1,26 +1,25 @@ using System; -namespace Signhost.APIClient.Rest -{ - public delegate void AddHeaders(string name, string value); +namespace Signhost.APIClient.Rest; + +public delegate void AddHeaders(string name, string value); - public interface ISignhostApiClientSettings - { - /// - /// Gets the usertoken identifying an authorized user. - /// - string UserToken { get; } +public interface ISignhostApiClientSettings +{ + /// + /// Gets the usertoken identifying an authorized user. + /// + string UserToken { get; } - /// - /// Gets the app key of your applications. - /// - string APPKey { get; } + /// + /// Gets the app key of your applications. + /// + string APPKey { get; } - /// - /// Gets the signhost API endpoint. - /// - string Endpoint { get; } + /// + /// Gets the signhost API endpoint. + /// + string Endpoint { get; } - Action AddHeader { get; } - } + Action AddHeader { get; } } diff --git a/src/SignhostAPIClient/Rest/ISignhostApiReceiver.cs b/src/SignhostAPIClient/Rest/ISignhostApiReceiver.cs index 7778debe..ba4eb961 100644 --- a/src/SignhostAPIClient/Rest/ISignhostApiReceiver.cs +++ b/src/SignhostAPIClient/Rest/ISignhostApiReceiver.cs @@ -1,23 +1,22 @@ using System.Collections.Generic; using Signhost.APIClient.Rest.DataObjects; -namespace Signhost.APIClient.Rest +namespace Signhost.APIClient.Rest; + +/// +/// Interface abstracting the available Signhost API responses. +/// +public interface ISignhostApiReceiver { /// - /// Interface abstracting the available Signhost API responses. + /// Checks the validity of the postback checksum. /// - public interface ISignhostApiReceiver - { - /// - /// Checks the validity of the postback checksum. - /// - /// true, if postback checksum valid was validated, false otherwise. - /// HTTP response headers. - /// HTTP response body. - /// A transaction object. - bool IsPostbackChecksumValid( - IDictionary headers, - string body, - out Transaction postbackTransaction); - } + /// true, if postback checksum valid was validated, false otherwise. + /// HTTP response headers. + /// HTTP response body. + /// A transaction object. + bool IsPostbackChecksumValid( + IDictionary headers, + string body, + out Transaction postbackTransaction); } diff --git a/src/SignhostAPIClient/Rest/JsonContent.cs b/src/SignhostAPIClient/Rest/JsonContent.cs index 837d627e..cb31cea6 100644 --- a/src/SignhostAPIClient/Rest/JsonContent.cs +++ b/src/SignhostAPIClient/Rest/JsonContent.cs @@ -2,45 +2,44 @@ using System.Net.Http.Headers; using System.Text.Json; -namespace Signhost.APIClient.Rest +namespace Signhost.APIClient.Rest; + +/// +/// See the helper class. +/// +internal static class JsonContent { /// - /// See the helper class. + /// Creates a new . /// - internal static class JsonContent + /// Type to serialize. + /// Value to serialize. + /// . + internal static JsonContent From(T value) { - /// - /// Creates a new . - /// - /// Type to serialize. - /// Value to serialize. - /// . - internal static JsonContent From(T value) - { - return new JsonContent(value); - } + return new JsonContent(value); } +} +/// +/// A class for application/json. +/// +/// The type to serialize +internal class JsonContent + : StringContent +{ /// - /// A class for application/json. + /// Initializes a new instance of the class. /// - /// The type to serialize - internal class JsonContent - : StringContent + /// Value to serialize. + public JsonContent(T value) + : base(ToJson(value)) { - /// - /// Initializes a new instance of the class. - /// - /// Value to serialize. - public JsonContent(T value) - : base(ToJson(value)) - { - Headers.ContentType = new MediaTypeHeaderValue("application/json"); - } + Headers.ContentType = new MediaTypeHeaderValue("application/json"); + } - private static string ToJson(T value) - { - return JsonSerializer.Serialize(value, SignhostJsonSerializerOptions.Default); - } + private static string ToJson(T value) + { + return JsonSerializer.Serialize(value, SignhostJsonSerializerOptions.Default); } } diff --git a/src/SignhostAPIClient/Rest/JsonConverters/LevelEnumConverter.cs b/src/SignhostAPIClient/Rest/JsonConverters/LevelEnumConverter.cs index 07c20313..06b9c0b8 100644 --- a/src/SignhostAPIClient/Rest/JsonConverters/LevelEnumConverter.cs +++ b/src/SignhostAPIClient/Rest/JsonConverters/LevelEnumConverter.cs @@ -3,54 +3,53 @@ using System.Text.Json.Serialization; using Signhost.APIClient.Rest.DataObjects; -namespace Signhost.APIClient.Rest.JsonConverters +namespace Signhost.APIClient.Rest.JsonConverters; + +/// +/// JSON converter factory for converting the enum. +/// Invalid values are mapped to . +/// +internal class LevelEnumConverter + : JsonConverter { - /// - /// JSON converter factory for converting the enum. - /// Invalid values are mapped to . - /// - internal class LevelEnumConverter - : JsonConverter + public override Level? Read( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options) { - public override Level? Read( - ref Utf8JsonReader reader, - Type typeToConvert, - JsonSerializerOptions options) - { - if (reader.TokenType == JsonTokenType.Null) { - return null; - } - - if (reader.TokenType == JsonTokenType.String) { - var value = reader.GetString() ?? string.Empty; - if (Enum.TryParse(value, out var level)) { - return level; - } - - return Level.Unknown; - } + if (reader.TokenType == JsonTokenType.Null) { + return null; + } - if (reader.TokenType == JsonTokenType.Number) { - int value = reader.GetInt32(); - if (Enum.IsDefined(typeof(Level), value)) { - return (Level)value; - } + if (reader.TokenType == JsonTokenType.String) { + var value = reader.GetString() ?? string.Empty; + if (Enum.TryParse(value, out var level)) { + return level; } return Level.Unknown; } - public override void Write( - Utf8JsonWriter writer, - Level? value, - JsonSerializerOptions options) - { - if (value is null) { - writer.WriteNullValue(); - } - else { - writer.WriteStringValue(value.ToString()); + if (reader.TokenType == JsonTokenType.Number) { + int value = reader.GetInt32(); + if (Enum.IsDefined(typeof(Level), value)) { + return (Level)value; } } + + return Level.Unknown; + } + + public override void Write( + Utf8JsonWriter writer, + Level? value, + JsonSerializerOptions options) + { + if (value is null) { + writer.WriteNullValue(); + } + else { + writer.WriteStringValue(value.ToString()); + } } } diff --git a/src/SignhostAPIClient/Rest/SignHostApiClient.cs b/src/SignhostAPIClient/Rest/SignHostApiClient.cs index a453f2cb..4c7f698b 100644 --- a/src/SignhostAPIClient/Rest/SignHostApiClient.cs +++ b/src/SignhostAPIClient/Rest/SignHostApiClient.cs @@ -9,475 +9,474 @@ using Signhost.APIClient.Rest.DataObjects; using Signhost.APIClient.Rest.ErrorHandling; -namespace Signhost.APIClient.Rest +namespace Signhost.APIClient.Rest; + +/// +/// Implements the interface which provides +/// an signhost api client implementation. +/// +public class SignhostApiClient + : ISignhostApiClient + , IDisposable { + private const string ApiVersion = "v1"; + + private static readonly string Version = typeof(SignhostApiClient) +#if TYPEINFO + .GetTypeInfo() +#endif + .Assembly.GetCustomAttribute() + .Version; + + private readonly ISignhostApiClientSettings settings; + private readonly HttpClient client; + /// - /// Implements the interface which provides - /// an signhost api client implementation. + /// Initializes a new instance of the class. + /// Set your usertoken and APPKey by creating a . /// - public class SignhostApiClient - : ISignhostApiClient - , IDisposable + /// . + public SignhostApiClient(ISignhostApiClientSettings settings) + : this(settings, new HttpClient()) { - private const string ApiVersion = "v1"; + } - private static readonly string Version = typeof(SignhostApiClient) -#if TYPEINFO - .GetTypeInfo() -#endif - .Assembly.GetCustomAttribute() - .Version; - - private readonly ISignhostApiClientSettings settings; - private readonly HttpClient client; - - /// - /// Initializes a new instance of the class. - /// Set your usertoken and APPKey by creating a . - /// - /// . - public SignhostApiClient(ISignhostApiClientSettings settings) - : this(settings, new HttpClient()) - { + /// + /// Initializes a new instance of the class. + /// Set your usertoken and APPKey by creating a . + /// + /// . + /// to use for all http calls. + public SignhostApiClient( + ISignhostApiClientSettings settings, + HttpClient httpClient) + { + this.settings = settings; + this.client = httpClient; + this.client.BaseAddress = new Uri( + settings.Endpoint + (settings.Endpoint.EndsWith("/") ? string.Empty : "/")); + this.client.DefaultRequestHeaders.UserAgent.Add( + new System.Net.Http.Headers.ProductInfoHeaderValue( + "SignhostClientLibrary", + Version)); + this.client.DefaultRequestHeaders.Add("Application", ApplicationHeader); + + if (!string.IsNullOrWhiteSpace(settings.UserToken)) { + this.client.DefaultRequestHeaders.Add("Authorization", AuthorizationHeader); } - /// - /// Initializes a new instance of the class. - /// Set your usertoken and APPKey by creating a . - /// - /// . - /// to use for all http calls. - public SignhostApiClient( - ISignhostApiClientSettings settings, - HttpClient httpClient) - { - this.settings = settings; - this.client = httpClient; - this.client.BaseAddress = new Uri( - settings.Endpoint + (settings.Endpoint.EndsWith("/") ? string.Empty : "/")); - this.client.DefaultRequestHeaders.UserAgent.Add( - new System.Net.Http.Headers.ProductInfoHeaderValue( - "SignhostClientLibrary", - Version)); - this.client.DefaultRequestHeaders.Add("Application", ApplicationHeader); - - if (!string.IsNullOrWhiteSpace(settings.UserToken)) { - this.client.DefaultRequestHeaders.Add("Authorization", AuthorizationHeader); - } - - this.client.DefaultRequestHeaders.Accept.Add(MediaTypeWithQualityHeaderValue.Parse($"application/vnd.signhost.{ApiVersion}+json")); - settings.AddHeader?.Invoke(this.client.DefaultRequestHeaders.Add); + this.client.DefaultRequestHeaders.Accept.Add(MediaTypeWithQualityHeaderValue.Parse($"application/vnd.signhost.{ApiVersion}+json")); + settings.AddHeader?.Invoke(this.client.DefaultRequestHeaders.Add); + } + + private string ApplicationHeader + => $"APPKey {settings.APPKey}"; + + private string AuthorizationHeader + => $"APIKey {settings.UserToken}"; + + /// + public async Task CreateTransactionAsync( + Transaction transaction) + => await CreateTransactionAsync(transaction, default) + .ConfigureAwait(false); + + /// + public async Task CreateTransactionAsync( + Transaction transaction, + CancellationToken cancellationToken = default) + { + if (transaction == null) { + throw new ArgumentNullException(nameof(transaction)); } - private string ApplicationHeader - => $"APPKey {settings.APPKey}"; + var result = await client + .PostAsync( + "transaction", + JsonContent.From(transaction), + cancellationToken) + .EnsureSignhostSuccessStatusCodeAsync() + .ConfigureAwait(false); - private string AuthorizationHeader - => $"APIKey {settings.UserToken}"; + return await result.Content.FromJsonAsync() + .ConfigureAwait(false); + } - /// - public async Task CreateTransactionAsync( - Transaction transaction) - => await CreateTransactionAsync(transaction, default) - .ConfigureAwait(false); + /// + public async Task> GetTransactionResponseAsync( + string transactionId) + => await GetTransactionResponseAsync(transactionId, default) + .ConfigureAwait(false); - /// - public async Task CreateTransactionAsync( - Transaction transaction, - CancellationToken cancellationToken = default) - { - if (transaction == null) { - throw new ArgumentNullException(nameof(transaction)); - } - - var result = await client - .PostAsync( - "transaction", - JsonContent.From(transaction), - cancellationToken) - .EnsureSignhostSuccessStatusCodeAsync() - .ConfigureAwait(false); + /// + public async Task> GetTransactionResponseAsync( + string transactionId, + CancellationToken cancellationToken = default) + { + if (transactionId == null) { + throw new ArgumentNullException(nameof(transactionId)); + } - return await result.Content.FromJsonAsync() - .ConfigureAwait(false); + if (string.IsNullOrWhiteSpace(transactionId)) { + throw new ArgumentException("Cannot be empty or contain only whitespaces.", nameof(transactionId)); } - /// - public async Task> GetTransactionResponseAsync( - string transactionId) - => await GetTransactionResponseAsync(transactionId, default) - .ConfigureAwait(false); + var result = await client + .GetAsync( + "transaction".JoinPaths(transactionId), + cancellationToken) + .EnsureSignhostSuccessStatusCodeAsync(HttpStatusCode.Gone) + .ConfigureAwait(false); + var transaction = await result.Content.FromJsonAsync() + .ConfigureAwait(false); - /// - public async Task> GetTransactionResponseAsync( - string transactionId, - CancellationToken cancellationToken = default) - { - if (transactionId == null) { - throw new ArgumentNullException(nameof(transactionId)); - } + return new ApiResponse(result, transaction); + } - if (string.IsNullOrWhiteSpace(transactionId)) { - throw new ArgumentException("Cannot be empty or contain only whitespaces.", nameof(transactionId)); - } + /// + public async Task GetTransactionAsync(string transactionId) + => await GetTransactionAsync(transactionId, default) + .ConfigureAwait(false); - var result = await client - .GetAsync( - "transaction".JoinPaths(transactionId), - cancellationToken) - .EnsureSignhostSuccessStatusCodeAsync(HttpStatusCode.Gone) - .ConfigureAwait(false); - var transaction = await result.Content.FromJsonAsync() - .ConfigureAwait(false); + /// + public async Task GetTransactionAsync( + string transactionId, + CancellationToken cancellationToken = default) + { + var response = await GetTransactionResponseAsync( + transactionId, + cancellationToken) + .ConfigureAwait(false); + + response.EnsureAvailableStatusCode(); + + return response.Value; + } + + /// + public async Task DeleteTransactionAsync( + string transactionId, + CancellationToken cancellationToken = default) + => await DeleteTransactionAsync( + transactionId, + default, + cancellationToken).ConfigureAwait(false); + + /// + public async Task DeleteTransactionAsync( + string transactionId, + DeleteTransactionOptions options) + => await DeleteTransactionAsync( + transactionId, + options, + default).ConfigureAwait(false); + + /// + public async Task DeleteTransactionAsync( + string transactionId, + DeleteTransactionOptions options, + CancellationToken cancellationToken = default) + { + if (transactionId == null) { + throw new ArgumentNullException(nameof(transactionId)); + } - return new ApiResponse(result, transaction); + if (string.IsNullOrWhiteSpace(transactionId)) { + throw new ArgumentException("Cannot be empty or contain only whitespaces.", nameof(transactionId)); } - /// - public async Task GetTransactionAsync(string transactionId) - => await GetTransactionAsync(transactionId, default) - .ConfigureAwait(false); + if (options == null) { + options = new DeleteTransactionOptions(); + } - /// - public async Task GetTransactionAsync( - string transactionId, - CancellationToken cancellationToken = default) - { - var response = await GetTransactionResponseAsync( - transactionId, + var request = new HttpRequestMessage(HttpMethod.Delete, "transaction".JoinPaths(transactionId)); + request.Content = JsonContent.From(options); + await client + .SendAsync( + request, cancellationToken) - .ConfigureAwait(false); + .EnsureSignhostSuccessStatusCodeAsync() + .ConfigureAwait(false); + } - response.EnsureAvailableStatusCode(); + /// + public async Task AddOrReplaceFileMetaToTransactionAsync( + FileMeta fileMeta, + string transactionId, + string fileId) + => await AddOrReplaceFileMetaToTransactionAsync( + fileMeta, + transactionId, + fileId, + default).ConfigureAwait(false); + + /// + public async Task AddOrReplaceFileMetaToTransactionAsync( + FileMeta fileMeta, + string transactionId, + string fileId, + CancellationToken cancellationToken = default) + { + if (fileMeta == null) { + throw new ArgumentNullException("fileMeta"); + } - return response.Value; + if (transactionId == null) { + throw new ArgumentNullException(nameof(transactionId)); } - /// - public async Task DeleteTransactionAsync( - string transactionId, - CancellationToken cancellationToken = default) - => await DeleteTransactionAsync( - transactionId, - default, - cancellationToken).ConfigureAwait(false); - - /// - public async Task DeleteTransactionAsync( - string transactionId, - DeleteTransactionOptions options) - => await DeleteTransactionAsync( - transactionId, - options, - default).ConfigureAwait(false); - - /// - public async Task DeleteTransactionAsync( - string transactionId, - DeleteTransactionOptions options, - CancellationToken cancellationToken = default) - { - if (transactionId == null) { - throw new ArgumentNullException(nameof(transactionId)); - } - - if (string.IsNullOrWhiteSpace(transactionId)) { - throw new ArgumentException("Cannot be empty or contain only whitespaces.", nameof(transactionId)); - } - - if (options == null) { - options = new DeleteTransactionOptions(); - } - - var request = new HttpRequestMessage(HttpMethod.Delete, "transaction".JoinPaths(transactionId)); - request.Content = JsonContent.From(options); - await client - .SendAsync( - request, - cancellationToken) - .EnsureSignhostSuccessStatusCodeAsync() - .ConfigureAwait(false); + if (string.IsNullOrWhiteSpace(transactionId)) { + throw new ArgumentException("Cannot be empty or contain only whitespaces.", nameof(transactionId)); } - /// - public async Task AddOrReplaceFileMetaToTransactionAsync( - FileMeta fileMeta, - string transactionId, - string fileId) - => await AddOrReplaceFileMetaToTransactionAsync( - fileMeta, - transactionId, - fileId, - default).ConfigureAwait(false); - - /// - public async Task AddOrReplaceFileMetaToTransactionAsync( - FileMeta fileMeta, - string transactionId, - string fileId, - CancellationToken cancellationToken = default) - { - if (fileMeta == null) { - throw new ArgumentNullException("fileMeta"); - } - - if (transactionId == null) { - throw new ArgumentNullException(nameof(transactionId)); - } - - if (string.IsNullOrWhiteSpace(transactionId)) { - throw new ArgumentException("Cannot be empty or contain only whitespaces.", nameof(transactionId)); - } - - if (fileId == null) { - throw new ArgumentNullException(nameof(fileId)); - } - - if (string.IsNullOrWhiteSpace(fileId)) { - throw new ArgumentException("Cannot be empty or contain only whitespaces.", nameof(fileId)); - } - - await client - .PutAsync( - "transaction".JoinPaths(transactionId, "file", fileId), - JsonContent.From(fileMeta), - cancellationToken) - .EnsureSignhostSuccessStatusCodeAsync() - .ConfigureAwait(false); + if (fileId == null) { + throw new ArgumentNullException(nameof(fileId)); + } + + if (string.IsNullOrWhiteSpace(fileId)) { + throw new ArgumentException("Cannot be empty or contain only whitespaces.", nameof(fileId)); } - /// - public async Task AddOrReplaceFileToTransactionAsync( + await client + .PutAsync( + "transaction".JoinPaths(transactionId, "file", fileId), + JsonContent.From(fileMeta), + cancellationToken) + .EnsureSignhostSuccessStatusCodeAsync() + .ConfigureAwait(false); + } + + /// + public async Task AddOrReplaceFileToTransactionAsync( + Stream fileStream, + string transactionId, + string fileId, + FileUploadOptions uploadOptions) + => await AddOrReplaceFileToTransactionAsync( + fileStream, + transactionId, + fileId, + uploadOptions, + default).ConfigureAwait(false); + + /// + public async Task AddOrReplaceFileToTransactionAsync( Stream fileStream, string transactionId, string fileId, - FileUploadOptions uploadOptions) - => await AddOrReplaceFileToTransactionAsync( - fileStream, - transactionId, - fileId, - uploadOptions, - default).ConfigureAwait(false); - - /// - public async Task AddOrReplaceFileToTransactionAsync( - Stream fileStream, - string transactionId, - string fileId, - FileUploadOptions uploadOptions, - CancellationToken cancellationToken = default) - { - if (fileStream == null) { - throw new ArgumentNullException(nameof(fileStream)); - } - - if (transactionId == null) { - throw new ArgumentNullException(nameof(transactionId)); - } - - if (string.IsNullOrWhiteSpace(transactionId)) { - throw new ArgumentException("Cannot be empty or contain only whitespaces.", nameof(transactionId)); - } - - if (fileId == null) { - throw new ArgumentNullException(nameof(fileId)); - } - - if (string.IsNullOrWhiteSpace(fileId)) { - throw new ArgumentException("Cannot be empty or contain only whitespaces.", nameof(fileId)); - } - - if (uploadOptions == null) { - uploadOptions = new FileUploadOptions(); - } - - var content = new StreamContent(fileStream) - .WithDigest(fileStream, uploadOptions.DigestOptions); - content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf"); - - await client - .PutAsync( - "transaction".JoinPaths(transactionId, "file", fileId), - content, - cancellationToken) - .EnsureSignhostSuccessStatusCodeAsync() - .ConfigureAwait(false); + FileUploadOptions uploadOptions, + CancellationToken cancellationToken = default) + { + if (fileStream == null) { + throw new ArgumentNullException(nameof(fileStream)); } - /// - public Task AddOrReplaceFileToTransaction( - Stream fileStream, - string transactionId, - string fileId) - { - return AddOrReplaceFileToTransactionAsync( - fileStream, - transactionId, - fileId, - null); + if (transactionId == null) { + throw new ArgumentNullException(nameof(transactionId)); } - /// - public async Task AddOrReplaceFileToTransactionAsync( - string filePath, - string transactionId, - string fileId, - FileUploadOptions uploadOptions) - => await AddOrReplaceFileToTransactionAsync( - filePath, - transactionId, - fileId, - uploadOptions, - default).ConfigureAwait(false); - - /// - public async Task AddOrReplaceFileToTransactionAsync( - string filePath, - string transactionId, - string fileId, - FileUploadOptions uploadOptions, - CancellationToken cancellationToken = default) - { - if (filePath == null) { - throw new ArgumentNullException(nameof(filePath)); - } - - using (Stream fileStream = System.IO.File.Open( - filePath, - FileMode.Open, - FileAccess.Read, - FileShare.Delete | FileShare.Read)) - { - await AddOrReplaceFileToTransactionAsync( - fileStream, - transactionId, - fileId, - uploadOptions, - cancellationToken) - .ConfigureAwait(false); - } + if (string.IsNullOrWhiteSpace(transactionId)) { + throw new ArgumentException("Cannot be empty or contain only whitespaces.", nameof(transactionId)); } - /// - public Task AddOrReplaceFileToTransaction( - string filePath, - string transactionId, - string fileId) - { - return AddOrReplaceFileToTransactionAsync( - filePath, - transactionId, - fileId, - null); + if (fileId == null) { + throw new ArgumentNullException(nameof(fileId)); } - /// - public async Task StartTransactionAsync( - string transactionId) - => await StartTransactionAsync(transactionId, default) - .ConfigureAwait(false); + if (string.IsNullOrWhiteSpace(fileId)) { + throw new ArgumentException("Cannot be empty or contain only whitespaces.", nameof(fileId)); + } + + if (uploadOptions == null) { + uploadOptions = new FileUploadOptions(); + } - /// - public async Task StartTransactionAsync( - string transactionId, - CancellationToken cancellationToken = default) + var content = new StreamContent(fileStream) + .WithDigest(fileStream, uploadOptions.DigestOptions); + content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf"); + + await client + .PutAsync( + "transaction".JoinPaths(transactionId, "file", fileId), + content, + cancellationToken) + .EnsureSignhostSuccessStatusCodeAsync() + .ConfigureAwait(false); + } + + /// + public Task AddOrReplaceFileToTransaction( + Stream fileStream, + string transactionId, + string fileId) + { + return AddOrReplaceFileToTransactionAsync( + fileStream, + transactionId, + fileId, + null); + } + + /// + public async Task AddOrReplaceFileToTransactionAsync( + string filePath, + string transactionId, + string fileId, + FileUploadOptions uploadOptions) + => await AddOrReplaceFileToTransactionAsync( + filePath, + transactionId, + fileId, + uploadOptions, + default).ConfigureAwait(false); + + /// + public async Task AddOrReplaceFileToTransactionAsync( + string filePath, + string transactionId, + string fileId, + FileUploadOptions uploadOptions, + CancellationToken cancellationToken = default) + { + if (filePath == null) { + throw new ArgumentNullException(nameof(filePath)); + } + + using (Stream fileStream = System.IO.File.Open( + filePath, + FileMode.Open, + FileAccess.Read, + FileShare.Delete | FileShare.Read)) { - if (transactionId == null) { - throw new ArgumentNullException(nameof(transactionId)); - } - - if (string.IsNullOrWhiteSpace(transactionId)) { - throw new ArgumentException("Cannot be empty or contain only whitespaces.", nameof(transactionId)); - } - - await client - .PutAsync( - "transaction".JoinPaths(transactionId, "start"), - null, + await AddOrReplaceFileToTransactionAsync( + fileStream, + transactionId, + fileId, + uploadOptions, cancellationToken) - .EnsureSignhostSuccessStatusCodeAsync() .ConfigureAwait(false); } + } - /// - public async Task GetReceiptAsync(string transactionId) - => await GetReceiptAsync(transactionId, default) - .ConfigureAwait(false); + /// + public Task AddOrReplaceFileToTransaction( + string filePath, + string transactionId, + string fileId) + { + return AddOrReplaceFileToTransactionAsync( + filePath, + transactionId, + fileId, + null); + } - /// - public async Task GetReceiptAsync( - string transactionId, - CancellationToken cancellationToken = default) - { - if (transactionId == null) { - throw new ArgumentNullException(nameof(transactionId)); - } + /// + public async Task StartTransactionAsync( + string transactionId) + => await StartTransactionAsync(transactionId, default) + .ConfigureAwait(false); - if (string.IsNullOrWhiteSpace(transactionId)) { - throw new ArgumentException("Cannot be empty or contain only whitespaces.", nameof(transactionId)); - } + /// + public async Task StartTransactionAsync( + string transactionId, + CancellationToken cancellationToken = default) + { + if (transactionId == null) { + throw new ArgumentNullException(nameof(transactionId)); + } - var result = await client - .GetStreamAsync( - "file".JoinPaths("receipt", transactionId)) - .ConfigureAwait(false); + if (string.IsNullOrWhiteSpace(transactionId)) { + throw new ArgumentException("Cannot be empty or contain only whitespaces.", nameof(transactionId)); + } + + await client + .PutAsync( + "transaction".JoinPaths(transactionId, "start"), + null, + cancellationToken) + .EnsureSignhostSuccessStatusCodeAsync() + .ConfigureAwait(false); + } - return result; + /// + public async Task GetReceiptAsync(string transactionId) + => await GetReceiptAsync(transactionId, default) + .ConfigureAwait(false); + + /// + public async Task GetReceiptAsync( + string transactionId, + CancellationToken cancellationToken = default) + { + if (transactionId == null) { + throw new ArgumentNullException(nameof(transactionId)); } - /// - public async Task GetDocumentAsync( - string transactionId, - string fileId) - => await GetDocumentAsync(transactionId, fileId, default) - .ConfigureAwait(false); + if (string.IsNullOrWhiteSpace(transactionId)) { + throw new ArgumentException("Cannot be empty or contain only whitespaces.", nameof(transactionId)); + } - /// - public async Task GetDocumentAsync( - string transactionId, - string fileId, - CancellationToken cancellationToken = default) - { - if (transactionId == null) { - throw new ArgumentNullException(nameof(transactionId)); - } + var result = await client + .GetStreamAsync( + "file".JoinPaths("receipt", transactionId)) + .ConfigureAwait(false); - if (string.IsNullOrWhiteSpace(transactionId)) { - throw new ArgumentException("Cannot be empty or contain only whitespaces.", nameof(transactionId)); - } + return result; + } - if (fileId == null) { - throw new ArgumentNullException(nameof(fileId)); - } + /// + public async Task GetDocumentAsync( + string transactionId, + string fileId) + => await GetDocumentAsync(transactionId, fileId, default) + .ConfigureAwait(false); - if (string.IsNullOrWhiteSpace(fileId)) { - throw new ArgumentException("Cannot be empty or contain only whitespaces.", nameof(fileId)); - } + /// + public async Task GetDocumentAsync( + string transactionId, + string fileId, + CancellationToken cancellationToken = default) + { + if (transactionId == null) { + throw new ArgumentNullException(nameof(transactionId)); + } - var result = await client - .GetStreamAsync( - "transaction".JoinPaths(transactionId, "file", fileId)) - .ConfigureAwait(false); + if (string.IsNullOrWhiteSpace(transactionId)) { + throw new ArgumentException("Cannot be empty or contain only whitespaces.", nameof(transactionId)); + } - return result; + if (fileId == null) { + throw new ArgumentNullException(nameof(fileId)); } - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); + if (string.IsNullOrWhiteSpace(fileId)) { + throw new ArgumentException("Cannot be empty or contain only whitespaces.", nameof(fileId)); } - /// - /// Disposes the instance. - /// - /// Is callled. - protected virtual void Dispose(bool disposing) - { - if (disposing) { - client?.Dispose(); - } + var result = await client + .GetStreamAsync( + "transaction".JoinPaths(transactionId, "file", fileId)) + .ConfigureAwait(false); + + return result; + } + + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Disposes the instance. + /// + /// Is callled. + protected virtual void Dispose(bool disposing) + { + if (disposing) { + client?.Dispose(); } } } diff --git a/src/SignhostAPIClient/Rest/SignHostApiClientSettings.cs b/src/SignhostAPIClient/Rest/SignHostApiClientSettings.cs index b4afed65..c96340d4 100644 --- a/src/SignhostAPIClient/Rest/SignHostApiClientSettings.cs +++ b/src/SignhostAPIClient/Rest/SignHostApiClientSettings.cs @@ -1,29 +1,28 @@ using System; -namespace Signhost.APIClient.Rest +namespace Signhost.APIClient.Rest; + +public class SignhostApiClientSettings + : ISignhostApiClientSettings { - public class SignhostApiClientSettings - : ISignhostApiClientSettings - { - public const string DefaultEndpoint = "https://api.signhost.com/api/"; + public const string DefaultEndpoint = "https://api.signhost.com/api/"; - public SignhostApiClientSettings(string appkey, string userToken) - { - APPKey = appkey; - UserToken = userToken; - } + public SignhostApiClientSettings(string appkey, string userToken) + { + APPKey = appkey; + UserToken = userToken; + } - public SignhostApiClientSettings(string appkey) - { - APPKey = appkey; - } + public SignhostApiClientSettings(string appkey) + { + APPKey = appkey; + } - public string UserToken { get; set; } + public string UserToken { get; set; } - public string APPKey { get; private set; } + public string APPKey { get; private set; } - public string Endpoint { get; set; } = DefaultEndpoint; + public string Endpoint { get; set; } = DefaultEndpoint; - public Action AddHeader { get; set; } - } + public Action AddHeader { get; set; } } diff --git a/src/SignhostAPIClient/Rest/SignhostApiReceiver.cs b/src/SignhostAPIClient/Rest/SignhostApiReceiver.cs index da6c1899..d4fb3bfa 100644 --- a/src/SignhostAPIClient/Rest/SignhostApiReceiver.cs +++ b/src/SignhostAPIClient/Rest/SignhostApiReceiver.cs @@ -7,86 +7,85 @@ using Signhost.APIClient.Rest; using Signhost.APIClient.Rest.DataObjects; -namespace Signhost.APIClient +namespace Signhost.APIClient; + +/// +/// Implements the interface which provides +/// a Signhost API receiver implementation. +/// +public class SignhostApiReceiver + : ISignhostApiReceiver { + private readonly SignhostApiReceiverSettings settings; + /// - /// Implements the interface which provides - /// a Signhost API receiver implementation. + /// Initializes a new instance of the class. + /// Set your SharedSecret by creating a . /// - public class SignhostApiReceiver - : ISignhostApiReceiver + /// + /// Settings for the receiver. + /// + public SignhostApiReceiver(SignhostApiReceiverSettings receiverSettings) { - private readonly SignhostApiReceiverSettings settings; + this.settings = receiverSettings; + } - /// - /// Initializes a new instance of the class. - /// Set your SharedSecret by creating a . - /// - /// - /// Settings for the receiver. - /// - public SignhostApiReceiver(SignhostApiReceiverSettings receiverSettings) - { - this.settings = receiverSettings; - } + /// + public bool IsPostbackChecksumValid( + IDictionary headers, + string body, + out Transaction postbackTransaction) + { + postbackTransaction = null; + string postbackChecksum; + string calculatedChecksum; + PostbackTransaction postback; - /// - public bool IsPostbackChecksumValid( - IDictionary headers, - string body, - out Transaction postbackTransaction) - { - postbackTransaction = null; - string postbackChecksum; - string calculatedChecksum; - PostbackTransaction postback; + postback = DeserializeToPostbackTransaction(body); + postbackChecksum = GetChecksumFromHeadersOrPostback(headers, postback); + bool parametersAreValid = HasValidChecksumProperties(postbackChecksum, postback); - postback = DeserializeToPostbackTransaction(body); - postbackChecksum = GetChecksumFromHeadersOrPostback(headers, postback); - bool parametersAreValid = HasValidChecksumProperties(postbackChecksum, postback); + if (parametersAreValid) { + calculatedChecksum = CalculateChecksumFromPostback(postback); + postbackTransaction = postback; + } else { + return false; + } - if (parametersAreValid) { - calculatedChecksum = CalculateChecksumFromPostback(postback); - postbackTransaction = postback; - } else { - return false; - } + return Equals(calculatedChecksum, postbackChecksum); + } - return Equals(calculatedChecksum, postbackChecksum); + private string CalculateChecksumFromPostback(PostbackTransaction postback) + { + using (var sha1 = SHA1.Create()) { + var checksumBytes = sha1.ComputeHash(Encoding.UTF8.GetBytes( + $"{postback.Id}||{(int)postback.Status}|{settings.SharedSecret}")); + return BitConverter.ToString(checksumBytes) + .Replace("-", string.Empty) + .ToLower(); } + } - private string CalculateChecksumFromPostback(PostbackTransaction postback) - { - using (var sha1 = SHA1.Create()) { - var checksumBytes = sha1.ComputeHash(Encoding.UTF8.GetBytes( - $"{postback.Id}||{(int)postback.Status}|{settings.SharedSecret}")); - return BitConverter.ToString(checksumBytes) - .Replace("-", string.Empty) - .ToLower(); - } - } + private PostbackTransaction DeserializeToPostbackTransaction(string body) + { + return JsonSerializer.Deserialize(body, SignhostJsonSerializerOptions.Default); + } - private PostbackTransaction DeserializeToPostbackTransaction(string body) - { - return JsonSerializer.Deserialize(body, SignhostJsonSerializerOptions.Default); + private string GetChecksumFromHeadersOrPostback( + IDictionary headers, + PostbackTransaction postback) + { + string[] postbackChecksumArray; + if (headers.TryGetValue("Checksum", out postbackChecksumArray)) { + return postbackChecksumArray.First(); } - - private string GetChecksumFromHeadersOrPostback( - IDictionary headers, - PostbackTransaction postback) - { - string[] postbackChecksumArray; - if (headers.TryGetValue("Checksum", out postbackChecksumArray)) { - return postbackChecksumArray.First(); - } - else { - return postback.Checksum; - } + else { + return postback.Checksum; } + } - private bool HasValidChecksumProperties(string postbackChecksum, PostbackTransaction postback) - { - return !string.IsNullOrWhiteSpace(postbackChecksum) && !string.IsNullOrWhiteSpace(postback.Id); - } + private bool HasValidChecksumProperties(string postbackChecksum, PostbackTransaction postback) + { + return !string.IsNullOrWhiteSpace(postbackChecksum) && !string.IsNullOrWhiteSpace(postback.Id); } } diff --git a/src/SignhostAPIClient/Rest/SignhostApiReceiverSettings.cs b/src/SignhostAPIClient/Rest/SignhostApiReceiverSettings.cs index d3d962aa..c1b2bbce 100644 --- a/src/SignhostAPIClient/Rest/SignhostApiReceiverSettings.cs +++ b/src/SignhostAPIClient/Rest/SignhostApiReceiverSettings.cs @@ -1,19 +1,18 @@ -namespace Signhost.APIClient.Rest +namespace Signhost.APIClient.Rest; + +/// +/// Registers the necessary settings for the class. +/// +public class SignhostApiReceiverSettings { - /// - /// Registers the necessary settings for the class. - /// - public class SignhostApiReceiverSettings + public SignhostApiReceiverSettings(string sharedsecret) { - public SignhostApiReceiverSettings(string sharedsecret) - { - SharedSecret = sharedsecret; - } - - /// - /// Gets the shared secret. - /// - /// The shared secret key issued by Signhost.com. - public string SharedSecret { get; private set; } + SharedSecret = sharedsecret; } + + /// + /// Gets the shared secret. + /// + /// The shared secret key issued by Signhost.com. + public string SharedSecret { get; private set; } } diff --git a/src/SignhostAPIClient/Rest/SignhostJsonSerializerOptions.cs b/src/SignhostAPIClient/Rest/SignhostJsonSerializerOptions.cs index 37845021..22c34542 100644 --- a/src/SignhostAPIClient/Rest/SignhostJsonSerializerOptions.cs +++ b/src/SignhostAPIClient/Rest/SignhostJsonSerializerOptions.cs @@ -1,23 +1,22 @@ using System.Text.Json; using System.Text.Json.Serialization; -namespace Signhost.APIClient.Rest +namespace Signhost.APIClient.Rest; + +/// +/// Centralized JSON serialization options for Signhost API. +/// +public static class SignhostJsonSerializerOptions { /// - /// Centralized JSON serialization options for Signhost API. + /// Gets the default JSON serializer options. /// - public static class SignhostJsonSerializerOptions + public static JsonSerializerOptions Default { get; } = new JsonSerializerOptions { - /// - /// Gets the default JSON serializer options. - /// - public static JsonSerializerOptions Default { get; } = new JsonSerializerOptions - { - PropertyNameCaseInsensitive = true, - DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, - Converters = { - new JsonStringEnumConverter(), - }, - }; - } + PropertyNameCaseInsensitive = true, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + Converters = { + new JsonStringEnumConverter(), + }, + }; } diff --git a/src/SignhostAPIClient/Rest/StreamContentDigestOptionsExtensions.cs b/src/SignhostAPIClient/Rest/StreamContentDigestOptionsExtensions.cs index 3ae2389b..eb75441a 100644 --- a/src/SignhostAPIClient/Rest/StreamContentDigestOptionsExtensions.cs +++ b/src/SignhostAPIClient/Rest/StreamContentDigestOptionsExtensions.cs @@ -3,95 +3,94 @@ using System.Net.Http; using System.Security.Cryptography; -namespace Signhost.APIClient.Rest +namespace Signhost.APIClient.Rest; + +/// +/// digest extensions. +/// +public static class StreamContentDigestOptionsExtensions { /// - /// digest extensions. + /// Digest extension method on the . /// - public static class StreamContentDigestOptionsExtensions + /// + /// of the filestream. + /// No digest is calculated if the stream is not . + /// digest options to use. + /// . + public static StreamContent WithDigest( + this StreamContent content, + Stream fileStream, + FileDigestOptions options) { - /// - /// Digest extension method on the . - /// - /// - /// of the filestream. - /// No digest is calculated if the stream is not . - /// digest options to use. - /// . - public static StreamContent WithDigest( - this StreamContent content, - Stream fileStream, - FileDigestOptions options) - { - if (!options.UseFileDigesting || options.DigestHashAlgorithm == null) { - return content; - } - - SetHashValue(fileStream, options); - - string base64Digest = Convert.ToBase64String(options.DigestHashValue); - - content.Headers.Add("Digest", $"{options.DigestHashAlgorithm}={base64Digest}"); - + if (!options.UseFileDigesting || options.DigestHashAlgorithm == null) { return content; } - private static void SetHashValue( - Stream fileStream, - FileDigestOptions options) - { - if (options.DigestHashValue != null) { - return; - } + SetHashValue(fileStream, options); - if (!fileStream.CanSeek) { - return; - } + string base64Digest = Convert.ToBase64String(options.DigestHashValue); - long position = fileStream.Position; + content.Headers.Add("Digest", $"{options.DigestHashAlgorithm}={base64Digest}"); - using (var algo = HashAlgorithmCreate(options)) { - options.DigestHashValue = algo.ComputeHash(fileStream); - } + return content; + } - fileStream.Position = position; + private static void SetHashValue( + Stream fileStream, + FileDigestOptions options) + { + if (options.DigestHashValue != null) { + return; } - private static HashAlgorithm HashAlgorithmCreate( - FileDigestOptions options) - { - string algorithmName = options.DigestHashAlgorithm; - HashAlgorithm algorithm = null; + if (!fileStream.CanSeek) { + return; + } + + long position = fileStream.Position; + + using (var algo = HashAlgorithmCreate(options)) { + options.DigestHashValue = algo.ComputeHash(fileStream); + } + + fileStream.Position = position; + } + + private static HashAlgorithm HashAlgorithmCreate( + FileDigestOptions options) + { + string algorithmName = options.DigestHashAlgorithm; + HashAlgorithm algorithm = null; #if NET462 - algorithm = HashAlgorithm.Create(algorithmName); + algorithm = HashAlgorithm.Create(algorithmName); #else - algorithm = algorithmName switch { - "SHA1" or "SHA-1" => SHA1.Create(), - "SHA256" or "SHA-256" => SHA256.Create(), - "SHA384" or "SHA-384" => SHA384.Create(), - "SHA512" or "SHA-512" => SHA512.Create(), - - _ => null, - }; + algorithm = algorithmName switch { + "SHA1" or "SHA-1" => SHA1.Create(), + "SHA256" or "SHA-256" => SHA256.Create(), + "SHA384" or "SHA-384" => SHA384.Create(), + "SHA512" or "SHA-512" => SHA512.Create(), + + _ => null, + }; #endif - if (algorithm == null && options.DigestHashValue == null) { - algorithm = DefaultHashAlgorithm(); - options.DigestHashAlgorithm = algorithm.GetType().Name; - } - - if (algorithm == null) { - throw new InvalidOperationException($"No hash algorithm for '{algorithmName}'"); - } + if (algorithm == null && options.DigestHashValue == null) { + algorithm = DefaultHashAlgorithm(); + options.DigestHashAlgorithm = algorithm.GetType().Name; + } - return algorithm; + if (algorithm == null) { + throw new InvalidOperationException($"No hash algorithm for '{algorithmName}'"); } - private static HashAlgorithm DefaultHashAlgorithm() => + return algorithm; + } + + private static HashAlgorithm DefaultHashAlgorithm() => #if NET462 - HashAlgorithm.Create(); + HashAlgorithm.Create(); #else - SHA256.Create(); + SHA256.Create(); #endif - } } diff --git a/src/SignhostAPIClient/Rest/UriPathExtensions.cs b/src/SignhostAPIClient/Rest/UriPathExtensions.cs index 39fb97fb..9f13c529 100644 --- a/src/SignhostAPIClient/Rest/UriPathExtensions.cs +++ b/src/SignhostAPIClient/Rest/UriPathExtensions.cs @@ -1,25 +1,24 @@ using System; using System.Linq; -namespace Signhost.APIClient.Rest +namespace Signhost.APIClient.Rest; + +internal static class UriPathExtensions { - internal static class UriPathExtensions + internal static UriBuilder AppendPathSegment(this string url) { - internal static UriBuilder AppendPathSegment(this string url) - { - var builder = new UriBuilder(url); + var builder = new UriBuilder(url); - return builder; - } + return builder; + } - internal static Uri JoinPaths( - this string url, - params string[] segments) - { - var segmentList = segments.ToList(); - segmentList.Insert(0, url); - var escaped = segmentList.Select(seg => Uri.EscapeDataString(seg)); - return new Uri(string.Join("/", escaped), UriKind.Relative); - } + internal static Uri JoinPaths( + this string url, + params string[] segments) + { + var segmentList = segments.ToList(); + segmentList.Insert(0, url); + var escaped = segmentList.Select(seg => Uri.EscapeDataString(seg)); + return new Uri(string.Join("/", escaped), UriKind.Relative); } } From 0789abb43a9e6d89b990f43d8ccfbbd975c88e22 Mon Sep 17 00:00:00 2001 From: Anthony Timmers Date: Fri, 26 Sep 2025 19:28:30 +0200 Subject: [PATCH 7/7] Remove support weak digest hash algos Also refactor file digest options to use enum for hash algorithms and update related tests --- .../SignhostApiClientTests.cs | 6 +- .../Rest/DigestHashAlgorithmNames.cs | 30 ++++++++++ .../Rest/FileDigestOptions.cs | 4 +- .../StreamContentDigestOptionsExtensions.cs | 55 ++++++++----------- 4 files changed, 59 insertions(+), 36 deletions(-) create mode 100644 src/SignhostAPIClient/Rest/DigestHashAlgorithmNames.cs diff --git a/src/SignhostAPIClient.Tests/SignhostApiClientTests.cs b/src/SignhostAPIClient.Tests/SignhostApiClientTests.cs index aee6ccff..80e0fbb7 100644 --- a/src/SignhostAPIClient.Tests/SignhostApiClientTests.cs +++ b/src/SignhostAPIClient.Tests/SignhostApiClientTests.cs @@ -462,7 +462,7 @@ await signhostApiClient.AddOrReplaceFileToTransactionAsync( new FileUploadOptions{ DigestOptions = new FileDigestOptions { - DigestHashAlgorithm = "SHA-512" + DigestHashAlgorithm = DigestHashAlgorithm.SHA512 } }); } @@ -476,7 +476,7 @@ public async Task when_AddOrReplaceFileToTransaction_with_digest_value_is_used_a var mockHttp = new MockHttpMessageHandler(); mockHttp .Expect(HttpMethod.Put, "http://localhost/api/transaction/transaction Id/file/file Id") - .WithHeaders("Digest", "SHA-1=AAEC") + .WithHeaders("Digest", "SHA-256=AAEC") .Respond(HttpStatusCode.OK); using (var httpClient = mockHttp.ToHttpClient()) { @@ -490,7 +490,7 @@ await signhostApiClient.AddOrReplaceFileToTransactionAsync( { DigestOptions = new FileDigestOptions { - DigestHashAlgorithm = "SHA-1", + DigestHashAlgorithm = DigestHashAlgorithm.SHA256, DigestHashValue = new byte[] { 0x00, 0x01, 0x02 } } }); diff --git a/src/SignhostAPIClient/Rest/DigestHashAlgorithmNames.cs b/src/SignhostAPIClient/Rest/DigestHashAlgorithmNames.cs new file mode 100644 index 00000000..c41d87e9 --- /dev/null +++ b/src/SignhostAPIClient/Rest/DigestHashAlgorithmNames.cs @@ -0,0 +1,30 @@ +namespace Signhost.APIClient.Rest; + +/// +/// Provides constants for hash algorithm names used in HTTP Digest headers, +/// following the naming conventions specified in RFC 3230 (Instance Digests in HTTP) +/// and RFC 5843 (Additional Hash Algorithms for HTTP Instance Digests). +/// +/// These names are in accordance with the Digest header in HTTP requests, +/// where the header specifies the algorithm used to create the digest of the resource. +/// +/// For more information: +/// https://evidos.github.io/endpoints/##/paths//api/transaction/%7BtransactionId%7D/file/%7BfileId%7D/put +/// +public enum DigestHashAlgorithm +{ + /// + /// Use no digest. + /// + None = 0, + + /// + /// SHA-256 hash algorithm, as specified in RFC 5843. + /// + SHA256, + + /// + /// SHA-512 hash algorithm, as specified in RFC 5843. + /// + SHA512, +} diff --git a/src/SignhostAPIClient/Rest/FileDigestOptions.cs b/src/SignhostAPIClient/Rest/FileDigestOptions.cs index bc0218b6..c5580a2a 100644 --- a/src/SignhostAPIClient/Rest/FileDigestOptions.cs +++ b/src/SignhostAPIClient/Rest/FileDigestOptions.cs @@ -1,7 +1,7 @@ namespace Signhost.APIClient.Rest; /// -/// File digest options for file uploads +/// File digest options for file uploads. /// public class FileDigestOptions { @@ -16,7 +16,7 @@ public class FileDigestOptions /// the hash value or the digest algorithm that is used /// to set the . /// - public string DigestHashAlgorithm { get; set; } = "SHA-256"; + public DigestHashAlgorithm DigestHashAlgorithm { get; set; } = DigestHashAlgorithm.SHA256; /// /// Gets or sets the hash digest value, you can set this yourself diff --git a/src/SignhostAPIClient/Rest/StreamContentDigestOptionsExtensions.cs b/src/SignhostAPIClient/Rest/StreamContentDigestOptionsExtensions.cs index eb75441a..32e27d47 100644 --- a/src/SignhostAPIClient/Rest/StreamContentDigestOptionsExtensions.cs +++ b/src/SignhostAPIClient/Rest/StreamContentDigestOptionsExtensions.cs @@ -23,7 +23,10 @@ public static StreamContent WithDigest( Stream fileStream, FileDigestOptions options) { - if (!options.UseFileDigesting || options.DigestHashAlgorithm == null) { + if ( + !options.UseFileDigesting || + options.DigestHashAlgorithm == DigestHashAlgorithm.None + ) { return content; } @@ -31,11 +34,22 @@ public static StreamContent WithDigest( string base64Digest = Convert.ToBase64String(options.DigestHashValue); - content.Headers.Add("Digest", $"{options.DigestHashAlgorithm}={base64Digest}"); + content.Headers.Add("Digest", $"{GetDigestHashAlgorithmName(options)}={base64Digest}"); return content; } + private static string GetDigestHashAlgorithmName(FileDigestOptions options) + { + return options.DigestHashAlgorithm switch { + DigestHashAlgorithm.SHA256 => "SHA-256", + DigestHashAlgorithm.SHA512 => "SHA-512", + + _ => throw new InvalidOperationException( + $"No hash algorithm name for '{options.DigestHashAlgorithm}'"), + }; + } + private static void SetHashValue( Stream fileStream, FileDigestOptions options) @@ -60,37 +74,16 @@ private static void SetHashValue( private static HashAlgorithm HashAlgorithmCreate( FileDigestOptions options) { - string algorithmName = options.DigestHashAlgorithm; - HashAlgorithm algorithm = null; - + return options.DigestHashAlgorithm switch { #if NET462 - algorithm = HashAlgorithm.Create(algorithmName); + DigestHashAlgorithm.SHA256 => HashAlgorithm.Create("SHA256"), + DigestHashAlgorithm.SHA512 => HashAlgorithm.Create("SHA512"), #else - algorithm = algorithmName switch { - "SHA1" or "SHA-1" => SHA1.Create(), - "SHA256" or "SHA-256" => SHA256.Create(), - "SHA384" or "SHA-384" => SHA384.Create(), - "SHA512" or "SHA-512" => SHA512.Create(), - - _ => null, - }; + DigestHashAlgorithm.SHA256 => SHA256.Create(), + DigestHashAlgorithm.SHA512 => SHA512.Create(), #endif - if (algorithm == null && options.DigestHashValue == null) { - algorithm = DefaultHashAlgorithm(); - options.DigestHashAlgorithm = algorithm.GetType().Name; - } - - if (algorithm == null) { - throw new InvalidOperationException($"No hash algorithm for '{algorithmName}'"); - } - - return algorithm; + _ => throw new InvalidOperationException( + $"No hash algorithm for '{options.DigestHashAlgorithm}'"), + }; } - - private static HashAlgorithm DefaultHashAlgorithm() => -#if NET462 - HashAlgorithm.Create(); -#else - SHA256.Create(); -#endif }