From 18d3413afeddf43c62dfd0caf1279e61c99b6b83 Mon Sep 17 00:00:00 2001 From: Minh Nguyen Cong Date: Thu, 7 Sep 2023 12:09:12 +0200 Subject: [PATCH] feat: Support sign template (#848) * feat: Support sign template * Update type field --- codegen/codegen.tsx | 16 ++++ docs/sign-templates.md | 41 +++++++++ src/box-client.ts | 3 + src/managers/sign-templates.generated.ts | 82 +++++++++++++++++ src/schemas/folder-mini.generated.ts | 10 +-- src/schemas/index.generated.ts | 4 + src/schemas/sign-request-base.generated.ts | 9 +- .../sign-request-create-request.generated.ts | 12 +-- src/schemas/sign-request-signer.generated.ts | 10 +++ src/schemas/sign-request.generated.ts | 12 +-- src/schemas/sign-requests.generated.ts | 3 + src/schemas/sign-template.generated.ts | 88 +++++++++++++++++++ src/schemas/sign-templates.generated.ts | 18 ++++ .../template-signer-input.generated.ts | 66 ++++++++++++++ src/schemas/template-signer.generated.ts | 36 ++++++++ src/schemas/user-base.generated.ts | 2 +- tests/lib/managers/sign-templates-test.js | 86 ++++++++++++++++++ 17 files changed, 475 insertions(+), 23 deletions(-) create mode 100644 docs/sign-templates.md create mode 100644 src/managers/sign-templates.generated.ts create mode 100644 src/schemas/sign-template.generated.ts create mode 100644 src/schemas/sign-templates.generated.ts create mode 100644 src/schemas/template-signer-input.generated.ts create mode 100644 src/schemas/template-signer.generated.ts create mode 100644 tests/lib/managers/sign-templates-test.js diff --git a/codegen/codegen.tsx b/codegen/codegen.tsx index bd1e98109..249074df0 100644 --- a/codegen/codegen.tsx +++ b/codegen/codegen.tsx @@ -40,6 +40,22 @@ import { generateManagerClasses } from './generate-manager-classes'; }, ], }, + { + name: 'SignTemplatesManager', + comment: + 'Simple manager for interacting with all Sign Templates endpoints and actions.', + relativePath: '../src/managers/sign-templates.generated.ts', + operations: [ + { + name: 'getById', + operationId: 'get_sign_templates_id', + }, + { + name: 'getAll', + operationId: 'get_sign_templates', + }, + ], + }, { name: 'ShieldInformationBarrierManager', comment: '', diff --git a/docs/sign-templates.md b/docs/sign-templates.md new file mode 100644 index 000000000..b795faf9e --- /dev/null +++ b/docs/sign-templates.md @@ -0,0 +1,41 @@ +# Sign Templates + + + + + + +- [Get sign template by ID](#get-sign-template-by-id) +- [List sign templates](#list-sign-templates) + + + + + +## Get sign template by ID + +Gets a sign template by ID [`signTemplates.getById(options, callback)`](http://opensource.box.com/box-node-sdk/jsdoc/SignTemplatesManager.html#getById) +method. + + + +```js +const sr = await client.signTemplates.getById({ + sign_request_id: 12345, +}); +console.log( + `Sign request id ${sr.id} contains ${sr.source_files.length} files` +); +``` + +## List sign templates + +Gets sign templates created by a user [`signTemplates.getAll(options, callback)`](http://opensource.box.com/box-node-sdk/jsdoc/SignTemplatesManager.html#getAll) +method. + + + +```js +const result = await client.signTemplates.getAll(); +console.log(`There are ${result.count} sign templates`); +``` diff --git a/src/box-client.ts b/src/box-client.ts index 303671213..0bedf75c5 100644 --- a/src/box-client.ts +++ b/src/box-client.ts @@ -23,6 +23,7 @@ import RetentionPolicies from './managers/retention-policies'; import Search from './managers/search'; import SharedItems from './managers/shared-items'; import SignRequests from './managers/sign-requests.generated'; +import SignTemplates from './managers/sign-templates.generated'; import StoragePolicies from './managers/storage-policies'; import Tasks from './managers/tasks'; import TermsOfService from './managers/terms-of-service'; @@ -200,6 +201,7 @@ class BoxClient { termsOfService: any; storagePolicies: any; signRequests: SignRequests; + signTemplates: SignTemplates; shieldInformationBarriers: ShieldInformationBarriers; shieldInformationBarrierSegments: ShieldInformationBarrierSegments; shieldInformationBarrierSegmentMembers: ShieldInformationBarrierSegmentMembers; @@ -274,6 +276,7 @@ class BoxClient { this.termsOfService = new TermsOfService(this); this.storagePolicies = new StoragePolicies(this); this.signRequests = new SignRequests(this); + this.signTemplates = new SignTemplates(this); this.shieldInformationBarriers = new ShieldInformationBarriers(this); this.shieldInformationBarrierSegments = new ShieldInformationBarrierSegments(this); this.shieldInformationBarrierSegmentMembers = new ShieldInformationBarrierSegmentMembers(this); diff --git a/src/managers/sign-templates.generated.ts b/src/managers/sign-templates.generated.ts new file mode 100644 index 000000000..dfa944b38 --- /dev/null +++ b/src/managers/sign-templates.generated.ts @@ -0,0 +1,82 @@ +import BoxClient from '../box-client'; +import urlPath from '../util/url-path'; +import * as schemas from '../schemas'; +/** + * Simple manager for interacting with all Sign Templates endpoints and actions. + */ +class SignTemplatesManager { + client: BoxClient; + /** + * @param {BoxClient} client The Box API Client that is responsible for making calls to the API + */ + constructor(client: BoxClient) { + this.client = client; + } + /** + * Get Box Sign template by ID + * + * Fetches details of a specific Box Sign template. + * @param {object} options Options for the request + * @param {string} options.template_id The ID of a Box Sign template. + * @param {Function} [callback] Passed the result if successful, error otherwise + * @returns {Promise} A promise resolving to the result or rejecting with an error + */ + getById( + options: { + /** + * The ID of a Box Sign template. + */ + readonly template_id: string; + }, + callback?: Function + ): Promise { + const { template_id: templateId, ...queryParams } = options, + apiPath = urlPath('sign_templates', templateId), + params = { + qs: queryParams, + }; + return this.client.wrapWithDefaultHandler(this.client.get)( + apiPath, + params, + callback + ); + } + /** + * List Box Sign templates + * + * Gets Box Sign templates created by a user. + * @param {object} [options] Options for the request + * @param {string} [options.marker] Defines the position marker at which to begin returning results. This is used when paginating using marker-based pagination. This requires `usemarker` to be set to `true`. + * @param {number} [options.limit] The maximum number of items to return per page. + * @param {Function} [callback] Passed the result if successful, error otherwise + * @returns {Promise} A promise resolving to the result or rejecting with an error + */ + getAll( + options?: { + /** + * Defines the position marker at which to begin returning results. This is + * used when paginating using marker-based pagination. + * + * This requires `usemarker` to be set to `true`. + */ + readonly marker?: string; + /** + * The maximum number of items to return per page. + */ + readonly limit?: number; + }, + callback?: Function + ): Promise { + const { ...queryParams } = options, + apiPath = urlPath('sign_templates'), + params = { + qs: queryParams, + }; + return this.client.wrapWithDefaultHandler(this.client.get)( + apiPath, + params, + callback + ); + } +} +export = SignTemplatesManager; diff --git a/src/schemas/folder-mini.generated.ts b/src/schemas/folder-mini.generated.ts index 76ffdea21..585aecc77 100644 --- a/src/schemas/folder-mini.generated.ts +++ b/src/schemas/folder-mini.generated.ts @@ -6,6 +6,11 @@ import * as schemas from '.'; * nested under another resource. */ export interface FolderMini extends schemas.FolderBase { + /** + * The name of the folder. + * Example: Contracts + */ + name?: string; /** * A numeric identifier that represents the most recent user event * that has been applied to this item. @@ -23,9 +28,4 @@ export interface FolderMini extends schemas.FolderBase { * Example: 3 */ sequence_id?: string; - /** - * The name of the folder. - * Example: Contracts - */ - name?: string; } diff --git a/src/schemas/index.generated.ts b/src/schemas/index.generated.ts index d19f49b44..5e466b702 100644 --- a/src/schemas/index.generated.ts +++ b/src/schemas/index.generated.ts @@ -26,4 +26,8 @@ export * from './sign-request-signer-input.generated'; export * from './sign-request-signer.generated'; export * from './sign-request.generated'; export * from './sign-requests.generated'; +export * from './sign-template.generated'; +export * from './sign-templates.generated'; +export * from './template-signer-input.generated'; +export * from './template-signer.generated'; export * from './user-base.generated'; diff --git a/src/schemas/sign-request-base.generated.ts b/src/schemas/sign-request-base.generated.ts index 78afdc421..0a2c580e3 100644 --- a/src/schemas/sign-request-base.generated.ts +++ b/src/schemas/sign-request-base.generated.ts @@ -1,6 +1,6 @@ import * as schemas from '.'; /** - * Create a sign request + * Sign Request (Base) * * A request to create a sign request object */ @@ -57,7 +57,7 @@ export interface SignRequestBase { */ prefill_tags?: schemas.SignRequestPrefillTag[]; /** - * Number of days after which this request will automatically expire if not completed. + * 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. * Example: 2 */ days_valid?: number; @@ -71,4 +71,9 @@ export interface SignRequestBase { * Example: true */ is_phone_verification_required_to_view?: boolean; + /** + * When a signature request is created from a template this field will indicate the id of that template. + * Example: 123075213-af2c8822-3ef2-4952-8557-52d69c2fe9cb + */ + template_id?: string; } diff --git a/src/schemas/sign-request-create-request.generated.ts b/src/schemas/sign-request-create-request.generated.ts index 6fa5474a1..f70c88164 100644 --- a/src/schemas/sign-request-create-request.generated.ts +++ b/src/schemas/sign-request-create-request.generated.ts @@ -6,17 +6,9 @@ import * as schemas from '.'; */ export interface SignRequestCreateRequest extends schemas.SignRequestBase { /** - * List of files to create a signing document from. This is currently - * limited to 10 files. Only the ID and type fields are required - * for each file. The array will be empty if the `source_files` - * are deleted. + * List of files to create a signing document from. This is currently limited to ten files. Only the ID and type fields are required for each file. */ - source_files?: schemas.FileMini[]; - /** - * Force a specific signature color (blue, black, or red). - * Example: blue - */ - signature_color?: 'blue' | 'black' | 'red'; + source_files?: schemas.FileBase[]; /** * Array of signers for the sign request. 35 is the * max number of signers permitted. diff --git a/src/schemas/sign-request-signer.generated.ts b/src/schemas/sign-request-signer.generated.ts index fbdb2486c..bf6025c2e 100644 --- a/src/schemas/sign-request-signer.generated.ts +++ b/src/schemas/sign-request-signer.generated.ts @@ -20,4 +20,14 @@ export interface SignRequestSigner extends schemas.SignRequestCreateSigner { * Example: https://example.com */ embed_url?: string; + /** + * This URL is specifically designed for + * signing documents within an HTML `iframe` tag. + * It will be returned in the response + * only if the `embed_url_external_user_id` + * parameter was passed in the + * `create sign request` call. + * Example: https://app.box.com/embed/sign/document/gfhr4222-a331-494b-808b-79bc7f3992a3/f14d7098-a331-494b-808b-79bc7f3992a4 + */ + iframeable_embed_url?: string; } diff --git a/src/schemas/sign-request.generated.ts b/src/schemas/sign-request.generated.ts index dc55923be..9488d8424 100644 --- a/src/schemas/sign-request.generated.ts +++ b/src/schemas/sign-request.generated.ts @@ -10,6 +10,10 @@ export interface SignRequest extends schemas.SignRequestBase { * Example: sign-request */ type?: 'sign-request'; + /** + * List of files to create a signing document from. This is currently limited to ten files. Only the ID and type fields are required for each file. + */ + source_files?: schemas.FileBase[]; /** * Array of signers for the sign request */ @@ -50,7 +54,9 @@ export interface SignRequest extends schemas.SignRequestBase { | 'declined' | 'error_converting' | 'error_sending' - | 'expired'; + | 'expired' + | 'finalizing' + | 'error_finalizing'; /** * List of files that will be signed, which are copies of the original * source files. A new version of these files are created as signers sign @@ -62,8 +68,4 @@ export interface SignRequest extends schemas.SignRequestBase { * Example: 2021-04-26T08:12:13.982Z */ auto_expire_at?: string; - /** - * List of files to create a signing document from. Only the ID and type fields are required for each file. The array will be empty if the `source_files` are deleted. - */ - source_files?: schemas.FileMini[]; } diff --git a/src/schemas/sign-requests.generated.ts b/src/schemas/sign-requests.generated.ts index ca884f6fb..5ab92146a 100644 --- a/src/schemas/sign-requests.generated.ts +++ b/src/schemas/sign-requests.generated.ts @@ -23,5 +23,8 @@ export interface SignRequests { * Example: 1000 */ prev_marker?: number; + /** + * A list of sign requests + */ entries?: schemas.SignRequest[]; } diff --git a/src/schemas/sign-template.generated.ts b/src/schemas/sign-template.generated.ts new file mode 100644 index 000000000..9d0fc30a2 --- /dev/null +++ b/src/schemas/sign-template.generated.ts @@ -0,0 +1,88 @@ +import * as schemas from '.'; +/** + * Box Sign template + * + * A Box Sign template object + */ +export interface SignTemplate { + /** + * object type + * Example: sign-template + */ + type?: 'sign-template'; + /** + * Template identifier. + * Example: 4206996024-14944f75-c34b-478a-95a1-264b1ff80d35 + */ + id?: string; + /** + * The name of the template. + * Example: Official contract + */ + name?: string; + /** + * Subject of signature request email. This is cleaned by sign request. If this field is not passed, a default subject will be used. + * Example: Sign Request from Acme + */ + email_subject?: string; + /** + * 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. + * Example: Hello! Please sign the document below + */ + email_message?: string; + /** + * 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. + * Example: 2 + */ + days_valid?: number; + /** + * The destination folder to place final, signed document and signing + * log. Only `ID` and `type` fields are required. The root folder, + * folder ID `0`, cannot be used. + */ + parent_folder?: schemas.FolderMini; + /** + * List of files to create a signing document from. Only the ID and type fields are required for each file. + */ + source_files?: schemas.FileMini[]; + /** + * Indicates if the template input fields are editable or not. + */ + are_fields_locked?: boolean; + /** + * Indicates if the template document options are editable or not, for example renaming the document. + * Example: true + */ + are_options_locked?: boolean; + /** + * Indicates if the template signers are editable or not. + */ + are_recipients_locked?: boolean; + /** + * Indicates if the template email settings are editable or not. + * Example: true + */ + are_email_settings_locked?: boolean; + /** + * Indicates if the template files are editable or not. This includes deleting or renaming template files. + * Example: true + */ + are_files_locked?: boolean; + /** + * Array of signers for the template. + */ + signers?: schemas.TemplateSigner[]; + /** + * Additional information on which fields are required and which fields are not editable. + */ + additional_info?: object; + /** + * 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. + */ + ready_sign_link?: object; + /** + * Custom branding applied to notifications + * and signature requests. + */ + custom_branding?: object; +} diff --git a/src/schemas/sign-templates.generated.ts b/src/schemas/sign-templates.generated.ts new file mode 100644 index 000000000..a997b71c1 --- /dev/null +++ b/src/schemas/sign-templates.generated.ts @@ -0,0 +1,18 @@ +import * as schemas from '.'; +/** + * Box Sign templates + * + * The part of an API response that describes marker + * based pagination + */ +export interface SignTemplates { + /** + * A list of templates. + */ + entries?: schemas.SignTemplate[]; + /** + * The marker for the start of the previous page of results. + * Example: JV9IRGZmieiBasejOG9yDCRNgd2ymoZIbjsxbJMjIs3kioVii + */ + prev_marker?: string; +} diff --git a/src/schemas/template-signer-input.generated.ts b/src/schemas/template-signer-input.generated.ts new file mode 100644 index 000000000..f7cc125cb --- /dev/null +++ b/src/schemas/template-signer-input.generated.ts @@ -0,0 +1,66 @@ +import * as schemas from '.'; +/** + * Template Signer Input + * + * Input created by a Signer on a Template + */ +export interface TemplateSignerInput extends schemas.SignRequestPrefillTag { + /** + * Type of input + * Example: text + */ + type?: 'signature' | 'date' | 'text' | 'checkbox' | 'radio' | 'dropdown'; + /** + * Content type of input + * Example: text + */ + content_type?: + | 'signature' + | 'initial' + | 'stamp' + | 'date' + | 'checkbox' + | 'text' + | 'full_name' + | 'first_name' + | 'last_name' + | 'company' + | 'title' + | 'email' + | 'attachment' + | 'radio' + | 'dropdown'; + /** + * Whether or not the input is required. + * Example: true + */ + is_required?: boolean; + /** + * Index of page that the input is on. + * Example: 4 + */ + page_index: number; + /** + * Document identifier. + * Example: 123075213-eb54b537-8b25-445e-87c1-5a1c67d8cbd7 + */ + document_id?: string; + /** + * When the input is of the type `dropdown` this values will be filled with all the dropdown options. + * Example: Yes,No,Maybe + */ + dropdown_choices?: string[]; + /** + * When the input is of type `radio` they can be grouped to gather with this identifier. + * Example: da317330-225a-4c72-89ad-0d6dcaaf4df6 + */ + group_id?: string; + /** + * Where the input is located on a page. + */ + coordinates?: object; + /** + * The size of the input. + */ + dimensions?: object; +} diff --git a/src/schemas/template-signer.generated.ts b/src/schemas/template-signer.generated.ts new file mode 100644 index 000000000..0b7833316 --- /dev/null +++ b/src/schemas/template-signer.generated.ts @@ -0,0 +1,36 @@ +import * as schemas from '.'; +/** + * Signer fields for Templates + * + * The schema for a Signer for Templates + */ +export interface TemplateSigner { + inputs?: schemas.TemplateSignerInput[]; + /** + * Email address of the signer + * Example: example@mail.com + */ + email?: string; + /** + * Defines the role of the signer in the signature request. A role of + * `signer` needs to sign the document, a role `approver` + * approves the document and + * a `final_copy_reader` role only + * receives the final signed document and signing log. + * Example: signer + * @default signer + */ + role?: 'signer' | 'approver' | 'final_copy_reader'; + /** + * Used in combination with an embed URL for a sender. + * After the sender signs, they will be + * redirected to the next `in_person` signer. + * Example: true + */ + is_in_person?: boolean; + /** + * Order of the signer + * Example: 2 + */ + order?: number; +} diff --git a/src/schemas/user-base.generated.ts b/src/schemas/user-base.generated.ts index 8b30d0362..7435d34be 100644 --- a/src/schemas/user-base.generated.ts +++ b/src/schemas/user-base.generated.ts @@ -10,7 +10,7 @@ export interface UserBase { * The unique identifier for this user * Example: 11446498 */ - id?: string; + id: string; /** * `user` * Example: user diff --git a/tests/lib/managers/sign-templates-test.js b/tests/lib/managers/sign-templates-test.js new file mode 100644 index 000000000..ae0fbca0b --- /dev/null +++ b/tests/lib/managers/sign-templates-test.js @@ -0,0 +1,86 @@ +/** + * @fileoverview SignTemplates Manager Tests + */ +'use strict'; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ +var sinon = require('sinon'), + mockery = require('mockery'), + leche = require('leche'), + BoxClient = require('../../../lib/box-client'); + +// ------------------------------------------------------------------------------ +// Helpers +// ------------------------------------------------------------------------------ +var sandbox = sinon.createSandbox(), + boxClientFake = leche.fake(BoxClient.prototype), + SignTemplates, + signTemplates, + BASE_PATH = '/sign_templates', + MODULE_FILE_PATH = '../../../lib/managers/sign-templates.generated'; + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +describe('SignTemplates', () => { + before(() => { + // Enable Mockery + mockery.enable({ + useCleanCache: true, + }); + // Register Mocks + mockery.registerAllowable('../util/url-path'); + mockery.registerAllowable(MODULE_FILE_PATH); + }); + + beforeEach(() => { + // Setup File Under Test + SignTemplates = require(MODULE_FILE_PATH); + signTemplates = new SignTemplates(boxClientFake); + }); + + afterEach(() => { + sandbox.verifyAndRestore(); + mockery.resetCache(); + }); + + after(() => { + mockery.deregisterAll(); + mockery.disable(); + }); + + [ + { + name: 'getById', + args: () => [ + { + template_id: '12345', + }, + ], + expectedMethod: 'get', + expectedPath: args => `${BASE_PATH}/${args[0].template_id}`, + expectedParams: () => ({ qs: {} }), + }, + { + name: 'getAll', + args: () => [], + expectedMethod: 'get', + expectedPath: () => BASE_PATH, + expectedParams: () => ({ qs: {} }), + }, + ].forEach(testCase => describe(`${testCase.name}()`, () => it(`should make ${testCase.expectedMethod.toUpperCase()} request when calling ${ + testCase.name + }`, () => { + const args = testCase.args(); + sandbox.stub(boxClientFake, 'wrapWithDefaultHandler').returnsArg(0); + sandbox + .mock(boxClientFake) + .expects(testCase.expectedMethod) + .withArgs(testCase.expectedPath(args), testCase.expectedParams(args)); + signTemplates[testCase.name].apply(signTemplates, args); + })) + ); +});