From 9cd96036a3854089d4b5b0cbacd0718c9ecd8dc6 Mon Sep 17 00:00:00 2001 From: Artur Jankowski Date: Wed, 6 Mar 2024 10:55:03 +0100 Subject: [PATCH 1/2] feat: Add support for `signer_group_id` field in `SignRequest` --- BoxSDK.xcodeproj/project.pbxproj | 10 ++- Cartfile.private | 2 +- Cartfile.resolved | 2 +- .../SignRequestsModuleIntegrationSpecs.swift | 51 ++++++++++++--- .../SignRequestCreateParameters.swift | 52 ++++++++++++++- Sources/Responses/SignRequest.swift | 12 ++++ .../Responses/SignRequestSignatureColor.swift | 47 ++++++++++++++ Sources/Responses/SignRequestSigner.swift | 21 +++++++ .../Responses/SignRequestSignerInput.swift | 24 +++++++ Tests/Modules/SignRequestsModuleSpecs.swift | 63 ++++++++++++++++--- .../SignRequestSignatureColorSpecs.swift | 29 +++++++++ Tests/Responses/SignRequestSpecs.swift | 8 +++ .../SignRequests/CreateSignRequest.json | 40 +++++++++++- .../SignRequests/FullSignRequest.json | 12 +++- 14 files changed, 348 insertions(+), 25 deletions(-) create mode 100644 Sources/Responses/SignRequestSignatureColor.swift create mode 100644 Tests/Responses/SignRequestSignatureColorSpecs.swift diff --git a/BoxSDK.xcodeproj/project.pbxproj b/BoxSDK.xcodeproj/project.pbxproj index 05b6c7a77..b360c6bf9 100644 --- a/BoxSDK.xcodeproj/project.pbxproj +++ b/BoxSDK.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 52; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -119,6 +119,8 @@ 05F6C90226F137B9008F38C0 /* Quick.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 056FE12726EF6F6800098F00 /* Quick.xcframework */; }; 05F770D426F337FA00BDECA2 /* FileLogDestinationSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05F770D326F337FA00BDECA2 /* FileLogDestinationSpec.swift */; }; 05FA797527D793B100669B6D /* CCGAuthSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05FA797427D793B100669B6D /* CCGAuthSession.swift */; }; + 05FAB0C72B9782AE000B22E0 /* SignRequestSignatureColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05FAB0C62B9782AE000B22E0 /* SignRequestSignatureColor.swift */; }; + 05FAB0CA2B9861B3000B22E0 /* SignRequestSignatureColorSpecs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05FAB0C82B98614C000B22E0 /* SignRequestSignatureColorSpecs.swift */; }; 0BD51EDC28CF257E000DE69E /* RetentionPoliciesModuleIntegrationSpecs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BD51EDB28CF257E000DE69E /* RetentionPoliciesModuleIntegrationSpecs.swift */; }; 0C00835C229C06FE0067C1AF /* GetFolderInfo.json in Resources */ = {isa = PBXBuildFile; fileRef = 0C00835B229C06FE0067C1AF /* GetFolderInfo.json */; }; 0C00836E229C41CA0067C1AF /* FolderCollaborations.json in Resources */ = {isa = PBXBuildFile; fileRef = 0C00836D229C41CA0067C1AF /* FolderCollaborations.json */; }; @@ -741,6 +743,8 @@ 05F59F1026FCAB4E00D9A539 /* ArrayInputStreamSpecs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrayInputStreamSpecs.swift; sourceTree = ""; }; 05F770D326F337FA00BDECA2 /* FileLogDestinationSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileLogDestinationSpec.swift; sourceTree = ""; }; 05FA797427D793B100669B6D /* CCGAuthSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CCGAuthSession.swift; sourceTree = ""; }; + 05FAB0C62B9782AE000B22E0 /* SignRequestSignatureColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignRequestSignatureColor.swift; sourceTree = ""; }; + 05FAB0C82B98614C000B22E0 /* SignRequestSignatureColorSpecs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignRequestSignatureColorSpecs.swift; sourceTree = ""; }; 0BD51EDB28CF257E000DE69E /* RetentionPoliciesModuleIntegrationSpecs.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RetentionPoliciesModuleIntegrationSpecs.swift; sourceTree = ""; }; 0C00835B229C06FE0067C1AF /* GetFolderInfo.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = GetFolderInfo.json; sourceTree = ""; }; 0C00835F229C08F40067C1AF /* FolderUploadEmail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FolderUploadEmail.swift; sourceTree = ""; }; @@ -1694,6 +1698,7 @@ 225639202253897D00D951B5 /* SharedLink.swift */, 05610A942710612A009F92CC /* SignRequest.swift */, 05610A9A271099A7009F92CC /* SignRequestPrefillTag.swift */, + 05FAB0C62B9782AE000B22E0 /* SignRequestSignatureColor.swift */, 05610A9627106ACA009F92CC /* SignRequestSigner.swift */, 054D789827158DAB00E1E273 /* SignRequestSignerDecision.swift */, 05610A9C27109BFB009F92CC /* SignRequestSignerInput.swift */, @@ -2147,6 +2152,7 @@ F99DB496233C41440065317F /* RetentionPolicySpecs.swift */, 05F59F0826FC871A00D9A539 /* SharedItemSpecs.swift */, 05EE814B2718658F006A2329 /* SignRequestPrefillTagSpecs.swift */, + 05FAB0C82B98614C000B22E0 /* SignRequestSignatureColorSpecs.swift */, 05EE814927186427006A2329 /* SignRequestSignerDecisionTypeSpecs.swift */, 050E725028BE54C000213B4D /* SignRequestSignerInputContentTypeSpecs.swift */, 05EE814D27186880006A2329 /* SignRequestSignerInputTypeSpecs.swift */, @@ -2983,6 +2989,7 @@ 225639AA2253897D00D951B5 /* FilesModule.swift in Sources */, 2263863E2306D5BD002CE1BE /* UploadPart.swift in Sources */, 9717866B22F0B868004A5F6D /* LockData.swift in Sources */, + 05FAB0C72B9782AE000B22E0 /* SignRequestSignatureColor.swift in Sources */, 9D9C80A422D8E11000AFC18C /* NullableParameter.swift in Sources */, 225639322253897D00D951B5 /* Coders.swift in Sources */, 22C41459231FDB4B00D3992C /* MetadataCascadePolicy.swift in Sources */, @@ -3131,6 +3138,7 @@ 0C506CA922A6AA76007F18A4 /* CollaborationsModuleSpecs.swift in Sources */, 97F04DBA22B981430034B9A3 /* GroupSpecs.swift in Sources */, 9771D4DF22B01CC200B76DF8 /* CollaborationSpecs.swift in Sources */, + 05FAB0CA2B9861B3000B22E0 /* SignRequestSignatureColorSpecs.swift in Sources */, 0C63989F2253A536004021D3 /* FolderModuleSpecs.swift in Sources */, 9DB4F7BC22E1EBAA002C4697 /* BoxModelSpecs.swift in Sources */, 8053E2D022B04534000B42E1 /* SharedItemsModuleSpecs.swift in Sources */, diff --git a/Cartfile.private b/Cartfile.private index e0f6c6d5a..e25553602 100644 --- a/Cartfile.private +++ b/Cartfile.private @@ -1,3 +1,3 @@ github "Quick/Quick" "v7.0.0" github "Quick/Nimble" "v12.0.0" -github "AliSoftware/OHHTTPStubs" "9.1.0" +github "AliSoftware/OHHTTPStubs" "master" diff --git a/Cartfile.resolved b/Cartfile.resolved index 15a46e427..a5aed601e 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,3 +1,3 @@ -github "AliSoftware/OHHTTPStubs" "9.1.0" +github "AliSoftware/OHHTTPStubs" "c582400a38590a3dabb4353416d9d46cb7278d06" github "Quick/Nimble" "v12.0.0" github "Quick/Quick" "v7.0.0" diff --git a/IntegrationTests/SignRequestsModuleIntegrationSpecs.swift b/IntegrationTests/SignRequestsModuleIntegrationSpecs.swift index aa7a914dc..cb01cb2f6 100644 --- a/IntegrationTests/SignRequestsModuleIntegrationSpecs.swift +++ b/IntegrationTests/SignRequestsModuleIntegrationSpecs.swift @@ -47,22 +47,40 @@ class SignRequestsModuleIntegrationSpecs: QuickSpec { return } - let signer = SignRequestCreateSigner( - email: "sdk_integration_test@boxdemo.com", - role: .signer, - redirectUrl: "https://www.box.com/redirect_url_signer_1", - declinedRedirectUrl: "https://www.box.com/declined_redirect_url_singer_1" - ) + let signers = [ + SignRequestCreateSigner( + email: "sdk_integration_test_1@boxdemo.com", + role: .signer, + redirectUrl: "https://www.box.com/redirect_url_signer_1", + declinedRedirectUrl: "https://www.box.com/declined_redirect_url_singer_1", + loginRequired: false, + password: "password", + signerGroupId: "SignerGroup" + ), + SignRequestCreateSigner( + email: "sdk_integration_test_2@boxdemo.com", + role: .signer, + redirectUrl: "https://www.box.com/redirect_url_signer_2", + declinedRedirectUrl: "https://www.box.com/declined_redirect_url_singer_2", + loginRequired: false, + verificationPhoneNumber: "+48123456789", + password: "password", + signerGroupId: "SignerGroup" + ) + ] let signParameters = SignRequestCreateParameters( redirectUrl: "https://www.box.com/redirect_url", - declinedRedirectUrl: "https://www.box.com/declined_redirect_url" + declinedRedirectUrl: "https://www.box.com/declined_redirect_url", + name: "Sign created by iOS SDK", + isPhoneVerificationRequiredToView: false, + signatureColor: .black ) // Create waitUntil(timeout: .seconds(Constants.Timeout.large)) { done in client.signRequests.create( - signers: [signer], + signers: signers, sourceFiles: [ SignRequestCreateSourceFile(id: fileToSign1.id), SignRequestCreateSourceFile(id: fileToSign2.id) @@ -73,10 +91,27 @@ class SignRequestsModuleIntegrationSpecs: QuickSpec { switch result { case let .success(signRequestResult): signRequest = signRequestResult + expect(signRequest?.name).to(equal(signParameters.name)) + expect(signRequest?.isPhoneVerificationRequiredToView).to(equal(signParameters.isPhoneVerificationRequiredToView)) + expect(signRequest?.signatureColor).to(equal(signParameters.signatureColor)) expect(signRequest?.redirectUrl).to(equal(signParameters.redirectUrl)) expect(signRequest?.declinedRedirectUrl).to(equal(signParameters.declinedRedirectUrl)) expect(signRequest?.parentFolder.id).to(equal(rootFolder.id)) expect(signRequest?.signFiles?.files?.count).to(equal(2)) + // first signer is the sender with role final_copy_reader, second and third is the recipient with role signer + expect(signRequest?.signers.count).to(equal(3)) + expect(signRequest?.signers[1].signerGroupId).notTo(beNil()) + expect(signRequest?.signers[1].signerGroupId).to(equal(signRequest?.signers[2].signerGroupId)) + expect(signRequest?.signers[1].email).to(equal(signers[0].email)) + expect(signRequest?.signers[1].redirectUrl).to(equal(signers[0].redirectUrl)) + expect(signRequest?.signers[1].declinedRedirectUrl).to(equal(signers[0].declinedRedirectUrl)) + expect(signRequest?.signers[1].loginRequired).to(equal(signers[0].loginRequired)) + expect(signRequest?.signers[2].signerGroupId).notTo(beNil()) + expect(signRequest?.signers[2].email).to(equal(signers[1].email)) + expect(signRequest?.signers[2].redirectUrl).to(equal(signers[1].redirectUrl)) + expect(signRequest?.signers[2].declinedRedirectUrl).to(equal(signers[1].declinedRedirectUrl)) + expect(signRequest?.signers[2].loginRequired).to(equal(signers[1].loginRequired)) + expect(signRequest?.signers[2].verificationPhoneNumber).to(equal(signers[1].verificationPhoneNumber)) case let .failure(error): fail("Expected create call to succeed, but instead got \(error)") } diff --git a/Sources/Requests/BodyData/SignRequestCreateParameters.swift b/Sources/Requests/BodyData/SignRequestCreateParameters.swift index 6690e4e0a..192df0bd5 100644 --- a/Sources/Requests/BodyData/SignRequestCreateParameters.swift +++ b/Sources/Requests/BodyData/SignRequestCreateParameters.swift @@ -109,6 +109,20 @@ public struct SignRequestCreateSigner: Encodable { public let redirectUrl: String? /// The URL that a signer will be redirect to after declining to sign a document. public let declinedRedirectUrl: String? + /// If set to true, signer will need to login to a Box account before signing the request. + /// If the signer does not have an existing account, they will have an option to create a free Box account. + public let loginRequired: Bool? + /// If set, this phone number is be used to verify the signer via two factor authentication before they are able to sign the document. + public let verificationPhoneNumber: String? + /// If set, the signer is required to enter the password before they are able to sign a document. This field is write only. + public let password: String? + /// If set, signers who have the same value will be assigned to the same input and to the same signer group. + /// A signer group is expected to have more than one signer. + /// If the provided value is only used for one signer, this value will be ignored and request will be handled + /// as it was intended for an individual signer. The value provided can be any string and only used to + /// determine which signers belongs to same group. A successful response will provide a generated UUID value + /// instead for signers in the same signer group. + public let signerGroupId: String? /// Initializer. /// @@ -121,6 +135,12 @@ public struct SignRequestCreateSigner: Encodable { /// - embedUrlExternalUserId: User ID for the signer in an external application responsible for authentication when accessing the embed URL. /// - redirectUrl: The URL that the signer will be redirected to after signing. /// - declinedRedirectUrl: The URL that a signer will be redirect to after declining to sign a document. + /// - loginRequired: If set to true, signer will need to login to a Box account before signing the request. + /// If the signer does not have an existing account, they will have an option to create a free Box account. + /// - verificationPhoneNumber: If set, the signer is required to enter the password before they are able to sign a document. This field is write only. + /// - password: If set, the signer is required to enter the password before they are able to sign a document. This field is write only. + /// - signerGroupId: If set, signers who have the same value will be assigned to the same input and to the same signer group. + /// A signer group is expected to have more than one signer. public init( email: String, role: SignRequestSignerRole? = nil, @@ -128,7 +148,11 @@ public struct SignRequestCreateSigner: Encodable { order: Int? = nil, embedUrlExternalUserId: String? = nil, redirectUrl: String? = nil, - declinedRedirectUrl: String? = nil + declinedRedirectUrl: String? = nil, + loginRequired: Bool? = nil, + verificationPhoneNumber: String? = nil, + password: String? = nil, + signerGroupId: String? = nil ) { self.email = email self.role = role @@ -137,6 +161,10 @@ public struct SignRequestCreateSigner: Encodable { self.embedUrlExternalUserId = embedUrlExternalUserId self.redirectUrl = redirectUrl self.declinedRedirectUrl = declinedRedirectUrl + self.loginRequired = loginRequired + self.verificationPhoneNumber = verificationPhoneNumber + self.password = password + self.signerGroupId = signerGroupId } } @@ -170,6 +198,14 @@ public struct SignRequestCreateParameters: Encodable { public let redirectUrl: String? /// The URL that the signer will be redirected to after declining to sign a document. public let declinedRedirectUrl: String? + /// Name of the sign request. + public let name: String? + /// Forces signers to verify a text message prior to viewing the document. You must specify the phone number of signers to have this setting apply to them. + public let isPhoneVerificationRequiredToView: Bool? + /// When a signature request is created from a template this field will indicate the id of that template. + public let templateId: String? + /// Specific color for the signature (blue, black, or red). + public let signatureColor: SignRequestSignatureColor? /// Initializer. /// @@ -184,6 +220,10 @@ public struct SignRequestCreateParameters: Encodable { /// - externalId: ID that serve as reference in an external system that the sign request is related to. /// - redirectUrl: The URL that a signer will be redirected to after signing a document. /// - declinedRedirectUrl: The URL that the signer will be redirected to after declining to sign a document. + /// - name: Name of the sign request. + /// - isPhoneVerificationRequiredToView: Forces signers to verify a text message prior to viewing the document. You must specify the phone number of signers to have this setting apply to them. + /// - templateId: When a signature request is created from a template this field will indicate the id of that template. + /// - signatureColor: Force a specific color for the signature (blue, black, or red). public init( isDocumentPreparationNeeded: Bool? = nil, areTextSignaturesEnabled: Bool? = nil, @@ -194,7 +234,11 @@ public struct SignRequestCreateParameters: Encodable { daysValid: Int? = nil, externalId: String? = nil, redirectUrl: String? = nil, - declinedRedirectUrl: String? = nil + declinedRedirectUrl: String? = nil, + name: String? = nil, + isPhoneVerificationRequiredToView: Bool? = nil, + templateId: String? = nil, + signatureColor: SignRequestSignatureColor? = nil ) { self.isDocumentPreparationNeeded = isDocumentPreparationNeeded self.areTextSignaturesEnabled = areTextSignaturesEnabled @@ -206,5 +250,9 @@ public struct SignRequestCreateParameters: Encodable { self.externalId = externalId self.redirectUrl = redirectUrl self.declinedRedirectUrl = declinedRedirectUrl + self.name = name + self.isPhoneVerificationRequiredToView = isPhoneVerificationRequiredToView + self.templateId = templateId + self.signatureColor = signatureColor } } diff --git a/Sources/Responses/SignRequest.swift b/Sources/Responses/SignRequest.swift index 37a06c7ca..ec7c96cd1 100644 --- a/Sources/Responses/SignRequest.swift +++ b/Sources/Responses/SignRequest.swift @@ -162,6 +162,14 @@ public class SignRequest: BoxModel { public let redirectUrl: String? /// The URL that a signer will be redirected to after declined signing a document. public let declinedRedirectUrl: String? + /// Name of the sign request. + public let name: String? + /// Forces signers to verify a text message prior to viewing the document. You must specify the phone number of signers to have this setting apply to them. + public let isPhoneVerificationRequiredToView: Bool? + /// When a signature request is created from a template this field will indicate the id of that template. + public let templateId: String? + /// Specific color for the signature (blue, black, or red). + public let signatureColor: SignRequestSignatureColor? /// Initializer. /// @@ -198,5 +206,9 @@ public class SignRequest: BoxModel { externalId = try BoxJSONDecoder.optionalDecode(json: json, forKey: "external_id") redirectUrl = try BoxJSONDecoder.optionalDecode(json: json, forKey: "redirect_url") declinedRedirectUrl = try BoxJSONDecoder.optionalDecode(json: json, forKey: "declined_redirect_url") + name = try BoxJSONDecoder.optionalDecode(json: json, forKey: "name") + isPhoneVerificationRequiredToView = try BoxJSONDecoder.optionalDecode(json: json, forKey: "is_phone_verification_required_to_view") + templateId = try BoxJSONDecoder.optionalDecode(json: json, forKey: "template_id") + signatureColor = try BoxJSONDecoder.optionalDecodeEnum(json: json, forKey: "signature_color") } } diff --git a/Sources/Responses/SignRequestSignatureColor.swift b/Sources/Responses/SignRequestSignatureColor.swift new file mode 100644 index 000000000..2f2db2dde --- /dev/null +++ b/Sources/Responses/SignRequestSignatureColor.swift @@ -0,0 +1,47 @@ +// +// SignRequestSignatureColor.swift +// BoxSDK-iOS +// +// Created by Artur Jankowski on 05/03/2024. +// Copyright © 2024 box. All rights reserved. +// + +import Foundation + +/// Force a specific color for the signature +public enum SignRequestSignatureColor: BoxEnum { + /// blue color + case blue + /// black color + case black + /// red color + case red + /// A custom value not implemented in this version of SDK. + case customValue(String) + + public init(_ value: String) { + switch value { + case "blue": + self = .blue + case "black": + self = .black + case "red": + self = .red + default: + self = .customValue(value) + } + } + + public var description: String { + switch self { + case .blue: + return "blue" + case .black: + return "black" + case .red: + return "red" + case let .customValue(userValue): + return userValue + } + } +} diff --git a/Sources/Responses/SignRequestSigner.swift b/Sources/Responses/SignRequestSigner.swift index cc2ef9294..18e515d58 100644 --- a/Sources/Responses/SignRequestSigner.swift +++ b/Sources/Responses/SignRequestSigner.swift @@ -77,6 +77,22 @@ public class SignRequestSigner: BoxModel { public let redirectUrl: String? /// The URL that a signer will be redirect to after declining to sign a document. public let declinedRedirectUrl: String? + /// This URL is specifically designed for signing documents within an HTML `iframe` tag. + public let iframeableEmbedUrl: String? + /// If set to true, signer will need to login to a Box account before signing the request. + /// If the signer does not have an existing account, they will have an option to create a free Box account. + public let loginRequired: Bool? + /// If set, this phone number is be used to verify the signer via two factor authentication before they are able to sign the document. + public let verificationPhoneNumber: String? + /// If set, the signer is required to enter the password before they are able to sign a document. This field is write only. + public let password: String? + /// If set, signers who have the same value will be assigned to the same input and to the same signer group. + /// A signer group is expected to have more than one signer. + /// If the provided value is only used for one signer, this value will be ignored and request will be handled + /// as it was intended for an individual signer. The value provided can be any string and only used to + /// determine which signers belongs to same group. A successful response will provide a generated UUID value + /// instead for signers in the same signer group. + public let signerGroupId: String? /// Initializer. /// @@ -95,5 +111,10 @@ public class SignRequestSigner: BoxModel { embedUrl = try BoxJSONDecoder.optionalDecode(json: json, forKey: "embed_url") redirectUrl = try BoxJSONDecoder.optionalDecode(json: json, forKey: "redirect_url") declinedRedirectUrl = try BoxJSONDecoder.optionalDecode(json: json, forKey: "declined_redirect_url") + iframeableEmbedUrl = try BoxJSONDecoder.optionalDecode(json: json, forKey: "iframeable_embed_url") + loginRequired = try BoxJSONDecoder.optionalDecode(json: json, forKey: "login_required") + verificationPhoneNumber = try BoxJSONDecoder.optionalDecode(json: json, forKey: "verification_phone_number") + password = try BoxJSONDecoder.optionalDecode(json: json, forKey: "password") + signerGroupId = try BoxJSONDecoder.optionalDecode(json: json, forKey: "signer_group_id") } } diff --git a/Sources/Responses/SignRequestSignerInput.swift b/Sources/Responses/SignRequestSignerInput.swift index 28fa11cd4..9f9340639 100644 --- a/Sources/Responses/SignRequestSignerInput.swift +++ b/Sources/Responses/SignRequestSignerInput.swift @@ -18,6 +18,10 @@ public enum SignRequestSignerInputType: BoxEnum { case text /// Checkbox input. case checkbox + /// Radio + case radio + /// Dropdown + case dropdown /// Custom value for enum values not yet implemented in the SDK case customValue(String) @@ -31,6 +35,10 @@ public enum SignRequestSignerInputType: BoxEnum { self = .text case "checkbox": self = .checkbox + case "radio": + self = .radio + case "dropdown": + self = .dropdown default: self = .customValue(value) } @@ -46,6 +54,10 @@ public enum SignRequestSignerInputType: BoxEnum { return "text" case .checkbox: return "checkbox" + case .radio: + return "radio" + case .dropdown: + return "dropdown" case let .customValue(value): return value } @@ -82,6 +94,10 @@ public enum SignRequestSignerInputContentType: BoxEnum { case checkbox /// Attachment case attachment + /// Radio + case radio + /// Dropdown + case dropdown /// Custom value for enum values not yet implemented in the SDK case customValue(String) @@ -115,6 +131,10 @@ public enum SignRequestSignerInputContentType: BoxEnum { self = .checkbox case "attachment": self = .attachment + case "radio": + self = .radio + case "dropdown": + self = .dropdown default: self = .customValue(value) } @@ -148,6 +168,10 @@ public enum SignRequestSignerInputContentType: BoxEnum { return "checkbox" case .attachment: return "attachment" + case .radio: + return "radio" + case .dropdown: + return "dropdown" case let .customValue(value): return value } diff --git a/Tests/Modules/SignRequestsModuleSpecs.swift b/Tests/Modules/SignRequestsModuleSpecs.swift index 97a044860..9ef2c965b 100644 --- a/Tests/Modules/SignRequestsModuleSpecs.swift +++ b/Tests/Modules/SignRequestsModuleSpecs.swift @@ -39,7 +39,18 @@ class SignRequestsModuleSpecs: QuickSpec { "email": "example@gmail.com", "role": "signer", "redirect_url": "https://box.com/redirect_url_signer_1", - "declined_redirect_url": "https://box.com/declined_redirect_url_signer_1" + "declined_redirect_url": "https://box.com/declined_redirect_url_signer_1", + "login_required": true, + "password": "1234567890", + "signer_group_id": "SignerGroup", + "verification_phone_number": "1234567890" + ], + [ + "email": "other-example@gmail.com", + "role": "signer", + "login_required": false, + "signer_group_id": "SignerGroup", + "verification_phone_number": "1234567890" ] ], "source_files": [["id": "12345", "type": "file"]], @@ -56,7 +67,12 @@ class SignRequestsModuleSpecs: QuickSpec { "external_id": "123", "days_valid": 2, "redirect_url": "https://box.com/redirect_url", - "declined_redirect_url": "https://box.com/declined_redirect_url" + "declined_redirect_url": "https://box.com/declined_redirect_url", + "name": "Sign Acme", + "is_phone_verification_required_to_view": true, + "template_id": "123075213-af2c8822-3ef2-4952-8557-52d69c2fe9cb", + "signature_color": "black" + ]) ) { _ in HTTPStubsResponse( @@ -66,12 +82,25 @@ class SignRequestsModuleSpecs: QuickSpec { } waitUntil(timeout: .seconds(10)) { done in - let signers = [SignRequestCreateSigner( - email: "example@gmail.com", - role: .signer, - redirectUrl: "https://box.com/redirect_url_signer_1", - declinedRedirectUrl: "https://box.com/declined_redirect_url_signer_1" - )] + let signers = [ + SignRequestCreateSigner( + email: "example@gmail.com", + role: .signer, + redirectUrl: "https://box.com/redirect_url_signer_1", + declinedRedirectUrl: "https://box.com/declined_redirect_url_signer_1", + loginRequired: true, + verificationPhoneNumber: "1234567890", + password: "1234567890", + signerGroupId: "SignerGroup" + ), + SignRequestCreateSigner( + email: "other-example@gmail.com", + role: .signer, + loginRequired: false, + verificationPhoneNumber: "1234567890", + signerGroupId: "SignerGroup" + ) + ] let sourceFiles = [SignRequestCreateSourceFile(id: "12345")] let parentFolder = SignRequestCreateParentFolder(id: "12345") let tags = [ @@ -88,7 +117,11 @@ class SignRequestsModuleSpecs: QuickSpec { daysValid: 2, externalId: "123", redirectUrl: "https://box.com/redirect_url", - declinedRedirectUrl: "https://box.com/declined_redirect_url" + declinedRedirectUrl: "https://box.com/declined_redirect_url", + name: "Sign Acme", + isPhoneVerificationRequiredToView: true, + templateId: "123075213-af2c8822-3ef2-4952-8557-52d69c2fe9cb", + signatureColor: .black ) sut.signRequests.create( @@ -106,14 +139,22 @@ class SignRequestsModuleSpecs: QuickSpec { expect(signRequest.sourceFiles.first?.name).to(equal("Contract.pdf")) expect(signRequest.parentFolder.id).to(equal("12345")) expect(signRequest.parentFolder.name).to(equal("Contracts")) + expect(signRequest.signers.count).to(equal(2)) expect(signRequest.signers[0].redirectUrl).to(equal("https://box.com/redirect_url_signer_1")) expect(signRequest.signers[0].declinedRedirectUrl).to(equal("https://box.com/declined_redirect_url_signer_1")) + expect(signRequest.signers[0].loginRequired).to(equal(true)) + expect(signRequest.signers[0].password).to(equal("1234567890")) + expect(signRequest.signers[0].signerGroupId).to(equal("cd4ff89-8fc1-42cf-8b29-1890dedd26d7")) + expect(signRequest.signers[0].verificationPhoneNumber).to(equal("1234567890")) expect(signRequest.signers[0].inputs?[0].documentTagId).to(equal("1234")) expect(signRequest.signers[0].inputs?[0].textValue).to(equal("text")) expect(signRequest.signers[0].inputs?[0].contentType).to(equal(.text)) expect(signRequest.signers[0].inputs?[1].documentTagId).to(equal("4567")) expect(signRequest.signers[0].inputs?[1].dateValue).to(equal("2021-12-03".iso8601)) expect(signRequest.signers[0].inputs?[1].contentType).to(equal(.date)) + expect(signRequest.signers[1].loginRequired).to(equal(false)) + expect(signRequest.signers[1].signerGroupId).to(equal("cd4ff89-8fc1-42cf-8b29-1890dedd26d7")) + expect(signRequest.signers[1].verificationPhoneNumber).to(equal("1234567890")) expect(signRequest.prefillTags?[0].documentTagId).to(equal("1234")) expect(signRequest.prefillTags?[0].textValue).to(equal("text")) expect(signRequest.prefillTags?[1].documentTagId).to(equal("4567")) @@ -124,6 +165,10 @@ class SignRequestsModuleSpecs: QuickSpec { expect(signRequest.daysValid).to(equal(2)) expect(signRequest.redirectUrl).to(equal("https://box.com/redirect_url")) expect(signRequest.declinedRedirectUrl).to(equal("https://box.com/declined_redirect_url")) + expect(signRequest.name).to(equal("Sign Acme")) + expect(signRequest.isPhoneVerificationRequiredToView).to(equal(true)) + expect(signRequest.templateId).to(equal("123075213-af2c8822-3ef2-4952-8557-52d69c2fe9cb")) + expect(signRequest.signatureColor).to(equal(.black)) case let .failure(error): fail("Expected call to create to succeed, but it failed: \(error)") } diff --git a/Tests/Responses/SignRequestSignatureColorSpecs.swift b/Tests/Responses/SignRequestSignatureColorSpecs.swift new file mode 100644 index 000000000..2658c2cf4 --- /dev/null +++ b/Tests/Responses/SignRequestSignatureColorSpecs.swift @@ -0,0 +1,29 @@ +// +// SignRequestSignatureColorSpecs.swift +// BoxSDK-iOS +// +// Created by Artur Jankowski on 06/03/2024. +// Copyright © 2024 box. All rights reserved. +// + +@testable import BoxSDK +import Nimble +import Quick + +class SignRequestSignatureColorSpecs: QuickSpec { + + override class func spec() { + describe("SignRequestSignatureColor") { + + describe("init()") { + + it("should correctly create an enum value from it's string representation") { + expect(SignRequestSignatureColor.black).to(equal(SignRequestSignatureColor(SignRequestSignatureColor.black.description))) + expect(SignRequestSignatureColor.blue).to(equal(SignRequestSignatureColor(SignRequestSignatureColor.blue.description))) + expect(SignRequestSignatureColor.red).to(equal(SignRequestSignatureColor(SignRequestSignatureColor.red.description))) + expect(SignRequestSignatureColor.customValue("custom value")).to(equal(SignRequestSignatureColor("custom value"))) + } + } + } + } +} diff --git a/Tests/Responses/SignRequestSpecs.swift b/Tests/Responses/SignRequestSpecs.swift index 713d12a92..b95f52250 100644 --- a/Tests/Responses/SignRequestSpecs.swift +++ b/Tests/Responses/SignRequestSpecs.swift @@ -40,10 +40,18 @@ class SignRequestSpecs: QuickSpec { expect(signRequest.autoExpireAt?.iso8601).to(equal("2021-04-26T08:12:13Z")) expect(signRequest.redirectUrl).to(equal("https://box.com/redirect_url")) expect(signRequest.declinedRedirectUrl).to(equal("https://box.com/declined_redirect_url")) + expect(signRequest.templateId).to(equal("123075213-af2c8822-3ef2-4952-8557-52d69c2fe9cb")) + expect(signRequest.name).to(equal("Contract.pdf")) + expect(signRequest.signatureColor).to(equal(.blue)) + expect(signRequest.isPhoneVerificationRequiredToView).to(equal(true)) expect(signRequest.signers[0].email).to(equal("example@gmail.com")) expect(signRequest.signers[0].role).to(equal(.signer)) expect(signRequest.signers[0].isInPerson).to(equal(true)) expect(signRequest.signers[0].order).to(equal(2)) + expect(signRequest.signers[0].loginRequired).to(equal(true)) + expect(signRequest.signers[0].verificationPhoneNumber).to(equal("6314578901")) + expect(signRequest.signers[0].password).to(equal("SecretPassword123")) + expect(signRequest.signers[0].signerGroupId).to(equal("cd4ff89-8fc1-42cf-8b29-1890dedd26d7")) expect(signRequest.signers[0].embedUrlExternalUserId).to(equal("1234")) expect(signRequest.signers[0].hasViewedDocument).to(equal(true)) expect(signRequest.signers[0].embedUrl).to(equal("https://example.com")) diff --git a/Tests/Stubs/Resources/SignRequests/CreateSignRequest.json b/Tests/Stubs/Resources/SignRequests/CreateSignRequest.json index c9d16f2f1..41456ba67 100644 --- a/Tests/Stubs/Resources/SignRequests/CreateSignRequest.json +++ b/Tests/Stubs/Resources/SignRequests/CreateSignRequest.json @@ -4,6 +4,10 @@ "email_subject": "Sign Request from Acme", "email_message": "Hello! Please sign the document below", "are_reminders_enabled": true, + "name": "Sign Acme", + "is_phone_verification_required_to_view": true, + "template_id": "123075213-af2c8822-3ef2-4952-8557-52d69c2fe9cb", + "signature_color": "black", "signers": [ { "email": "example@gmail.com", @@ -38,7 +42,41 @@ ], "embed_url": "https://example.com", "redirect_url": "https://box.com/redirect_url_signer_1", - "declined_redirect_url": "https://box.com/declined_redirect_url_signer_1" + "declined_redirect_url": "https://box.com/declined_redirect_url_signer_1", + "login_required": true, + "password": "1234567890", + "signer_group_id": "cd4ff89-8fc1-42cf-8b29-1890dedd26d7", + "verification_phone_number": "1234567890" + }, + { + "email": "other-example@gmail.com", + "role": "signer", + "is_in_person": true, + "order": 2, + "embed_url_external_user_id": "1234", + "has_viewed_document": true, + "signer_decision": { + "type": "signed", + "finalized_at": "2021-04-26T08:12:13.982Z" + }, + "inputs": [ + { + "document_tag_id": "1234", + "text_value": "text", + "checkbox_value": true, + "date_value": "2021-04-26T08:12:13.982Z", + "type": "text", + "page_index": 4, + "content_type": "checkbox" + } + ], + "embed_url": "https://example.com", + "redirect_url": "https://box.com/redirect_url_signer_1", + "declined_redirect_url": "https://box.com/declined_redirect_url_signer_1", + "iframeable_embed_url": "https://app.box.com/embed/sign/document/bf7aaac6/", + "login_required": false, + "signer_group_id": "cd4ff89-8fc1-42cf-8b29-1890dedd26d7", + "verification_phone_number": "1234567890" } ], "source_files": [ diff --git a/Tests/Stubs/Resources/SignRequests/FullSignRequest.json b/Tests/Stubs/Resources/SignRequests/FullSignRequest.json index d216581e2..08ad4d053 100644 --- a/Tests/Stubs/Resources/SignRequests/FullSignRequest.json +++ b/Tests/Stubs/Resources/SignRequests/FullSignRequest.json @@ -27,7 +27,11 @@ ], "embed_url": "https://example.com", "redirect_url": "https://box.com/redirect_url_signer_1", - "declined_redirect_url": "https://box.com/declined_redirect_url_signer_1" + "declined_redirect_url": "https://box.com/declined_redirect_url_signer_1", + "login_required": true, + "verification_phone_number": "6314578901", + "password": "SecretPassword123", + "signer_group_id": "cd4ff89-8fc1-42cf-8b29-1890dedd26d7", } ], "source_files": [ @@ -97,5 +101,9 @@ ], "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": "123075213-af2c8822-3ef2-4952-8557-52d69c2fe9cb", + "name": "Contract.pdf", + "signature_color": "blue", + "is_phone_verification_required_to_view": true } From ae8237c754bf496bdf420104a86e3e55a72074ab Mon Sep 17 00:00:00 2001 From: Artur Jankowski Date: Fri, 8 Mar 2024 10:55:22 +0100 Subject: [PATCH 2/2] fixes --- IntegrationTests/SignRequestsModuleIntegrationSpecs.swift | 3 +++ Sources/Responses/SignRequestSigner.swift | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/IntegrationTests/SignRequestsModuleIntegrationSpecs.swift b/IntegrationTests/SignRequestsModuleIntegrationSpecs.swift index cb01cb2f6..87b2a3851 100644 --- a/IntegrationTests/SignRequestsModuleIntegrationSpecs.swift +++ b/IntegrationTests/SignRequestsModuleIntegrationSpecs.swift @@ -100,13 +100,16 @@ class SignRequestsModuleIntegrationSpecs: QuickSpec { expect(signRequest?.signFiles?.files?.count).to(equal(2)) // first signer is the sender with role final_copy_reader, second and third is the recipient with role signer expect(signRequest?.signers.count).to(equal(3)) + expect(signRequest?.signers[0].role).to(equal(.finalCopyReader)) expect(signRequest?.signers[1].signerGroupId).notTo(beNil()) expect(signRequest?.signers[1].signerGroupId).to(equal(signRequest?.signers[2].signerGroupId)) + expect(signRequest?.signers[1].role).to(equal(.signer)) expect(signRequest?.signers[1].email).to(equal(signers[0].email)) expect(signRequest?.signers[1].redirectUrl).to(equal(signers[0].redirectUrl)) expect(signRequest?.signers[1].declinedRedirectUrl).to(equal(signers[0].declinedRedirectUrl)) expect(signRequest?.signers[1].loginRequired).to(equal(signers[0].loginRequired)) expect(signRequest?.signers[2].signerGroupId).notTo(beNil()) + expect(signRequest?.signers[2].role).to(equal(.signer)) expect(signRequest?.signers[2].email).to(equal(signers[1].email)) expect(signRequest?.signers[2].redirectUrl).to(equal(signers[1].redirectUrl)) expect(signRequest?.signers[2].declinedRedirectUrl).to(equal(signers[1].declinedRedirectUrl)) diff --git a/Sources/Responses/SignRequestSigner.swift b/Sources/Responses/SignRequestSigner.swift index 18e515d58..c64603bc0 100644 --- a/Sources/Responses/SignRequestSigner.swift +++ b/Sources/Responses/SignRequestSigner.swift @@ -77,7 +77,7 @@ public class SignRequestSigner: BoxModel { public let redirectUrl: String? /// The URL that a signer will be redirect to after declining to sign a document. public let declinedRedirectUrl: String? - /// This URL is specifically designed for signing documents within an HTML `iframe` tag. + /// This URL is specifically designed for signing documents within an HTML `iframe` tag. public let iframeableEmbedUrl: String? /// If set to true, signer will need to login to a Box account before signing the request. /// If the signer does not have an existing account, they will have an option to create a free Box account.