From 67a53c6c9fba46b47e3a413ec3ccaa9668261f53 Mon Sep 17 00:00:00 2001 From: Minh Nguyen Cong Date: Tue, 5 Sep 2023 10:29:21 +0200 Subject: [PATCH 1/5] feat: Support Sign Templates and new Sign Request statuses --- Box.V2.Test/Box.V2.Test.csproj | 6 + Box.V2.Test/BoxResourceManagerTest.cs | 2 + Box.V2.Test/BoxSignRequestsManagerTest.cs | 4 +- Box.V2.Test/BoxSignTemplateManagerTest.cs | 85 ++++++++++++ .../BoxSignRequest/CancelSignRequest200.json | 3 +- .../BoxSignRequest/CreateSignRequest200.json | 3 +- .../BoxSignRequest/GetAllSignRequests200.json | 3 +- .../BoxSignRequest/GetSignRequest200.json | 3 +- .../GetAllSignTemplates200.json | 108 +++++++++++++++ .../BoxSignTemplate/GetSignTemplate200.json | 102 ++++++++++++++ Box.V2/Box.V2.csproj | 6 + Box.V2/BoxClient.cs | 6 + Box.V2/Config/BoxConfig.cs | 8 ++ Box.V2/Config/Constants.cs | 5 + Box.V2/Config/IBoxConfig.cs | 8 ++ Box.V2/Converter/BoxItemConverter.cs | 2 + Box.V2/Managers/BoxSignTemplatesManager.cs | 62 +++++++++ Box.V2/Managers/IBoxSignTemplatesManager.cs | 26 ++++ Box.V2/Models/BoxSignRequest.cs | 11 +- Box.V2/Models/BoxSignTemplate.cs | 128 ++++++++++++++++++ .../Models/BoxSignTemplateAdditionalInfo.cs | 40 ++++++ .../Models/BoxSignTemplateCustomBranding.cs | 42 ++++++ Box.V2/Models/BoxSignTemplateReadySignLink.cs | 56 ++++++++ .../Request/BoxSignRequestCreateRequest.cs | 6 + docs/sign-templates.md | 32 +++++ 25 files changed, 751 insertions(+), 6 deletions(-) create mode 100644 Box.V2.Test/BoxSignTemplateManagerTest.cs create mode 100644 Box.V2.Test/Fixtures/BoxSignTemplate/GetAllSignTemplates200.json create mode 100644 Box.V2.Test/Fixtures/BoxSignTemplate/GetSignTemplate200.json create mode 100644 Box.V2/Managers/BoxSignTemplatesManager.cs create mode 100644 Box.V2/Managers/IBoxSignTemplatesManager.cs create mode 100644 Box.V2/Models/BoxSignTemplate.cs create mode 100644 Box.V2/Models/BoxSignTemplateAdditionalInfo.cs create mode 100644 Box.V2/Models/BoxSignTemplateCustomBranding.cs create mode 100644 Box.V2/Models/BoxSignTemplateReadySignLink.cs create mode 100644 docs/sign-templates.md diff --git a/Box.V2.Test/Box.V2.Test.csproj b/Box.V2.Test/Box.V2.Test.csproj index 6f3267cd5..eb37744b5 100644 --- a/Box.V2.Test/Box.V2.Test.csproj +++ b/Box.V2.Test/Box.V2.Test.csproj @@ -75,6 +75,12 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + PreserveNewest diff --git a/Box.V2.Test/BoxResourceManagerTest.cs b/Box.V2.Test/BoxResourceManagerTest.cs index 4175edb7d..73dbc8ecc 100644 --- a/Box.V2.Test/BoxResourceManagerTest.cs +++ b/Box.V2.Test/BoxResourceManagerTest.cs @@ -49,6 +49,8 @@ protected BoxResourceManagerTest() Config.SetupGet(x => x.FolderLocksEndpointUri).Returns(FolderLocksUri); Config.SetupGet(x => x.SignRequestsEndpointUri).Returns(SignRequestUri); Config.SetupGet(x => x.SignRequestsEndpointWithPathUri).Returns(SignRequestWithPathUri); + Config.SetupGet(x => x.SignTemplatesEndpointUri).Returns(new Uri(Constants.SignTemplatesEndpointString)); + Config.SetupGet(x => x.SignTemplatesEndpointWithPathUri).Returns(new Uri(Constants.SignTemplatesWithPathEndpointString)); Config.SetupGet(x => x.FileRequestsEndpointWithPathUri).Returns(FileRequestsWithPathUri); Config.SetupGet(x => x.RetryStrategy).Returns(new InstantRetryStrategy()); diff --git a/Box.V2.Test/BoxSignRequestsManagerTest.cs b/Box.V2.Test/BoxSignRequestsManagerTest.cs index 3e88ab9ce..3b4b3b7fb 100644 --- a/Box.V2.Test/BoxSignRequestsManagerTest.cs +++ b/Box.V2.Test/BoxSignRequestsManagerTest.cs @@ -144,7 +144,8 @@ public async Task CreateSignRequest_OptionalParams_Success() "1234", "text" ) - } + }, + TemplateId = "12345" }; /*** Act ***/ @@ -180,6 +181,7 @@ public async Task CreateSignRequest_OptionalParams_Success() Assert.AreEqual(DateTimeOffset.Parse("2021-04-26T08:12:13.982Z"), response.PrefillTags[0].DateValue); Assert.AreEqual("https://box.com/redirect_url", response.RedirectUrl.ToString()); Assert.AreEqual("https://box.com/declined_redirect_url", response.DeclinedRedirectUrl.ToString()); + Assert.AreEqual("12345", response.TemplateId); } [TestMethod] diff --git a/Box.V2.Test/BoxSignTemplateManagerTest.cs b/Box.V2.Test/BoxSignTemplateManagerTest.cs new file mode 100644 index 000000000..6d126c81b --- /dev/null +++ b/Box.V2.Test/BoxSignTemplateManagerTest.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Box.V2.Managers; +using Box.V2.Models; +using Box.V2.Models.Request; +using Box.V2.Test.Extensions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Newtonsoft.Json.Linq; + +namespace Box.V2.Test +{ + [TestClass] + public class BoxSignTemplatesManagerTest : BoxResourceManagerTest + { + private readonly BoxSignTemplatesManager _signTemplatesManager; + + public BoxSignTemplatesManagerTest() + { + _signTemplatesManager = new BoxSignTemplatesManager(Config.Object, Service, Converter, AuthRepository); + } + + [TestMethod] + public async Task GetSignTemplateById_Success() + { + /** Arrange **/ + const string signTemplateId = "93153068-5420-467b-b8ef-8e54bfb7be42"; + IBoxRequest boxRequest = null; + Handler.Setup(h => h.ExecuteAsync(It.IsAny())) + .Returns(Task.FromResult>(new BoxResponse() + { + Status = ResponseStatus.Success, + ContentString = LoadFixtureFromJson("Fixtures/BoxSignTemplate/GetSignTemplate200.json") + })) + .Callback(r => boxRequest = r); + + /*** Act ***/ + BoxSignTemplate response = await _signTemplatesManager.GetSignTemplateByIdAsync(signTemplateId); + + /*** Assert ***/ + // Request check + Assert.IsNotNull(boxRequest); + Assert.AreEqual(RequestMethod.Get, boxRequest.Method); + Assert.AreEqual(new Uri("https://api.box.com/2.0/sign_templates/93153068-5420-467b-b8ef-8e54bfb7be42"), boxRequest.AbsoluteUri); + + // Response check + Assert.AreEqual(signTemplateId, response.Id); + Assert.AreEqual("requirements-dev.pdf", response.Name); + Assert.AreEqual("Please sign this document.\n\nKind regards", response.EmailMessage); + Assert.AreEqual("Someone (user00@box.com) has requested your signature on a document", response.EmailSubject); + Assert.AreEqual("1234567890", response.ParentFolder.Id); + Assert.AreEqual(1, response.SourceFiles.Count); + Assert.AreEqual("1234567890", response.SourceFiles[0].Id); + Assert.AreEqual("https://app.box.com/sign/ready-sign-link/59917816-c12b-4ef6-8f1d-aaaaaaa", response.ReadySignLink.Url); + } + + [TestMethod] + public async Task GetSignTemplates_Success() + { + /** Arrange **/ + IBoxRequest boxRequest = null; + Handler.Setup(h => h.ExecuteAsync>(It.IsAny())) + .Returns(Task.FromResult>>(new BoxResponse>() + { + Status = ResponseStatus.Success, + ContentString = LoadFixtureFromJson("Fixtures/BoxSignTemplate/GetAllSignTemplates200.json") + })) + .Callback(r => boxRequest = r); + + /*** Act ***/ + BoxCollectionMarkerBased response = await _signTemplatesManager.GetSignTemplatesAsync(1000, "JV9IRGZmieiBasejOG9yDCRNgd2ymoZIbjsxbJMjIs3kioVii"); + + /*** Assert ***/ + // Request check + Assert.IsNotNull(boxRequest); + Assert.AreEqual(RequestMethod.Get, boxRequest.Method); + Assert.AreEqual(new Uri("https://api.box.com/2.0/sign_templates?limit=1000&marker=JV9IRGZmieiBasejOG9yDCRNgd2ymoZIbjsxbJMjIs3kioVii"), boxRequest.AbsoluteUri); + + // Response check + Assert.AreEqual(1, response.Entries.Count); + Assert.AreEqual("93153068-5420-467b-b8ef-8e54bfb7be42", response.Entries[0].Id); + } + } +} diff --git a/Box.V2.Test/Fixtures/BoxSignRequest/CancelSignRequest200.json b/Box.V2.Test/Fixtures/BoxSignRequest/CancelSignRequest200.json index 593997136..f8383479a 100644 --- a/Box.V2.Test/Fixtures/BoxSignRequest/CancelSignRequest200.json +++ b/Box.V2.Test/Fixtures/BoxSignRequest/CancelSignRequest200.json @@ -101,5 +101,6 @@ } } ], - "status": "cancelled" + "status": "cancelled", + "template_id": "12345" } diff --git a/Box.V2.Test/Fixtures/BoxSignRequest/CreateSignRequest200.json b/Box.V2.Test/Fixtures/BoxSignRequest/CreateSignRequest200.json index 584f81906..57b43b48f 100644 --- a/Box.V2.Test/Fixtures/BoxSignRequest/CreateSignRequest200.json +++ b/Box.V2.Test/Fixtures/BoxSignRequest/CreateSignRequest200.json @@ -101,5 +101,6 @@ } } ], - "status": "converting" + "status": "converting", + "template_id": "12345" } diff --git a/Box.V2.Test/Fixtures/BoxSignRequest/GetAllSignRequests200.json b/Box.V2.Test/Fixtures/BoxSignRequest/GetAllSignRequests200.json index 651fb6119..3409ce225 100644 --- a/Box.V2.Test/Fixtures/BoxSignRequest/GetAllSignRequests200.json +++ b/Box.V2.Test/Fixtures/BoxSignRequest/GetAllSignRequests200.json @@ -109,7 +109,8 @@ ], "is_ready_for_download": true }, - "auto_expire_at": "2021-04-26T08:12:13.982Z" + "auto_expire_at": "2021-04-26T08:12:13.982Z", + "template_id": "12345" } ] } diff --git a/Box.V2.Test/Fixtures/BoxSignRequest/GetSignRequest200.json b/Box.V2.Test/Fixtures/BoxSignRequest/GetSignRequest200.json index 584f81906..57b43b48f 100644 --- a/Box.V2.Test/Fixtures/BoxSignRequest/GetSignRequest200.json +++ b/Box.V2.Test/Fixtures/BoxSignRequest/GetSignRequest200.json @@ -101,5 +101,6 @@ } } ], - "status": "converting" + "status": "converting", + "template_id": "12345" } diff --git a/Box.V2.Test/Fixtures/BoxSignTemplate/GetAllSignTemplates200.json b/Box.V2.Test/Fixtures/BoxSignTemplate/GetAllSignTemplates200.json new file mode 100644 index 000000000..3e4b840f4 --- /dev/null +++ b/Box.V2.Test/Fixtures/BoxSignTemplate/GetAllSignTemplates200.json @@ -0,0 +1,108 @@ +{ + "limit": 10, + "next_marker": null, + "prev_marker": null, + "entries": [ + { + "id": "93153068-5420-467b-b8ef-8e54bfb7be42", + "type": "sign-template", + "name": "requirements-dev.pdf", + "email_message": "Please sign this document.\n\nKind regards,\n\nMinh Nguyen Cong (mcong+biz00@boxdemo.com)", + "email_subject": "Minh Nguyen Cong (mcong+biz00@boxdemo.com) has requested your signature on a document", + "parent_folder": { + "id": "205263471578", + "etag": "0", + "type": "folder", + "sequence_id": "0", + "name": "My Sign Requests" + }, + "auto_expire_days": null, + "source_files": [ + { + "id": "1278569733058", + "etag": "0", + "type": "file", + "sequence_id": "0", + "sha1": "082c9540e82e9c465309367a32404054b13b183f", + "file_version": { + "id": "1397632535458", + "type": "file_version", + "sha1": "082c9540e82e9c465309367a32404054b13b183f" + } + } + ], + "are_email_settings_locked": false, + "are_fields_locked": false, + "are_files_locked": false, + "are_options_locked": false, + "are_recipients_locked": false, + "signers": [ + { + "email": "", + "label": "", + "public_id": "18K8K7Q4", + "role": "final_copy_reader", + "is_in_person": false, + "order": 1, + "inputs": [] + }, + { + "email": "", + "label": "", + "public_id": "13XQXJZ4", + "role": "signer", + "is_in_person": false, + "order": 1, + "inputs": [ + { + "document_tag_id": null, + "id": "0260f921-3b52-477f-ae74-bcf02e2ccc09", + "type": "signature", + "text_value": null, + "is_required": true, + "coordinates": { + "x": 0.27038464059712, + "y": 0.10051756244533624 + }, + "dimensions": { + "width": 0.23570031566618235, + "height": 0.04781003891921971 + }, + "date_value": null, + "page_index": 0, + "checkbox_value": null, + "document_id": "2fdf9003-d798-40ee-be7f-f91f96432470", + "content_type": "signature", + "dropdown_choices": null, + "group_id": null, + "label": null + } + ] + } + ], + "ready_sign_link": { + "url": "https://app.box.com/sign/ready-sign-link/59917816-c12b-4ef6-8f1d-f7ea66191f99", + "name": "requirements-dev.pdf", + "instructions": "Hello", + "folder_id": "205263471578", + "is_notification_disabled": true, + "is_active": true + }, + "custom_branding": null, + "days_valid": 0, + "additional_info": { + "non_editable": [], + "required": { + "signers": [ + [ + "email" + ], + [ + "email" + ] + ] + } + } + } + ] +} diff --git a/Box.V2.Test/Fixtures/BoxSignTemplate/GetSignTemplate200.json b/Box.V2.Test/Fixtures/BoxSignTemplate/GetSignTemplate200.json new file mode 100644 index 000000000..5bd560103 --- /dev/null +++ b/Box.V2.Test/Fixtures/BoxSignTemplate/GetSignTemplate200.json @@ -0,0 +1,102 @@ + +{ + "id": "93153068-5420-467b-b8ef-8e54bfb7be42", + "type": "sign-template", + "name": "requirements-dev.pdf", + "email_message": "Please sign this document.\n\nKind regards", + "email_subject": "Someone (user00@box.com) has requested your signature on a document", + "parent_folder": { + "id": "1234567890", + "etag": "0", + "type": "folder", + "sequence_id": "0", + "name": "My Sign Requests" + }, + "auto_expire_days": null, + "source_files": [ + { + "id": "1234567890", + "etag": "0", + "type": "file", + "sequence_id": "0", + "sha1": "082c9540e82e9c465309367a3240405aaaaaaa", + "file_version": { + "id": "1234567890", + "type": "file_version", + "sha1": "082c9540e82e9c465309367a3240405aaaaaaa" + } + } + ], + "are_email_settings_locked": false, + "are_fields_locked": false, + "are_files_locked": false, + "are_options_locked": false, + "are_recipients_locked": false, + "signers": [ + { + "email": "", + "label": "", + "public_id": "18K8K7Q4", + "role": "final_copy_reader", + "is_in_person": false, + "order": 1, + "inputs": [] + }, + { + "email": "", + "label": "", + "public_id": "13XQXJZ4", + "role": "signer", + "is_in_person": false, + "order": 1, + "inputs": [ + { + "document_tag_id": null, + "id": "0260f921-3b52-477f-ae74-aaaaaaa", + "type": "signature", + "text_value": null, + "is_required": true, + "coordinates": { + "x": 0.27038464059712, + "y": 0.10051756244533624 + }, + "dimensions": { + "width": 0.23570031566618235, + "height": 0.04781003891921971 + }, + "date_value": null, + "page_index": 0, + "checkbox_value": null, + "document_id": "2fdf9003-d798-40ee-be7f-aaaaaaa", + "content_type": "signature", + "dropdown_choices": null, + "group_id": null, + "label": null + } + ] + } + ], + "ready_sign_link": { + "url": "https://app.box.com/sign/ready-sign-link/59917816-c12b-4ef6-8f1d-aaaaaaa", + "name": "requirements-dev.pdf", + "instructions": "Hello", + "folder_id": "1234567890", + "is_notification_disabled": true, + "is_active": true + }, + "custom_branding": null, + "days_valid": 0, + "additional_info": { + "non_editable": [], + "required": { + "signers": [ + [ + "email" + ], + [ + "email" + ] + ] + } + } +} diff --git a/Box.V2/Box.V2.csproj b/Box.V2/Box.V2.csproj index 83a8db350..e617b4089 100644 --- a/Box.V2/Box.V2.csproj +++ b/Box.V2/Box.V2.csproj @@ -103,6 +103,7 @@ + @@ -127,6 +128,7 @@ + @@ -182,6 +184,10 @@ + + + + diff --git a/Box.V2/BoxClient.cs b/Box.V2/BoxClient.cs index 318269e78..c26b19b40 100644 --- a/Box.V2/BoxClient.cs +++ b/Box.V2/BoxClient.cs @@ -137,6 +137,7 @@ private void InitManagers() MetadataCascadePolicyManager = new BoxMetadataCascadePolicyManager(Config, _service, _converter, Auth, _asUser, _suppressNotifications); StoragePoliciesManager = new BoxStoragePoliciesManager(Config, _service, _converter, Auth, _asUser, _suppressNotifications); SignRequestsManager = new BoxSignRequestsManager(Config, _service, _converter, Auth, _asUser, _suppressNotifications); + SignTemplatesManager = new BoxSignTemplatesManager(Config, _service, _converter, Auth, _asUser, _suppressNotifications); FileRequestsManager = new BoxFileRequestsManager(Config, _service, _converter, Auth, _asUser, _suppressNotifications); // Init Resource Plugins Manager @@ -285,6 +286,11 @@ public IBoxClient AddResourcePlugin() where T : BoxResourceManager /// public IBoxSignRequestsManager SignRequestsManager { get; private set; } + /// + /// The manager that represents sign templates endpoints. + /// + public IBoxSignTemplatesManager SignTemplatesManager { get; private set; } + /// /// The manager that represents all of the file requests endpoints. /// diff --git a/Box.V2/Config/BoxConfig.cs b/Box.V2/Config/BoxConfig.cs index be7333072..90eda8121 100644 --- a/Box.V2/Config/BoxConfig.cs +++ b/Box.V2/Config/BoxConfig.cs @@ -285,6 +285,14 @@ public string JWTAudience /// public Uri SignRequestsEndpointWithPathUri { get { return new Uri(BoxApiUri, Constants.SignRequestsWithPathString); } } /// + /// Gets the sign templates endpoint URI. + /// + public Uri SignTemplatesEndpointUri { get { return new Uri(BoxApiUri, Constants.SignTemplatesString); } } + /// + /// Gets the sign templates endpoint URI with path. + /// + public Uri SignTemplatesEndpointWithPathUri { get { return new Uri(BoxApiUri, Constants.SignTemplatesWithPathString); } } + /// /// Gets the file requests endpoint URI. /// public Uri FileRequestsEndpointWithPathUri { get { return new Uri(BoxApiUri, Constants.FileRequestsWithPathString); } } diff --git a/Box.V2/Config/Constants.cs b/Box.V2/Config/Constants.cs index 6a754c7fe..8aff1debf 100644 --- a/Box.V2/Config/Constants.cs +++ b/Box.V2/Config/Constants.cs @@ -59,6 +59,8 @@ public static class Constants public const string FolderLocksString = @"folder_locks/"; public const string SignRequestsString = @"sign_requests"; public const string SignRequestsWithPathString = @"sign_requests/"; + public const string SignTemplatesString = @"sign_templates"; + public const string SignTemplatesWithPathString = @"sign_templates/"; public const string FileRequestsWithPathString = @"file_requests/"; @@ -119,6 +121,8 @@ public static class Constants public const string FolderLocksEndpointString = BoxApiUriString + FolderLocksString; public const string SignRequestsEndpointString = BoxApiUriString + SignRequestsString; public const string SignRequestsWithPathEndpointString = BoxApiUriString + SignRequestsWithPathString; + public const string SignTemplatesEndpointString = BoxApiUriString + SignTemplatesString; + public const string SignTemplatesWithPathEndpointString = BoxApiUriString + SignTemplatesWithPathString; public const string FileRequestsWithPathEndpointString = BoxApiUriString + FileRequestsWithPathString; /*** Endpoint Paths ***/ @@ -203,6 +207,7 @@ public static class Constants public const string TypeApplication = "application"; public const string TypeFolderLock = "folder_lock"; public const string TypeSignRequest = "sign-request"; + public const string TypeSignTemplate = "sign-template"; public const string TypeFileRequest = "file_request"; /*** File Preview ***/ diff --git a/Box.V2/Config/IBoxConfig.cs b/Box.V2/Config/IBoxConfig.cs index a5f4740c9..3447be206 100644 --- a/Box.V2/Config/IBoxConfig.cs +++ b/Box.V2/Config/IBoxConfig.cs @@ -131,6 +131,14 @@ public interface IBoxConfig /// Uri SignRequestsEndpointWithPathUri { get; } /// + /// Gets the sign templates endpoint URI. + /// + Uri SignTemplatesEndpointUri { get; } + /// + /// Gets the sign template endpoints URI with path. + /// + Uri SignTemplatesEndpointWithPathUri { get; } + /// /// Gets the file requests endpoint URI with path. /// Uri FileRequestsEndpointWithPathUri { get; } diff --git a/Box.V2/Converter/BoxItemConverter.cs b/Box.V2/Converter/BoxItemConverter.cs index 7d044e14f..21bd986cc 100644 --- a/Box.V2/Converter/BoxItemConverter.cs +++ b/Box.V2/Converter/BoxItemConverter.cs @@ -95,6 +95,8 @@ protected override BoxEntity Create(Type objectType, JObject jObject) return new BoxFolderLock(); case Constants.TypeSignRequest: return new BoxSignRequest(); + case Constants.TypeSignTemplate: + return new BoxSignTemplate(); case Constants.TypeFileRequest: return new BoxFileRequestObject(); } diff --git a/Box.V2/Managers/BoxSignTemplatesManager.cs b/Box.V2/Managers/BoxSignTemplatesManager.cs new file mode 100644 index 000000000..d8777d422 --- /dev/null +++ b/Box.V2/Managers/BoxSignTemplatesManager.cs @@ -0,0 +1,62 @@ +using System.Threading.Tasks; +using Box.V2.Auth; +using Box.V2.Config; +using Box.V2.Converter; +using Box.V2.Extensions; +using Box.V2.Models; +using Box.V2.Models.Request; +using Box.V2.Services; + +namespace Box.V2.Managers +{ + /// + /// The manager that represents all of the sign templates endpoints. + /// + public class BoxSignTemplatesManager : BoxResourceManager, IBoxSignTemplatesManager + { + public BoxSignTemplatesManager(IBoxConfig config, IBoxService service, IBoxConverter converter, IAuthRepository auth, string asUser = null, bool? suppressNotifications = null) + : base(config, service, converter, auth, asUser, suppressNotifications) { } + + /// + /// Retrieves information about a sign template by ID. + /// + /// Id of the sign template. + /// A full SignTemplate object is returned if the id is valid and if the user has access to the sign template. + public async Task GetSignTemplateByIdAsync(string signTemplateId) + { + signTemplateId.ThrowIfNullOrWhiteSpace("signTemplateId"); + + var request = new BoxRequest(_config.SignTemplatesEndpointWithPathUri, signTemplateId) + .Method(RequestMethod.Get); + + IBoxResponse response = await ToResponseAsync(request).ConfigureAwait(false); + + return response.ResponseObject; + } + + /// + /// Retrieves information about all sign templates. + /// + /// Limit result size to this number. Defaults to 100, maximum is 1,000. + /// Take from "next_marker" column of a prior call to get the next page. + /// Whether or not to auto-paginate to fetch all items; defaults to false. + /// A a collection of sign templates is returned if the id if the user has access. + public async Task> GetSignTemplatesAsync(int limit = 100, string nextMarker = null, bool autoPaginate = false) + { + BoxRequest request = new BoxRequest(_config.SignTemplatesEndpointUri) + .Param("limit", limit.ToString()) + .Param("marker", nextMarker) + .Method(RequestMethod.Get); + + if (autoPaginate) + { + return await AutoPaginateMarker(request, limit).ConfigureAwait(false); + } + else + { + var response = await ToResponseAsync>(request).ConfigureAwait(false); + return response.ResponseObject; + } + } + } +} diff --git a/Box.V2/Managers/IBoxSignTemplatesManager.cs b/Box.V2/Managers/IBoxSignTemplatesManager.cs new file mode 100644 index 000000000..2bd21f83a --- /dev/null +++ b/Box.V2/Managers/IBoxSignTemplatesManager.cs @@ -0,0 +1,26 @@ +using System.Threading.Tasks; +using Box.V2.Models; +using Box.V2.Models.Request; + + +namespace Box.V2.Managers +{ + public interface IBoxSignTemplatesManager + { + /// + /// Retrieves information about a sign template by ID. + /// + /// Id of the sign template. + /// A full SignTemplate object is returned if the id is valid and if the user has access to the sign template. + Task GetSignTemplateByIdAsync(string signTemplateId); + + /// + /// Retrieves information about all sign templates. + /// + /// Limit result size to this number. Defaults to 100, maximum is 1,000. + /// Take from "next_marker" column of a prior call to get the next page. + /// Whether or not to auto-paginate to fetch all items; defaults to false. + /// A a collection of sign templates is returned if the id if the user has access. + Task> GetSignTemplatesAsync(int limit = 100, string nextMarker = null, bool autoPaginate = false); + } +} diff --git a/Box.V2/Models/BoxSignRequest.cs b/Box.V2/Models/BoxSignRequest.cs index 9338dbecd..213e00314 100644 --- a/Box.V2/Models/BoxSignRequest.cs +++ b/Box.V2/Models/BoxSignRequest.cs @@ -29,6 +29,7 @@ public class BoxSignRequest : BoxEntity public const string FieldStatus = "status"; public const string FieldDeclinedRedirectUrl = "declined_redirect_url"; public const string FieldRedirectUrl = "redirect_url"; + public const string FieldTemplateId = "template_id"; /// /// Reminds signers to sign a document on day 3, 8, 13 and 18. Reminders are only sent to outstanding signers. @@ -142,6 +143,12 @@ public class BoxSignRequest : BoxEntity /// [JsonProperty(PropertyName = FieldRedirectUrl)] public virtual Uri RedirectUrl { get; private set; } + + /// + /// The ID of the template that was used to create this sign request. + /// + [JsonProperty(PropertyName = FieldTemplateId)] + public virtual string TemplateId { get; private set; } } /// @@ -161,6 +168,8 @@ public enum BoxSignRequestStatus expired, downloaded, [EnumMember(Value = "signed and downloaded")] - signed_and_downloaded + signed_and_downloaded, + finalizing, + error_finalizing } } diff --git a/Box.V2/Models/BoxSignTemplate.cs b/Box.V2/Models/BoxSignTemplate.cs new file mode 100644 index 000000000..61ead56a6 --- /dev/null +++ b/Box.V2/Models/BoxSignTemplate.cs @@ -0,0 +1,128 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Box.V2.Models +{ + /// + /// A standard representation of a sign template, as returned from any Box Sign Templates API endpoints by default. + /// + public class BoxSignTemplate : BoxEntity + { + public const string FieldAdditionalInfo = "additional_info"; + public const string FieldAreEmailSettingsLocked = "are_email_settings_locked"; + public const string FieldAreFieldsLocked = "are_fields_locked"; + public const string FieldAreFilesLocked = "are_files_locked"; + public const string FieldAreOptionsLocked = "are_options_locked"; + public const string FieldAreRecipientsLocked = "are_recipients_locked"; + public const string FieldCustomBranding = "custom_branding"; + public const string FieldDaysValid = "days_valid"; + public const string FieldEmailMessage = "email_message"; + public const string FieldEmailSubject = "email_subject"; + public const string FieldName = "name"; + public const string FieldParentFolder = "parent_folder"; + public const string FieldReadySignLink = "ready_sign_link"; + public const string FieldSigners = "signers"; + public const string FieldSourceFiles = "source_files"; + + /// + /// Additional information on which fields are required and which fields are not editable. + /// + [JsonProperty(PropertyName = FieldAdditionalInfo)] + public virtual BoxSignTemplateAdditionalInfo AdditionalInfo { get; private set; } + + /// + /// Indicates if the template email settings are editable or not. + /// + [JsonProperty(PropertyName = FieldAreEmailSettingsLocked)] + public virtual bool AreEmailSettingsLocked { get; private set; } + + /// + /// Indicates if the template input fields are editable or not. + /// + [JsonProperty(PropertyName = FieldAreFieldsLocked)] + public virtual bool AreFieldsLocked { get; private set; } + + /// + /// Indicates if the template files are editable or not. This includes deleting or renaming template files. + /// + [JsonProperty(PropertyName = FieldAreFilesLocked)] + public virtual bool AreFilesLocked { get; private set; } + + /// + /// Indicates if the template document options are editable or not, for example renaming the document. + /// + [JsonProperty(PropertyName = FieldAreOptionsLocked)] + public virtual bool AreOptionsLocked { get; private set; } + + /// + /// Indicates if the template signers are editable or not. + /// + [JsonProperty(PropertyName = FieldAreRecipientsLocked)] + public virtual bool AreRecipientsLocked { get; private set; } + + /// + /// Custom branding applied to notifications and signature requests. + /// + [JsonProperty(PropertyName = FieldCustomBranding)] + public virtual BoxSignTemplateCustomBranding CustomBranding { get; private set; } + + /// + /// Set the number of days after which the created signature request will automatically expire if not completed. + /// By default, we do not apply any expiration date on signature requests, and the signature request does not expire. + /// + [JsonProperty(PropertyName = FieldDaysValid)] + public virtual int? DaysValid { get; private set; } + + /// + /// Message to include in signature request email. The field is cleaned through sanitization of specific characters. + /// However, some html tags are allowed. Links included in the message are also converted to hyperlinks in the email. + /// The message may contain the following html tags including a, abbr, acronym, b, blockquote, code, em, i, ul, li, ol, and strong. + /// Be aware that when the text to html ratio is too high, the email may end up in spam filters. Custom styles on these tags are not allowed. + /// If this field is not passed, a default message will be used. + /// + [JsonProperty(PropertyName = FieldEmailMessage)] + public virtual string EmailMessage { get; private set; } + + /// + /// Subject of signature request email. This is cleaned by signature request. If this field is not passed, a default subject will be used. + /// + [JsonProperty(PropertyName = FieldEmailSubject)] + public virtual string EmailSubject { get; private set; } + + /// + /// Name of the template. + /// + [JsonProperty(PropertyName = FieldName)] + public virtual string Name { get; private set; } + + /// + /// The destination folder to place final, signed document and signing log. + /// + [JsonProperty(PropertyName = FieldParentFolder)] + public virtual BoxFolder ParentFolder { get; private set; } + + /// + /// Box's ready-sign link feature enables you to create a link to a signature request that you've created from a template. + /// Use this link when you want to post a signature request on a public form — such as an email, social media post, + /// or web page — without knowing who the signers will be. + /// Note: The ready-sign link feature is limited to Enterprise Plus customers and not available to Box Verified Enterprises. + /// + [JsonProperty(PropertyName = FieldReadySignLink)] + public virtual BoxSignTemplateReadySignLink ReadySignLink { get; private set; } + + /// + /// List of signers for the template. + /// + [JsonProperty(PropertyName = FieldSigners)] + public virtual List Signers { get; private set; } + + /// + /// List of files to be used in the template. + /// + [JsonProperty(PropertyName = FieldSourceFiles)] + public virtual List SourceFiles { get; private set; } + } +} diff --git a/Box.V2/Models/BoxSignTemplateAdditionalInfo.cs b/Box.V2/Models/BoxSignTemplateAdditionalInfo.cs new file mode 100644 index 000000000..e14137919 --- /dev/null +++ b/Box.V2/Models/BoxSignTemplateAdditionalInfo.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Box.V2.Models +{ + /// + /// Additional information on which fields are required and which fields are not editable. + /// + public class BoxSignTemplateAdditionalInfo + { + public const string FieldNonEditable = "non_editable"; + public const string FieldRequired = "required"; + + /// + /// List of fields that are not editable. + /// + [JsonProperty(PropertyName = FieldNonEditable)] + public virtual List NonEditable { get; private set; } + + /// + /// Required fields. + /// + [JsonProperty(PropertyName = FieldRequired)] + public virtual BoxSignTemplateAdditionalInfoRequired Required { get; private set; } + + } + + public class BoxSignTemplateAdditionalInfoRequired + { + public const string FieldSigners = "signers"; + + /// + /// Required signer fields. + /// + [JsonProperty(PropertyName = FieldSigners)] + public virtual List> Signers { get; private set; } + } +} diff --git a/Box.V2/Models/BoxSignTemplateCustomBranding.cs b/Box.V2/Models/BoxSignTemplateCustomBranding.cs new file mode 100644 index 000000000..6d8ed1f27 --- /dev/null +++ b/Box.V2/Models/BoxSignTemplateCustomBranding.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Box.V2.Models +{ + /// + /// Custom branding applied to notifications and signature requests. + /// + public class BoxSignTemplateCustomBranding + { + public const string FieldBrandingColor = "branding_color"; + public const string FieldCompanyName = "company_name"; + public const string FieldEmailFooterText = "email_footer_text"; + public const string FieldLogoUri = "logo_uri"; + + /// + /// Custom branding color in hex. + /// + [JsonProperty(PropertyName = FieldBrandingColor)] + public virtual string BrandingColor { get; private set; } + + /// + /// Name of the company. + /// + [JsonProperty(PropertyName = FieldCompanyName)] + public virtual string CompanyName { get; private set; } + + /// + /// Custom email footer text. + /// + [JsonProperty(PropertyName = FieldEmailFooterText)] + public virtual string EmailFooterText { get; private set; } + + /// + /// Custom branding logo URI in the form of a base64 image. + /// + [JsonProperty(PropertyName = FieldLogoUri)] + public virtual string LogoUri { get; private set; } + } +} \ No newline at end of file diff --git a/Box.V2/Models/BoxSignTemplateReadySignLink.cs b/Box.V2/Models/BoxSignTemplateReadySignLink.cs new file mode 100644 index 000000000..93b0038fb --- /dev/null +++ b/Box.V2/Models/BoxSignTemplateReadySignLink.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Box.V2.Models +{ + // + // Box's ready-sign link feature enables you to create a link to a signature request that you've created from a template. + // + public class BoxSignTemplateReadySignLink + { + public const string FieldFolderId = "folder_id"; + public const string FieldInstructions = "instructions"; + public const string FieldIsActive = "is_active"; + public const string FieldIsNotificationDisabled = "is_notification_disabled"; + public const string FieldName = "name"; + public const string FieldUrl = "url"; + + /// + /// The destination folder to place final, signed document and signing log. + /// + [JsonProperty(PropertyName = FieldFolderId)] + public virtual string FolderId { get; private set; } + + /// + /// Extra instructions for all signers. + /// + [JsonProperty(PropertyName = FieldInstructions)] + public virtual string Instructions { get; private set; } + + /// + /// Whether the ready sign link is enabled or not. + /// + [JsonProperty(PropertyName = FieldIsActive)] + public virtual bool IsActive { get; private set; } + + /// + /// Whether to disable notifications when a signer has signed. + /// + [JsonProperty(PropertyName = FieldIsNotificationDisabled)] + public virtual bool IsNotificationDisabled { get; private set; } + + /// + /// The name of the ready sign link. + /// + [JsonProperty(PropertyName = FieldName)] + public virtual string Name { get; private set; } + + /// + /// The URL that can be sent to signers. + /// + [JsonProperty(PropertyName = FieldUrl)] + public virtual string Url { get; private set; } + } +} diff --git a/Box.V2/Models/Request/BoxSignRequestCreateRequest.cs b/Box.V2/Models/Request/BoxSignRequestCreateRequest.cs index 6e33828bd..f3fbfc4ca 100644 --- a/Box.V2/Models/Request/BoxSignRequestCreateRequest.cs +++ b/Box.V2/Models/Request/BoxSignRequestCreateRequest.cs @@ -91,6 +91,12 @@ public class BoxSignRequestCreateRequest /// [JsonProperty(PropertyName = "redirect_url")] public Uri RedirectUrl { get; set; } + + /// + /// The ID of sign template to use to create the sign request. + /// + [JsonProperty(PropertyName = "template_id")] + public string TemplateId { get; set; } } /// diff --git a/docs/sign-templates.md b/docs/sign-templates.md new file mode 100644 index 000000000..dcb4279f3 --- /dev/null +++ b/docs/sign-templates.md @@ -0,0 +1,32 @@ +Sign Templates +================== + +Box Sign enables you to create templates so you can automatically add the same fields and formatting to requests for signature. With templates, you don't need to repetitively add the same fields to each request every time you send a new document for signature. + + + + +- [Get All Sign Templates](#get-all-sign-templates) +- [Get Sign Template by ID](#get-sign-template-by-id) + + + +Get All Sign Templates +------------------------ + +Calling the `SignTemplatesManager.GetSignTemplatesAsync(int limit = 100, string nextMarker = null, bool autoPaginate = false)` method will return an iterable that will page through all the Sign Templates. + + +```c# +BoxCollectionMarkerBased signTemplates = await client.SignTemplatesManager.GetSignTemplatesAsync(); +``` + +Get Sign Template by ID +------------------------ + +Calling the `SignTemplatesManager.GetSignTemplateByIdAsync(string signTemplateId)` method will return the Sign Template with the given ID. + + +```c# +BoxSignTemplate signTemplate = await client.SignTemplatesManager.GetSignTemplateByIdAsync("12345"); +``` From 553912cb958ee3df0eeaec7e4f9b44d56b60ca48 Mon Sep 17 00:00:00 2001 From: Minh Nguyen Cong Date: Tue, 5 Sep 2023 10:41:06 +0200 Subject: [PATCH 2/5] Fix linter --- Box.V2.Test/BoxSignTemplateManagerTest.cs | 90 +++++++++---------- Box.V2/Managers/IBoxSignTemplatesManager.cs | 2 +- .../Models/BoxSignTemplateAdditionalInfo.cs | 4 +- .../Models/BoxSignTemplateCustomBranding.cs | 2 +- Box.V2/Models/BoxSignTemplateReadySignLink.cs | 2 +- 5 files changed, 50 insertions(+), 50 deletions(-) diff --git a/Box.V2.Test/BoxSignTemplateManagerTest.cs b/Box.V2.Test/BoxSignTemplateManagerTest.cs index 6d126c81b..c101e758f 100644 --- a/Box.V2.Test/BoxSignTemplateManagerTest.cs +++ b/Box.V2.Test/BoxSignTemplateManagerTest.cs @@ -14,53 +14,53 @@ namespace Box.V2.Test [TestClass] public class BoxSignTemplatesManagerTest : BoxResourceManagerTest { - private readonly BoxSignTemplatesManager _signTemplatesManager; + private readonly BoxSignTemplatesManager _signTemplatesManager; - public BoxSignTemplatesManagerTest() - { - _signTemplatesManager = new BoxSignTemplatesManager(Config.Object, Service, Converter, AuthRepository); - } + public BoxSignTemplatesManagerTest() + { + _signTemplatesManager = new BoxSignTemplatesManager(Config.Object, Service, Converter, AuthRepository); + } - [TestMethod] - public async Task GetSignTemplateById_Success() - { - /** Arrange **/ - const string signTemplateId = "93153068-5420-467b-b8ef-8e54bfb7be42"; - IBoxRequest boxRequest = null; - Handler.Setup(h => h.ExecuteAsync(It.IsAny())) - .Returns(Task.FromResult>(new BoxResponse() - { - Status = ResponseStatus.Success, - ContentString = LoadFixtureFromJson("Fixtures/BoxSignTemplate/GetSignTemplate200.json") - })) - .Callback(r => boxRequest = r); + [TestMethod] + public async Task GetSignTemplateById_Success() + { + /** Arrange **/ + const string signTemplateId = "93153068-5420-467b-b8ef-8e54bfb7be42"; + IBoxRequest boxRequest = null; + Handler.Setup(h => h.ExecuteAsync(It.IsAny())) + .Returns(Task.FromResult>(new BoxResponse() + { + Status = ResponseStatus.Success, + ContentString = LoadFixtureFromJson("Fixtures/BoxSignTemplate/GetSignTemplate200.json") + })) + .Callback(r => boxRequest = r); - /*** Act ***/ - BoxSignTemplate response = await _signTemplatesManager.GetSignTemplateByIdAsync(signTemplateId); + /*** Act ***/ + BoxSignTemplate response = await _signTemplatesManager.GetSignTemplateByIdAsync(signTemplateId); - /*** Assert ***/ - // Request check - Assert.IsNotNull(boxRequest); - Assert.AreEqual(RequestMethod.Get, boxRequest.Method); - Assert.AreEqual(new Uri("https://api.box.com/2.0/sign_templates/93153068-5420-467b-b8ef-8e54bfb7be42"), boxRequest.AbsoluteUri); + /*** Assert ***/ + // Request check + Assert.IsNotNull(boxRequest); + Assert.AreEqual(RequestMethod.Get, boxRequest.Method); + Assert.AreEqual(new Uri("https://api.box.com/2.0/sign_templates/93153068-5420-467b-b8ef-8e54bfb7be42"), boxRequest.AbsoluteUri); - // Response check - Assert.AreEqual(signTemplateId, response.Id); - Assert.AreEqual("requirements-dev.pdf", response.Name); - Assert.AreEqual("Please sign this document.\n\nKind regards", response.EmailMessage); - Assert.AreEqual("Someone (user00@box.com) has requested your signature on a document", response.EmailSubject); - Assert.AreEqual("1234567890", response.ParentFolder.Id); - Assert.AreEqual(1, response.SourceFiles.Count); - Assert.AreEqual("1234567890", response.SourceFiles[0].Id); - Assert.AreEqual("https://app.box.com/sign/ready-sign-link/59917816-c12b-4ef6-8f1d-aaaaaaa", response.ReadySignLink.Url); - } + // Response check + Assert.AreEqual(signTemplateId, response.Id); + Assert.AreEqual("requirements-dev.pdf", response.Name); + Assert.AreEqual("Please sign this document.\n\nKind regards", response.EmailMessage); + Assert.AreEqual("Someone (user00@box.com) has requested your signature on a document", response.EmailSubject); + Assert.AreEqual("1234567890", response.ParentFolder.Id); + Assert.AreEqual(1, response.SourceFiles.Count); + Assert.AreEqual("1234567890", response.SourceFiles[0].Id); + Assert.AreEqual("https://app.box.com/sign/ready-sign-link/59917816-c12b-4ef6-8f1d-aaaaaaa", response.ReadySignLink.Url); + } - [TestMethod] - public async Task GetSignTemplates_Success() - { - /** Arrange **/ - IBoxRequest boxRequest = null; - Handler.Setup(h => h.ExecuteAsync>(It.IsAny())) + [TestMethod] + public async Task GetSignTemplates_Success() + { + /** Arrange **/ + IBoxRequest boxRequest = null; + Handler.Setup(h => h.ExecuteAsync>(It.IsAny())) .Returns(Task.FromResult>>(new BoxResponse>() { Status = ResponseStatus.Success, @@ -68,7 +68,7 @@ public async Task GetSignTemplates_Success() })) .Callback(r => boxRequest = r); - /*** Act ***/ + /*** Act ***/ BoxCollectionMarkerBased response = await _signTemplatesManager.GetSignTemplatesAsync(1000, "JV9IRGZmieiBasejOG9yDCRNgd2ymoZIbjsxbJMjIs3kioVii"); /*** Assert ***/ @@ -77,9 +77,9 @@ public async Task GetSignTemplates_Success() Assert.AreEqual(RequestMethod.Get, boxRequest.Method); Assert.AreEqual(new Uri("https://api.box.com/2.0/sign_templates?limit=1000&marker=JV9IRGZmieiBasejOG9yDCRNgd2ymoZIbjsxbJMjIs3kioVii"), boxRequest.AbsoluteUri); - // Response check - Assert.AreEqual(1, response.Entries.Count); + // Response check + Assert.AreEqual(1, response.Entries.Count); Assert.AreEqual("93153068-5420-467b-b8ef-8e54bfb7be42", response.Entries[0].Id); } - } + } } diff --git a/Box.V2/Managers/IBoxSignTemplatesManager.cs b/Box.V2/Managers/IBoxSignTemplatesManager.cs index 2bd21f83a..72772a02e 100644 --- a/Box.V2/Managers/IBoxSignTemplatesManager.cs +++ b/Box.V2/Managers/IBoxSignTemplatesManager.cs @@ -1,4 +1,4 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; using Box.V2.Models; using Box.V2.Models.Request; diff --git a/Box.V2/Models/BoxSignTemplateAdditionalInfo.cs b/Box.V2/Models/BoxSignTemplateAdditionalInfo.cs index e14137919..8e2de92ca 100644 --- a/Box.V2/Models/BoxSignTemplateAdditionalInfo.cs +++ b/Box.V2/Models/BoxSignTemplateAdditionalInfo.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using Newtonsoft.Json; using Newtonsoft.Json.Converters; @@ -30,7 +30,7 @@ public class BoxSignTemplateAdditionalInfo public class BoxSignTemplateAdditionalInfoRequired { public const string FieldSigners = "signers"; - + /// /// Required signer fields. /// diff --git a/Box.V2/Models/BoxSignTemplateCustomBranding.cs b/Box.V2/Models/BoxSignTemplateCustomBranding.cs index 6d8ed1f27..cad74f70d 100644 --- a/Box.V2/Models/BoxSignTemplateCustomBranding.cs +++ b/Box.V2/Models/BoxSignTemplateCustomBranding.cs @@ -39,4 +39,4 @@ public class BoxSignTemplateCustomBranding [JsonProperty(PropertyName = FieldLogoUri)] public virtual string LogoUri { get; private set; } } -} \ No newline at end of file +} diff --git a/Box.V2/Models/BoxSignTemplateReadySignLink.cs b/Box.V2/Models/BoxSignTemplateReadySignLink.cs index 93b0038fb..dd62b4abb 100644 --- a/Box.V2/Models/BoxSignTemplateReadySignLink.cs +++ b/Box.V2/Models/BoxSignTemplateReadySignLink.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using Newtonsoft.Json; using Newtonsoft.Json.Converters; From 1d2da5880fd13eef8813b18df2dce1a4da4d5172 Mon Sep 17 00:00:00 2001 From: Minh Nguyen Cong Date: Wed, 6 Sep 2023 14:35:39 +0200 Subject: [PATCH 3/5] Update fields --- .../GetAllSignTemplates200.json | 16 +- Box.V2/Box.V2.csproj | 1 + Box.V2/Models/BoxSignTemplate.cs | 2 +- Box.V2/Models/BoxSignTemplateSigner.cs | 243 ++++++++++++++++++ docs/README.md | 2 + 5 files changed, 255 insertions(+), 9 deletions(-) create mode 100644 Box.V2/Models/BoxSignTemplateSigner.cs diff --git a/Box.V2.Test/Fixtures/BoxSignTemplate/GetAllSignTemplates200.json b/Box.V2.Test/Fixtures/BoxSignTemplate/GetAllSignTemplates200.json index 3e4b840f4..52952faef 100644 --- a/Box.V2.Test/Fixtures/BoxSignTemplate/GetAllSignTemplates200.json +++ b/Box.V2.Test/Fixtures/BoxSignTemplate/GetAllSignTemplates200.json @@ -4,13 +4,13 @@ "prev_marker": null, "entries": [ { - "id": "93153068-5420-467b-b8ef-8e54bfb7be42", + "id": "93153068-5420-467b-b8ef-aaaaaaa", "type": "sign-template", "name": "requirements-dev.pdf", - "email_message": "Please sign this document.\n\nKind regards,\n\nMinh Nguyen Cong (mcong+biz00@boxdemo.com)", - "email_subject": "Minh Nguyen Cong (mcong+biz00@boxdemo.com) has requested your signature on a document", + "email_message": "Please sign this document.\n\nKind regards,", + "email_subject": "Somebody has requested your signature on a document", "parent_folder": { - "id": "205263471578", + "id": "1234567890", "etag": "0", "type": "folder", "sequence_id": "0", @@ -19,7 +19,7 @@ "auto_expire_days": null, "source_files": [ { - "id": "1278569733058", + "id": "1234567890", "etag": "0", "type": "file", "sequence_id": "0", @@ -56,7 +56,7 @@ "inputs": [ { "document_tag_id": null, - "id": "0260f921-3b52-477f-ae74-bcf02e2ccc09", + "id": "0260f921-3b52-477f-ae74-aaaaaaa", "type": "signature", "text_value": null, "is_required": true, @@ -71,7 +71,7 @@ "date_value": null, "page_index": 0, "checkbox_value": null, - "document_id": "2fdf9003-d798-40ee-be7f-f91f96432470", + "document_id": "2fdf9003-d798-40ee-be7f-aaaaaaa", "content_type": "signature", "dropdown_choices": null, "group_id": null, @@ -84,7 +84,7 @@ "url": "https://app.box.com/sign/ready-sign-link/59917816-c12b-4ef6-8f1d-f7ea66191f99", "name": "requirements-dev.pdf", "instructions": "Hello", - "folder_id": "205263471578", + "folder_id": "1234567890", "is_notification_disabled": true, "is_active": true }, diff --git a/Box.V2/Box.V2.csproj b/Box.V2/Box.V2.csproj index e617b4089..8cfd492d3 100644 --- a/Box.V2/Box.V2.csproj +++ b/Box.V2/Box.V2.csproj @@ -188,6 +188,7 @@ + diff --git a/Box.V2/Models/BoxSignTemplate.cs b/Box.V2/Models/BoxSignTemplate.cs index 61ead56a6..dfa2c12f9 100644 --- a/Box.V2/Models/BoxSignTemplate.cs +++ b/Box.V2/Models/BoxSignTemplate.cs @@ -117,7 +117,7 @@ public class BoxSignTemplate : BoxEntity /// List of signers for the template. /// [JsonProperty(PropertyName = FieldSigners)] - public virtual List Signers { get; private set; } + public virtual List Signers { get; private set; } /// /// List of files to be used in the template. diff --git a/Box.V2/Models/BoxSignTemplateSigner.cs b/Box.V2/Models/BoxSignTemplateSigner.cs new file mode 100644 index 000000000..05f62cfe3 --- /dev/null +++ b/Box.V2/Models/BoxSignTemplateSigner.cs @@ -0,0 +1,243 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Box.V2.Models +{ + /// + /// A representation of a signer on a sign template. + /// + public class BoxSignTemplateSigner + { + public const string FieldEmail = "email"; + public const string FieldInputs = "inputs"; + public const string FieldIsInPerson = "is_in_person"; + public const string FieldOrder = "order"; + public const string FieldRole = "role"; + + /// + /// The email address of the signer. + /// + [JsonProperty(PropertyName = FieldEmail)] + public virtual string Email { get; private set; } + + /// + /// The input fields for the signer. + /// + [JsonProperty(PropertyName = FieldInputs)] + public virtual List Inputs { get; private set; } + + /// + /// Used in combination with an embed URL for a sender. + /// After the sender signs, they will be redirected to the next in_person signer. + /// + [JsonProperty(PropertyName = FieldIsInPerson)] + public virtual bool IsInPerson { get; private set; } + + /// + /// The order of the signer in the list of signers. + /// + [JsonProperty(PropertyName = FieldOrder)] + public virtual int Order { get; private set; } + + /// + /// The role of the signer. + /// + [JsonProperty(PropertyName = FieldRole)] + public virtual BoxSignTemplateSignerRole Role { get; private set; } + } + + /// + /// The role of the signer. + /// + public enum BoxSignTemplateSignerRole + { + signer, + approver, + final_copy_reader + } + + /// + /// A representation of an input field for a signer on a sign template. + /// + public class BoxSignTemplateSignerInput + { + public const string FieldType = "type"; + public const string FieldCheckboxValue = "checkbox_value"; + public const string FieldContentType = "content_type"; + public const string FieldCoordinates = "coordinates"; + public const string FieldDateValue = "date_value"; + public const string FieldDimensions = "dimensions"; + public const string FieldDocumentId = "document_id"; + public const string FieldDocumentTagId = "document_tag_id"; + public const string FieldDropdownChoices = "dropdown_choices"; + public const string FieldGroupId = "group_id"; + public const string FieldIsRequired = "is_required"; + public const string FieldPageIndex = "page_index"; + public const string FieldTextValue = "text_value"; + public const string FieldLabel = "label"; + + /// + /// The type of input field. + /// + [JsonProperty(PropertyName = FieldType)] + public virtual BoxSignTemplateSignerInputType Type { get; private set; } + + /// + /// The value of the checkbox. + /// + [JsonProperty(PropertyName = FieldCheckboxValue)] + public virtual bool? CheckboxValue { get; private set; } + + /// + /// The content type of the input field. + /// + [JsonProperty(PropertyName = FieldContentType)] + public virtual BoxSignTemplateSignerInputContentType ContentType { get; private set; } + + /// + /// The coordinates of the input field. + /// + [JsonProperty(PropertyName = FieldCoordinates)] + public virtual BoxSignTemplateSignerInputCoordinates Coordinates { get; private set; } + + /// + /// The value of the date. + /// + [JsonProperty(PropertyName = FieldDateValue)] + public virtual DateTime? DateValue { get; private set; } + + /// + /// The dimensions of the input field. + /// + [JsonProperty(PropertyName = FieldDimensions)] + public virtual BoxSignTemplateSignerInputDimensions Dimensions { get; private set; } + + /// + /// The ID of the document. + /// + [JsonProperty(PropertyName = FieldDocumentId)] + public virtual string DocumentId { get; private set; } + + /// + /// The ID of the document tag. + /// + [JsonProperty(PropertyName = FieldDocumentTagId)] + public virtual string DocumentTagId { get; private set; } + + /// + /// The choices for the dropdown. + /// + [JsonProperty(PropertyName = FieldDropdownChoices)] + public virtual List DropdownChoices { get; private set; } + + /// + /// The ID of the group. + /// + [JsonProperty(PropertyName = FieldGroupId)] + public virtual string GroupId { get; private set; } + + /// + /// Indicates if the input field is required. + /// + [JsonProperty(PropertyName = FieldIsRequired)] + public virtual bool IsRequired { get; private set; } + + /// + /// The index of the page. + /// + [JsonProperty(PropertyName = FieldPageIndex)] + public virtual int PageIndex { get; private set; } + + /// + /// The value of the text. + /// + [JsonProperty(PropertyName = FieldTextValue)] + public virtual string TextValue { get; private set; } + + /// + /// The label field is used especially for text, attachment, radio, and checkbox type inputs. + /// + [JsonProperty(PropertyName = FieldLabel)] + public virtual string Label { get; private set; } + } + + /// + /// The type of input field. + /// + public enum BoxSignTemplateSignerInputType + { + signature, + date, + text, + checkbox, + attachment, + radio, + dropdown + } + + /// + /// The content type of the input field. + /// + public enum BoxSignTemplateSignerInputContentType + { + signature, + initial, + stamp, + date, + checkbox, + text, + full_name, + first_name, + last_name, + company, + title, + email, + attachment, + radio, + dropdown + } + + /// + /// The coordinates of the input field. + /// + public class BoxSignTemplateSignerInputCoordinates + { + public const string FieldX = "x"; + public const string FieldY = "y"; + + /// + /// The x coordinate of the input field. + /// + [JsonProperty(PropertyName = FieldX)] + public virtual float X { get; private set; } + + /// + /// The y coordinate of the input field. + /// + [JsonProperty(PropertyName = FieldY)] + public virtual float Y { get; private set; } + } + + /// + /// The dimensions of the input field. + /// + public class BoxSignTemplateSignerInputDimensions + { + public const string FieldHeight = "height"; + public const string FieldWidth = "width"; + + /// + /// The height of the input field. + /// + [JsonProperty(PropertyName = FieldHeight)] + public virtual float Height { get; private set; } + + /// + /// The width of the input field. + /// + [JsonProperty(PropertyName = FieldWidth)] + public virtual float Width { get; private set; } + } +} diff --git a/docs/README.md b/docs/README.md index 87d388da4..7483d9679 100644 --- a/docs/README.md +++ b/docs/README.md @@ -7,6 +7,7 @@ You can read more about supported resources on [API reference](https://developer - [Classifications](classifications.md) - [Collaboration Whitelist](collaboration-whitelist.md) - [Collaborations](collaborations.md) +- [Collections](collections.md) - [Comments](comments.md) - [Custom Requests](custom-requests.md) - [Device Pins](device-pins.md) @@ -22,6 +23,7 @@ You can read more about supported resources on [API reference](https://developer - [Retention Policies](retention-policies.md) - [Search](search.md) - [Sign Requests](sign-requests.md) +- [Sign Templates](sign-templates.md) - [Storage Policies](storage-policies.md) - [Tasks](tasks.md) - [Terms Of Service](terms-of-service.md) From d344a4659ca8d6c41d071e90889896acb7b252e6 Mon Sep 17 00:00:00 2001 From: Minh Nguyen Cong Date: Wed, 6 Sep 2023 14:52:42 +0200 Subject: [PATCH 4/5] Update test --- .../GetAllSignTemplates200.json | 23 +++++++------------ 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/Box.V2.Test/Fixtures/BoxSignTemplate/GetAllSignTemplates200.json b/Box.V2.Test/Fixtures/BoxSignTemplate/GetAllSignTemplates200.json index 52952faef..0ed5c84f9 100644 --- a/Box.V2.Test/Fixtures/BoxSignTemplate/GetAllSignTemplates200.json +++ b/Box.V2.Test/Fixtures/BoxSignTemplate/GetAllSignTemplates200.json @@ -4,11 +4,11 @@ "prev_marker": null, "entries": [ { - "id": "93153068-5420-467b-b8ef-aaaaaaa", + "id": "93153068-5420-467b-b8ef-8e54bfb7be42", "type": "sign-template", "name": "requirements-dev.pdf", - "email_message": "Please sign this document.\n\nKind regards,", - "email_subject": "Somebody has requested your signature on a document", + "email_message": "Please sign this document.\n\nKind regards", + "email_subject": "Someone (user00@box.com) has requested your signature on a document", "parent_folder": { "id": "1234567890", "etag": "0", @@ -23,11 +23,11 @@ "etag": "0", "type": "file", "sequence_id": "0", - "sha1": "082c9540e82e9c465309367a32404054b13b183f", + "sha1": "082c9540e82e9c465309367a3240405aaaaaaa", "file_version": { - "id": "1397632535458", + "id": "1234567890", "type": "file_version", - "sha1": "082c9540e82e9c465309367a32404054b13b183f" + "sha1": "082c9540e82e9c465309367a3240405aaaaaaa" } } ], @@ -81,7 +81,7 @@ } ], "ready_sign_link": { - "url": "https://app.box.com/sign/ready-sign-link/59917816-c12b-4ef6-8f1d-f7ea66191f99", + "url": "https://app.box.com/sign/ready-sign-link/59917816-c12b-4ef6-8f1d-aaaaaaa", "name": "requirements-dev.pdf", "instructions": "Hello", "folder_id": "1234567890", @@ -93,14 +93,7 @@ "additional_info": { "non_editable": [], "required": { - "signers": [ - [ - "email" - ], - [ - "email" - ] - ] + "signers": [["email"], ["email"]] } } } From f79870b50fbb6815cc4bc7d0ec14b9b4b4d80966 Mon Sep 17 00:00:00 2001 From: Minh Nguyen Cong Date: Wed, 6 Sep 2023 16:21:25 +0200 Subject: [PATCH 5/5] Update code --- Box.V2/Models/BoxSignTemplateSigner.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Box.V2/Models/BoxSignTemplateSigner.cs b/Box.V2/Models/BoxSignTemplateSigner.cs index 05f62cfe3..a3c5e8627 100644 --- a/Box.V2/Models/BoxSignTemplateSigner.cs +++ b/Box.V2/Models/BoxSignTemplateSigner.cs @@ -106,7 +106,7 @@ public class BoxSignTemplateSignerInput /// The value of the date. /// [JsonProperty(PropertyName = FieldDateValue)] - public virtual DateTime? DateValue { get; private set; } + public virtual DateTimeOffset? DateValue { get; private set; } /// /// The dimensions of the input field. @@ -211,13 +211,13 @@ public class BoxSignTemplateSignerInputCoordinates /// The x coordinate of the input field. /// [JsonProperty(PropertyName = FieldX)] - public virtual float X { get; private set; } + public virtual double X { get; private set; } /// /// The y coordinate of the input field. /// [JsonProperty(PropertyName = FieldY)] - public virtual float Y { get; private set; } + public virtual double Y { get; private set; } } /// @@ -232,12 +232,12 @@ public class BoxSignTemplateSignerInputDimensions /// The height of the input field. /// [JsonProperty(PropertyName = FieldHeight)] - public virtual float Height { get; private set; } + public virtual double Height { get; private set; } /// /// The width of the input field. /// [JsonProperty(PropertyName = FieldWidth)] - public virtual float Width { get; private set; } + public virtual double Width { get; private set; } } }