diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2e14be2f..f1612391 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,20 +5,26 @@ The format is based on [Keep a Changelog](http://keepachangelog.com)
and this project adheres to [Semantic Versioning](http://semver.org).
## [Unreleased] - TBD
+
+
+## [1.2.0] - 2023-07-03
### Added
- Added Readme and License files to Nuget package
- `OAuth2Service`: added ability to configure token expiration time
- Added OAuth2 service to SignNow service container
- All the services can use custom HttpClient via constructor of class [#148](https://github.com/signnow/SignNow.NET/issues/148)
+- Complex Text Tags support while upload document with Fields
### Changed
- `OAuth2Service` moved to `SignNow.Net.Services` namespace
+
## [1.1.1] - 2023-05-02
### Added
- Properties for sign invite that allows you to prefill text in the Signature field, allows for signers to use their saved signature, allows recipients reassign this invite to another email address, allow recipients decline the invite.
- Add support for field type `stamp` [#149](https://github.com/signnow/SignNow.NET/issues/149)
+
## [1.1.0] - 2023-01-23
### Added
- The `Thumbnail` property on `Model.SignNowDocument`, which allows you to get document thumbnails in small, medium and large image sizes
@@ -40,6 +46,7 @@ and this project adheres to [Semantic Versioning](http://semver.org).
### Changed
- `FieldJsonAttributes` added to `ISignNowFields` that allows you to get Field attributes
+
## [0.9.0] - 2021-07-07
### Added
- `IUserService.GetModifiedDocumentsAsync` that allows to get all modified documents for User
@@ -52,11 +59,13 @@ and this project adheres to [Semantic Versioning](http://semver.org).
- `IFolderService.RenameFolderAsync` that allows you to renames a folder.
- `IDocumentService.MoveDocumentAsync` that allows you to move the document to a specified folder.
+
## [0.8.0] - 2021-04-26
### Added
- `IDocumentService.CreateTemplateFromDocumentAsync` that allows to create template by flattening an existing document
- `IDocumentService.CreateDocumentFromTemplateAsync` that allows to create document from the template
+
## [0.7.0] - 2021-03-28
### Added
- `ISignInvite.CreateInviteAsync` that allows to create embedded signing invite for a document
@@ -66,6 +75,7 @@ and this project adheres to [Semantic Versioning](http://semver.org).
### Changed
- Changed JsonConverter for `Model.SignNowInvite` properties
+
## [0.6.0-beta] - 2020-11-17
### Added
- Carbon Copy for freeform invite and role-based invite [#106](https://github.com/signnow/SignNow.NET/issues/106)
@@ -87,6 +97,7 @@ and this project adheres to [Semantic Versioning](http://semver.org).
### Fixed
- Fixed `Models.FieldContents.RadiobuttonContent` converting error [#104](https://github.com/signnow/SignNow.NET/issues/104)
+
## [0.5.1-beta] - 2020-04-18
### Changed
- Upgraded netcore version from 2.x to 3.x for `SignNow.Net.Test`
@@ -172,8 +183,10 @@ and this project adheres to [Semantic Versioning](http://semver.org).
[create role-based invite]: https://github.com/signnow/SignNow.NET/blob/develop/README.md#create-role-based-invite
[create freeform invite]: https://github.com/signnow/SignNow.NET/blob/develop/README.md#create-freeform-invite
-
-[Unreleased]: https://github.com/signnow/SignNow.NET/compare/1.1.0...HEAD
+
+[Unreleased]: https://github.com/signnow/SignNow.NET/compare/1.2.0...HEAD
+[1.1.1]: https://github.com/signnow/SignNow.NET/compare/1.1.1...1.2.0
+[1.1.1]: https://github.com/signnow/SignNow.NET/compare/1.1.0...1.1.1
[1.1.0]: https://github.com/signnow/SignNow.NET/compare/1.0.0...1.1.0
[1.0.0]: https://github.com/signnow/SignNow.NET/compare/0.9.0...1.0.0
[0.9.0]: https://github.com/signnow/SignNow.NET/compare/0.8.0...0.9.0
diff --git a/SignNow.Net.Examples/ExamplesRunner.cs b/SignNow.Net.Examples/ExamplesRunner.cs
index ff0a02c6..2d12638e 100644
--- a/SignNow.Net.Examples/ExamplesRunner.cs
+++ b/SignNow.Net.Examples/ExamplesRunner.cs
@@ -80,7 +80,7 @@ public ExamplesRunner()
///
/// Delete test document after test.
///
- public void DeleteTestDocument(string disposableDocumentId)
+ private void DeleteTestDocument(string disposableDocumentId)
{
if (string.IsNullOrEmpty(disposableDocumentId))
{
diff --git a/SignNow.Net.Test/UnitTests/Models/ComplexTags/ComplexTagsTest.cs b/SignNow.Net.Test/UnitTests/Models/ComplexTags/ComplexTagsTest.cs
new file mode 100644
index 00000000..f411d7aa
--- /dev/null
+++ b/SignNow.Net.Test/UnitTests/Models/ComplexTags/ComplexTagsTest.cs
@@ -0,0 +1,199 @@
+using System;
+using System.Collections.Generic;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using SignNow.Net.Model.ComplexTags;
+
+namespace UnitTests.Models.ComplexTags
+{
+ [TestClass]
+ public class ComplexTagsTest
+ {
+ [TestMethod]
+ public void ShouldSerializeAttachmentsTag()
+ {
+ var tag = new AttachmentTag
+ {
+ Height = 100,
+ Width = 200,
+ Label = "label_name",
+ Required = true,
+ Role = "Role_1",
+ TagName = "attached document"
+ };
+
+ var expected = @"{
+ ""type"": ""attachments"",
+ ""label"": ""label_name"",
+ ""tag_name"": ""attached document"",
+ ""role"": ""Role_1"",
+ ""required"": true,
+ ""width"": 200,
+ ""height"": 100
+ }";
+
+ Assert.That.JsonEqual(expected, tag);
+ }
+
+ [TestMethod]
+ public void ShouldSerializeCheckBoxTag()
+ {
+ var tag = new CheckBoxTag
+ {
+ Height = 12,
+ Width = 12,
+ Required = true,
+ Role = "CLIENT",
+ TagName = "CheckboxTagExample"
+ };
+
+ var expected = @"{
+ ""type"": ""checkbox"",
+ ""tag_name"": ""CheckboxTagExample"",
+ ""role"": ""CLIENT"",
+ ""required"": true,
+ ""width"": 12,
+ ""height"": 12
+ }";
+
+ Assert.That.JsonEqual(expected, tag);
+ }
+
+ [TestMethod]
+ public void ShouldSerializeDropdownTag()
+ {
+ var tag = new DropdownTag
+ {
+ TagName = "DropdownTagExample",
+ Role = "CLIENT",
+ Required = true,
+ EnumerationOptions = new List {"All", "None"},
+ Width = 100,
+ Height = 15,
+ };
+
+ var expected = @"{
+ ""type"": ""enumeration"",
+ ""custom_defined_option"": false,
+ ""enumeration_options"": [
+ ""All"",
+ ""None""
+ ],
+ ""tag_name"": ""DropdownTagExample"",
+ ""role"": ""CLIENT"",
+ ""required"": true,
+ ""width"": 100,
+ ""height"": 15
+ }";
+
+ Assert.That.JsonEqual(expected, tag);
+ }
+
+ [TestMethod]
+ public void ShouldSerializeHyperlinkTag()
+ {
+ var tag = new HyperlinkTag
+ {
+ TagName = "hyperlink_example",
+ PageNumber = 0,
+ Role = "CLIENT",
+ Name = "HyperlinkTagExampleUID",
+ Required = true,
+ Width = 100,
+ Height = 15,
+ Link = new Uri("https://signnow.com"),
+ Label = "signNow main page",
+ Hint = "click"
+ };
+
+ var expected = @"{
+ ""type"": ""hyperlink"",
+ ""page_number"": 0,
+ ""name"": ""HyperlinkTagExampleUID"",
+ ""link"": ""https://signnow.com"",
+ ""hint"": ""click"",
+ ""label"": ""signNow main page"",
+ ""tag_name"": ""hyperlink_example"",
+ ""role"": ""CLIENT"",
+ ""required"": true,
+ ""width"": 100,
+ ""height"": 15
+ }";
+
+ Assert.That.JsonEqual(expected, tag);
+ }
+
+ [TestMethod]
+ public void ShouldSerializeInitialsTag()
+ {
+ var tag = new InitialsTag
+ {
+ TagName = "InitialsTagExample",
+ Role = "CLIENT",
+ Required = true,
+ Height = 15,
+ Width = 40,
+ };
+
+ var expected = @"{
+ ""type"": ""initials"",
+ ""tag_name"": ""InitialsTagExample"",
+ ""role"": ""CLIENT"",
+ ""required"": true,
+ ""width"": 40,
+ ""height"": 15
+ }";
+
+ Assert.That.JsonEqual(expected, tag);
+ }
+
+ [TestMethod]
+ public void ShouldSerializeSignatureTag()
+ {
+ var tag = new SignatureTag
+ {
+ TagName = "SignatureTagExample",
+ Role = "CLIENT",
+ Required = true,
+ Height = 15,
+ Width = 400,
+ };
+
+ var expected = @"{
+ ""type"": ""signature"",
+ ""tag_name"": ""SignatureTagExample"",
+ ""role"": ""CLIENT"",
+ ""required"": true,
+ ""width"": 400,
+ ""height"": 15
+ }";
+
+ Assert.That.JsonEqual(expected, tag);
+ }
+
+ [TestMethod]
+ public void ShouldSerializeTextTag()
+ {
+ var tag = new TextTag
+ {
+ TagName = "TextTagExample",
+ Role = "CLIENT",
+ Label = "Label1",
+ Required = true,
+ Height = 150,
+ Width = 400,
+ };
+
+ var expected = @"{
+ ""type"": ""text"",
+ ""label"": ""Label1"",
+ ""tag_name"": ""TextTagExample"",
+ ""role"": ""CLIENT"",
+ ""required"": true,
+ ""width"": 400,
+ ""height"": 150
+ }";
+
+ Assert.That.JsonEqual(expected, tag);
+ }
+ }
+}
diff --git a/SignNow.Net.Test/UnitTests/Models/ComplexTags/RadioButtonTagTest.cs b/SignNow.Net.Test/UnitTests/Models/ComplexTags/RadioButtonTagTest.cs
new file mode 100644
index 00000000..328a6331
--- /dev/null
+++ b/SignNow.Net.Test/UnitTests/Models/ComplexTags/RadioButtonTagTest.cs
@@ -0,0 +1,79 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using SignNow.Net.Model.ComplexTags;
+
+namespace UnitTests.Models.ComplexTags
+{
+ [TestClass]
+ public class RadioButtonTagTest
+ {
+ [TestMethod]
+ public void ShouldProperSerialize()
+ {
+ var radioButton = new RadioButtonTag("Group_name")
+ {
+ TagName = "radio_group_1",
+ PageNumber = 0,
+ Role = "Signer 1",
+ Required = true,
+ X = 36,
+ Y = 246,
+ Width = 340,
+ Height = 13,
+ };
+
+ radioButton.AddOption("value-1", 0, 0);
+ radioButton.AddOption("value-2", 0, 14, 1);
+ radioButton.AddOption("value-3", 0, 28);
+
+ var expected = @"{
+ ""type"":""radiobutton"",
+ ""name"":""Group_name"",
+ ""page_number"": 0,
+ ""x"": 36,
+ ""y"": 246,
+ ""radio"": [
+ {
+ ""page_number"": 0,
+ ""x"": 36,
+ ""y"": 246,
+ ""width"": 13,
+ ""height"": 13,
+ ""value"": ""value-1"",
+ ""checked"": 0,
+ ""x-offset"": 0,
+ ""y-offset"": 0
+ },
+ {
+ ""page_number"": 0,
+ ""x"": 36,
+ ""y"": 246,
+ ""width"": 13,
+ ""height"": 13,
+ ""value"": ""value-2"",
+ ""checked"": 1,
+ ""x-offset"": 0,
+ ""y-offset"": 14
+ },
+ {
+ ""page_number"": 0,
+ ""x"": 36,
+ ""y"": 246,
+ ""width"": 13,
+ ""height"": 13,
+ ""value"": ""value-3"",
+ ""checked"": 0,
+ ""x-offset"": 0,
+ ""y-offset"": 28
+ }
+ ],
+ ""tag_name"": ""radio_group_1"",
+ ""role"": ""Signer 1"",
+ ""required"": true,
+ ""width"": 340,
+ ""height"": 13
+ }";
+
+ Assert.That.JsonEqual(expected, radioButton);
+ }
+ }
+}
diff --git a/SignNow.Net.Test/UnitTests/Requests/MultipartHttpContentTest.cs b/SignNow.Net.Test/UnitTests/Requests/MultipartHttpContentTest.cs
new file mode 100644
index 00000000..f4bc9269
--- /dev/null
+++ b/SignNow.Net.Test/UnitTests/Requests/MultipartHttpContentTest.cs
@@ -0,0 +1,46 @@
+using System.IO;
+using System.Net.Http;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using SignNow.Net.Internal.Requests;
+using SignNow.Net.Model;
+using SignNow.Net.Model.ComplexTags;
+
+namespace UnitTests
+{
+ [TestClass]
+ public class MultipartHttpContentTest : SignNowTestBase
+ {
+ [TestMethod]
+ public void CanGetHttpContent()
+ {
+ var testTag = new TextTag()
+ {
+ TagName = "Test",
+ Role = "Signer 1",
+ Required = true,
+ Label = "name",
+ PrefilledText = "enter-the-name",
+ Width = 100,
+ Height = 15
+ };
+ var complexTags = new ComplexTextTags(testTag);
+
+ using var testStream = new StreamContent(File.OpenRead(PdfFilePath));
+ var multipart = new MultipartHttpContent(testStream.ReadAsStreamAsync().Result, "testFileName", complexTags);
+
+ var httpContent = multipart.GetHttpContent();
+ var requestContent = httpContent.ReadAsStringAsync().Result;
+
+ StringAssert.StartsWith(httpContent.Headers.ContentType.ToString(), "multipart/form-data");
+ StringAssert.Contains(
+ requestContent,
+ "Content-Disposition: form-data; name=file; filename=testFileName; filename*=utf-8''testFileName");
+ StringAssert.Contains(
+ requestContent,
+ "Content-Type: text/plain; charset=utf-8\r\nContent-Disposition: form-data; name=Tags");
+ StringAssert.Contains(
+ requestContent,
+ "[{\"type\":\"text\",\"prefilled_text\":\"enter-the-name\",\"label\":\"name\",\"tag_name\":\"Test\",\"role\":\"Signer 1\",\"required\":true,\"width\":100,\"height\":15}]");
+ }
+ }
+}
diff --git a/SignNow.Net/Interfaces/IDocumentService.cs b/SignNow.Net/Interfaces/IDocumentService.cs
index e0d0693d..c712c1af 100644
--- a/SignNow.Net/Interfaces/IDocumentService.cs
+++ b/SignNow.Net/Interfaces/IDocumentService.cs
@@ -38,9 +38,10 @@ public interface IDocumentService
///
/// Document content stream
/// Uploaded document file name
+ /// Simple Text Tag
/// Propagates notification that operations should be canceled.
/// Operation result object containing ID of the new document.
- TaskUploadDocumentWithFieldExtractAsync(Stream documentContent, string fileName, CancellationToken cancellationToken = default);
+ TaskUploadDocumentWithFieldExtractAsync(Stream documentContent, string fileName, ITextTags tags = null, CancellationToken cancellationToken = default);
///
/// Removes a document from signNow account.
diff --git a/SignNow.Net/Interfaces/ITextTags.cs b/SignNow.Net/Interfaces/ITextTags.cs
new file mode 100644
index 00000000..61b03502
--- /dev/null
+++ b/SignNow.Net/Interfaces/ITextTags.cs
@@ -0,0 +1,7 @@
+namespace SignNow.Net.Interfaces
+{
+ public interface ITextTags
+ {
+ public string ToStringContent();
+ }
+}
diff --git a/SignNow.Net/Model/ComplexTags/AttachmentTag.cs b/SignNow.Net/Model/ComplexTags/AttachmentTag.cs
new file mode 100644
index 00000000..1a45f95c
--- /dev/null
+++ b/SignNow.Net/Model/ComplexTags/AttachmentTag.cs
@@ -0,0 +1,13 @@
+using Newtonsoft.Json;
+using Newtonsoft.Json.Converters;
+
+namespace SignNow.Net.Model.ComplexTags
+{
+ public class AttachmentTag : ComplexTagWithLabel
+ {
+ ///
+ [JsonProperty("type")]
+ [JsonConverter(typeof(StringEnumConverter))]
+ public override FieldType Type { get; protected set; } = FieldType.Attachment;
+ }
+}
diff --git a/SignNow.Net/Model/ComplexTags/CheckBoxTag.cs b/SignNow.Net/Model/ComplexTags/CheckBoxTag.cs
new file mode 100644
index 00000000..5734c2fd
--- /dev/null
+++ b/SignNow.Net/Model/ComplexTags/CheckBoxTag.cs
@@ -0,0 +1,13 @@
+using Newtonsoft.Json;
+using Newtonsoft.Json.Converters;
+
+namespace SignNow.Net.Model.ComplexTags
+{
+ public class CheckBoxTag : ComplexTagBase
+ {
+ ///
+ [JsonProperty("type")]
+ [JsonConverter(typeof(StringEnumConverter))]
+ public override FieldType Type { get; protected set; } = FieldType.Checkbox;
+ }
+}
diff --git a/SignNow.Net/Model/ComplexTags/ComplexTagBase.cs b/SignNow.Net/Model/ComplexTags/ComplexTagBase.cs
new file mode 100644
index 00000000..9068210d
--- /dev/null
+++ b/SignNow.Net/Model/ComplexTags/ComplexTagBase.cs
@@ -0,0 +1,60 @@
+using Newtonsoft.Json;
+using Newtonsoft.Json.Converters;
+using SignNow.Net.Interfaces;
+
+namespace SignNow.Net.Model.ComplexTags
+{
+ public abstract class ComplexTag
+ {
+ ///
+ /// Field type
+ ///
+ [JsonProperty("type")]
+ [JsonConverter(typeof(StringEnumConverter))]
+ public virtual FieldType Type { get; protected set; }
+ }
+
+ public abstract class ComplexTagBase : ComplexTag
+ {
+ ///
+ /// The name of the Tag
+ ///
+ [JsonProperty("tag_name")]
+ public string TagName { get; set; }
+
+ ///
+ /// Which role the field is assigned to, e.g. Signer_1
+ ///
+ [JsonProperty("role")]
+ public string Role { get; set; }
+
+ ///
+ /// Whether the field is mandatory to fill in
+ ///
+ [JsonProperty("required")]
+ public bool Required { get; set; }
+
+ ///
+ /// How many pixels wide the field is
+ ///
+ [JsonProperty("width")]
+ public int Width { get; set; }
+
+ ///
+ /// How many pixels high the field is
+ ///
+ [JsonProperty("height")]
+ public int Height { get; set; }
+ }
+
+ public abstract class ComplexTagWithLabel : ComplexTagBase
+ {
+ ///
+ /// (optional) - hint for the signer inside a fillable field about the field type,
+ /// e.g. first_name or text_1;
+ /// once the field is filled in, the value automatically appears in all the fields with the same label
+ ///
+ [JsonProperty("label", NullValueHandling = NullValueHandling.Ignore)]
+ public string Label { get; set; }
+ }
+}
diff --git a/SignNow.Net/Model/ComplexTags/DropdownTag.cs b/SignNow.Net/Model/ComplexTags/DropdownTag.cs
new file mode 100644
index 00000000..dd595f5d
--- /dev/null
+++ b/SignNow.Net/Model/ComplexTags/DropdownTag.cs
@@ -0,0 +1,20 @@
+using System.Collections.Generic;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Converters;
+
+namespace SignNow.Net.Model.ComplexTags
+{
+ public class DropdownTag : ComplexTagWithLabel
+ {
+ ///
+ [JsonProperty("type")]
+ [JsonConverter(typeof(StringEnumConverter))]
+ public override FieldType Type { get; protected set; } = FieldType.Enumeration;
+
+ [JsonProperty("custom_defined_option")]
+ public bool CustomDefinedOptions { get; set; }
+
+ [JsonProperty("enumeration_options")]
+ public List EnumerationOptions { get; set; } = new List();
+ }
+}
diff --git a/SignNow.Net/Model/ComplexTags/HyperlinkTag.cs b/SignNow.Net/Model/ComplexTags/HyperlinkTag.cs
new file mode 100644
index 00000000..b9db180c
--- /dev/null
+++ b/SignNow.Net/Model/ComplexTags/HyperlinkTag.cs
@@ -0,0 +1,38 @@
+using System;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Converters;
+using SignNow.Net.Internal.Helpers.Converters;
+
+namespace SignNow.Net.Model.ComplexTags
+
+{
+ public class HyperlinkTag : ComplexTagWithLabel
+ {
+ ///
+ [JsonProperty("type")]
+ [JsonConverter(typeof(StringEnumConverter))]
+ public override FieldType Type { get; protected set; } = FieldType.Hyperlink;
+
+ ///
+ /// Page number where is located hyperlink
+ ///
+ [JsonProperty("page_number")]
+ public int PageNumber { get; set; }
+
+ ///
+ /// Hyperlink unique id
+ ///
+ [JsonProperty("name")]
+ public string Name { get; set; }
+
+ [JsonProperty("link")]
+ [JsonConverter(typeof(StringToUriJsonConverter))]
+ public Uri Link { get; set; }
+
+ ///
+ /// Hyperlink hint
+ ///
+ [JsonProperty("hint")]
+ public string Hint { get; set; }
+ }
+}
diff --git a/SignNow.Net/Model/ComplexTags/InitialsTag.cs b/SignNow.Net/Model/ComplexTags/InitialsTag.cs
new file mode 100644
index 00000000..77b376c5
--- /dev/null
+++ b/SignNow.Net/Model/ComplexTags/InitialsTag.cs
@@ -0,0 +1,13 @@
+using Newtonsoft.Json;
+using Newtonsoft.Json.Converters;
+
+namespace SignNow.Net.Model.ComplexTags
+{
+ public class InitialsTag : ComplexTagBase
+ {
+ ///
+ [JsonProperty("type")]
+ [JsonConverter(typeof(StringEnumConverter))]
+ public override FieldType Type { get; protected set; } = FieldType.Initials;
+ }
+}
diff --git a/SignNow.Net/Model/ComplexTags/RadioButtonTag.cs b/SignNow.Net/Model/ComplexTags/RadioButtonTag.cs
new file mode 100644
index 00000000..8a12acac
--- /dev/null
+++ b/SignNow.Net/Model/ComplexTags/RadioButtonTag.cs
@@ -0,0 +1,93 @@
+using System;
+using System.Collections.Generic;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Converters;
+
+namespace SignNow.Net.Model.ComplexTags
+{
+ public class RadioButtonTag : ComplexTagWithLabel
+ {
+ ///
+ [JsonProperty("type")]
+ [JsonConverter(typeof(StringEnumConverter))]
+ public override FieldType Type { get; protected set; } = FieldType.RadioButton;
+
+ ///
+ /// Radiobutton name
+ ///
+ [JsonProperty("name")]
+ public string Name { get; set; }
+
+ [JsonProperty("page_number")]
+ public int PageNumber { get; set; }
+
+ ///
+ /// Position of the field by X axis
+ ///
+ [JsonProperty("x")]
+ public int X { get; set; }
+
+ ///
+ /// Position of the field by Y axis
+ ///
+ [JsonProperty("y")]
+ public int Y { get; set; }
+
+ [JsonProperty("radio")]
+ public List Options { get; set; } = new List();
+
+ public RadioButtonTag(string groupName)
+ {
+ Name = groupName;
+ }
+
+ public void AddOption(string value, int xPos, int yPos, int isChecked = 0)
+ {
+ var option = new RadioGroup
+ {
+ PageNumber = this.PageNumber,
+ X = this.X,
+ Y = this.Y,
+ Width = Math.Min(this.Width, this.Height),
+ Height = Math.Min(this.Width, this.Height),
+ Value = value,
+ isChecked = isChecked,
+ XOffset = xPos,
+ YOffset = yPos
+
+ };
+
+ Options.Add(option);
+ }
+ }
+
+ public class RadioGroup
+ {
+ [JsonProperty("page_number")]
+ public int PageNumber { get; internal set; }
+
+ [JsonProperty("x")]
+ public int X { get; internal set; }
+
+ [JsonProperty("y")]
+ public int Y { get; internal set; }
+
+ [JsonProperty("width")]
+ public int Width { get; internal set; }
+
+ [JsonProperty("height")]
+ public int Height { get; internal set; }
+
+ [JsonProperty("value")]
+ public string Value { get; set; }
+
+ [JsonProperty("checked")]
+ public int isChecked { get; set; }
+
+ [JsonProperty("x-offset")]
+ public int XOffset { get; set; }
+
+ [JsonProperty("y-offset")]
+ public int YOffset { get; set; }
+ }
+}
diff --git a/SignNow.Net/Model/ComplexTags/SignatureTag.cs b/SignNow.Net/Model/ComplexTags/SignatureTag.cs
new file mode 100644
index 00000000..0789ad63
--- /dev/null
+++ b/SignNow.Net/Model/ComplexTags/SignatureTag.cs
@@ -0,0 +1,13 @@
+using Newtonsoft.Json;
+using Newtonsoft.Json.Converters;
+
+namespace SignNow.Net.Model.ComplexTags
+{
+ public class SignatureTag : ComplexTagBase
+ {
+ ///
+ [JsonProperty("type")]
+ [JsonConverter(typeof(StringEnumConverter))]
+ public override FieldType Type { get; protected set; } = FieldType.Signature;
+ }
+}
diff --git a/SignNow.Net/Model/ComplexTags/TextTag.cs b/SignNow.Net/Model/ComplexTags/TextTag.cs
new file mode 100644
index 00000000..91323f11
--- /dev/null
+++ b/SignNow.Net/Model/ComplexTags/TextTag.cs
@@ -0,0 +1,19 @@
+using Newtonsoft.Json;
+using Newtonsoft.Json.Converters;
+
+namespace SignNow.Net.Model.ComplexTags
+{
+ public class TextTag : ComplexTagWithLabel
+ {
+ ///
+ [JsonProperty("type")]
+ [JsonConverter(typeof(StringEnumConverter))]
+ public override FieldType Type { get; protected set; } = FieldType.Text;
+
+ ///
+ /// Editable text (optional) that appears in the field when the signer opens the document, e.g. Lucy
+ ///
+ [JsonProperty("prefilled_text", NullValueHandling = NullValueHandling.Ignore)]
+ public string PrefilledText { get; set; }
+ }
+}
diff --git a/SignNow.Net/Model/ComplexTextTags.cs b/SignNow.Net/Model/ComplexTextTags.cs
new file mode 100644
index 00000000..ab6440c9
--- /dev/null
+++ b/SignNow.Net/Model/ComplexTextTags.cs
@@ -0,0 +1,25 @@
+using System.Collections.Generic;
+using Newtonsoft.Json;
+using SignNow.Net.Interfaces;
+using SignNow.Net.Model.ComplexTags;
+
+namespace SignNow.Net.Model
+{
+ public class ComplexTextTags : ITextTags
+ {
+ [JsonIgnore]
+ public List Properties { get; set; } = new List();
+
+ public ComplexTextTags() { }
+
+ public ComplexTextTags(ComplexTag tag)
+ {
+ Properties.Add(tag);
+ }
+
+ public string ToStringContent()
+ {
+ return JsonConvert.SerializeObject(Properties);
+ }
+ }
+}
diff --git a/SignNow.Net/Service/DocumentService.cs b/SignNow.Net/Service/DocumentService.cs
index 290dbba2..48532351 100644
--- a/SignNow.Net/Service/DocumentService.cs
+++ b/SignNow.Net/Service/DocumentService.cs
@@ -76,23 +76,23 @@ await SignNowClient
///
public async Task UploadDocumentAsync(Stream documentContent, string fileName, CancellationToken cancellationToken = default)
{
- return await UploadDocumentAsync("/document", documentContent, fileName, cancellationToken)
+ return await UploadDocumentAsync("/document", documentContent, fileName, null, cancellationToken)
.ConfigureAwait(false);
}
///
- public async Task UploadDocumentWithFieldExtractAsync(Stream documentContent, string fileName, CancellationToken cancellationToken = default)
+ public async Task UploadDocumentWithFieldExtractAsync(Stream documentContent, string fileName, ITextTags tags = null, CancellationToken cancellationToken = default)
{
- return await UploadDocumentAsync("/document/fieldextract", documentContent, fileName, cancellationToken)
+ return await UploadDocumentAsync("/document/fieldextract", documentContent, fileName, tags, cancellationToken)
.ConfigureAwait(false);
}
- private async Task UploadDocumentAsync(string requestRelativeUrl, Stream documentContent, string fileName, CancellationToken cancellationToken = default)
+ private async Task UploadDocumentAsync(string requestRelativeUrl, Stream documentContent, string fileName, ITextTags tags, CancellationToken cancellationToken = default)
{
var requestOptions = new PostHttpRequestOptions
{
RequestUrl = new Uri(ApiBaseUrl, requestRelativeUrl),
- Content = new FileHttpContent(documentContent, fileName),
+ Content = new MultipartHttpContent(documentContent, fileName, tags),
Token = Token
};
diff --git a/SignNow.Net/_Internal/Requests/FileHttpContent.cs b/SignNow.Net/_Internal/Requests/FileHttpContent.cs
deleted file mode 100644
index fcd51225..00000000
--- a/SignNow.Net/_Internal/Requests/FileHttpContent.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-using System.IO;
-using System.Net.Http;
-using SignNow.Net.Interfaces;
-using System;
-using System.Diagnostics.CodeAnalysis;
-
-namespace SignNow.Net.Internal.Requests
-{
- ///
- /// A container for content encoded using multipart/form-data MIME type.
- ///
- internal class FileHttpContent : IContent
- {
- readonly Stream streamContent;
- readonly string fileName;
-
- public FileHttpContent(Stream content, string fileName)
- {
- this.streamContent = content;
- this.fileName = fileName;
- }
-
- [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose HttpContent object before losing scope", Justification = "It should be disposed via HttpContent.Dispose()")]
- public HttpContent GetHttpContent()
- {
- var content = new MultipartFormDataContent($"----{Guid.NewGuid():N}-----")
- {
- { new StreamContent(streamContent), "file", fileName }
- };
-
- return content;
- }
- }
-}
diff --git a/SignNow.Net/_Internal/Requests/MultipartHttpContent.cs b/SignNow.Net/_Internal/Requests/MultipartHttpContent.cs
new file mode 100644
index 00000000..646c5305
--- /dev/null
+++ b/SignNow.Net/_Internal/Requests/MultipartHttpContent.cs
@@ -0,0 +1,39 @@
+using System.IO;
+using System.Net.Http;
+using SignNow.Net.Interfaces;
+using System;
+using System.Text;
+
+namespace SignNow.Net.Internal.Requests
+{
+ ///
+ /// A container for content encoded using multipart/form-data MIME type.
+ ///
+ internal class MultipartHttpContent : IContent
+ {
+ private readonly Stream _streamContent;
+ private readonly string _fileName;
+ private readonly ITextTags _textTags;
+
+ public MultipartHttpContent(Stream content, string fileName, ITextTags tags)
+ {
+ _streamContent = content;
+ _fileName = fileName;
+ _textTags = tags;
+ }
+
+ // [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose HttpContent object before losing scope", Justification = "It should be disposed via HttpContent.Dispose()")]
+ public HttpContent GetHttpContent()
+ {
+ var content = new MultipartFormDataContent();
+ content.Add(new StreamContent(_streamContent), "file", _fileName);
+
+ if (_textTags != null)
+ {
+ content.Add(new StringContent(_textTags.ToStringContent(), Encoding.UTF8), "Tags");
+ }
+
+ return content;
+ }
+ }
+}
diff --git a/SignNow.props b/SignNow.props
index a8ad8688..291aa79f 100644
--- a/SignNow.props
+++ b/SignNow.props
@@ -1,6 +1,6 @@
- 1.1.1-dev
+ 1.2.0
signNow
signNow
signNow.Net is a .NET 4.5+ and .NET standard class library for the signNow API. (Official Library)