Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 14 additions & 9 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 33 additions & 0 deletions packages/pieces/community/sign-now/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"extends": [
"../../../../.eslintrc.json"
],
"ignorePatterns": [
"!**/*"
],
"overrides": [
{
"files": [
"*.ts",
"*.tsx",
"*.js",
"*.jsx"
],
"rules": {}
},
{
"files": [
"*.ts",
"*.tsx"
],
"rules": {}
},
{
"files": [
"*.js",
"*.jsx"
],
"rules": {}
}
]
}
18 changes: 18 additions & 0 deletions packages/pieces/community/sign-now/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "@activepieces/piece-sign-now",
"version": "0.0.1",
"type": "commonjs",
"main": "./dist/src/index.js",
"types": "./dist/src/index.d.ts",
"dependencies": {
"@activepieces/pieces-common": "workspace:*",
"@activepieces/pieces-framework": "workspace:*",
"@activepieces/shared": "workspace:*",
"form-data": "4.0.4",
"tslib": "2.6.2"
},
"scripts": {
"build": "tsc -p tsconfig.lib.json && cp package.json dist/",
"lint": "eslint 'src/**/*.ts'"
}
}
44 changes: 44 additions & 0 deletions packages/pieces/community/sign-now/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { createPiece } from '@activepieces/pieces-framework';
import { PieceCategory } from '@activepieces/shared';
import { signNowAuth } from './lib/common/auth';
import { cancelInviteAction } from './lib/actions/cancel-invite';
import { createDocumentFromTemplateAndSendInviteAction } from './lib/actions/create-document-from-template-and-send-invite';
import { createDocumentFromTemplateAndSendRoleBasedInviteAction } from './lib/actions/create-document-from-template-and-send-role-based-invite';
import { createDocumentGroupFromTemplateAndSendInviteAction } from './lib/actions/create-document-group-from-template-and-send-invite';
import { sendInviteAction } from './lib/actions/send-invite';
import { uploadDocumentAction } from './lib/actions/upload-document';
import { uploadDocumentAndExtractFieldsAction } from './lib/actions/upload-document-and-extract-fields';
import { customApiCallAction } from './lib/actions/custom-api-call';
import { documentCompletedTrigger } from './lib/triggers/document-completed';
import { documentDeletedTrigger } from './lib/triggers/document-deleted';
import { newDocumentTrigger } from './lib/triggers/new-document';
import { documentGroupCompletedTrigger } from './lib/triggers/document-group-completed';
import { documentUpdatedTrigger } from './lib/triggers/document-updated';

export const signNow = createPiece({
displayName: 'SignNow',
description:
'eSignature platform for sending, signing, and managing documents.',
auth: signNowAuth,
minimumSupportedRelease: '0.36.1',
logoUrl: 'https://cdn.activepieces.com/pieces/sign-now.png',
categories: [PieceCategory.PRODUCTIVITY],
authors: [],
actions: [
cancelInviteAction,
uploadDocumentAction,
uploadDocumentAndExtractFieldsAction,
sendInviteAction,
createDocumentFromTemplateAndSendInviteAction,
createDocumentFromTemplateAndSendRoleBasedInviteAction,
createDocumentGroupFromTemplateAndSendInviteAction,
customApiCallAction,
],
triggers: [
newDocumentTrigger,
documentUpdatedTrigger,
documentCompletedTrigger,
documentDeletedTrigger,
documentGroupCompletedTrigger,
],
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
import { signNowAuth, getSignNowBearerToken } from '../common/auth';

export const cancelInviteAction = createAction({
auth: signNowAuth,
name: 'cancel_invite',
displayName: 'Cancel Invite to Sign',
description: 'Cancels an invite to sign a document.',
props: {
document_id: Property.ShortText({
displayName: 'Document ID',
description: 'The ID of the document whose invite you want to cancel.',
required: true,
}),
reason: Property.ShortText({
displayName: 'Cancellation Reason',
description: 'The reason for cancelling the invite.',
required: true,
}),
},
async run(context) {
const { document_id, reason } = context.propsValue;
const token = getSignNowBearerToken(context.auth);

const response = await httpClient.sendRequest({
method: HttpMethod.PUT,
url: `https://api.signnow.com/document/${document_id}/fieldinvitecancel`,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: { reason },
});

return response.body;
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
import { signNowAuth, getSignNowBearerToken } from '../common/auth';

export const createDocumentFromTemplateAndSendInviteAction = createAction({
auth: signNowAuth,
name: 'create_document_from_template_and_send_invite',
displayName: 'Create Document From Template & Send Free Form Invite',
description:
'Creates a new document from a template and sends a free form invite to a signer.',
props: {
template_id: Property.ShortText({
displayName: 'Template ID',
description: 'The ID of the template to create the document from.',
required: true,
}),
document_name: Property.ShortText({
displayName: 'Document Name',
description: 'Name for the new document. Defaults to the template name if not provided.',
required: false,
}),
to: Property.ShortText({
displayName: "Signer's Email",
description: "Email address of the signer. A free form invite can be sent to the sender's own email address.",
required: true,
}),
from: Property.ShortText({
displayName: "Sender's Email",
description: 'Must be the email address associated with your SignNow account.',
required: true,
}),
subject: Property.ShortText({
displayName: 'Email Subject',
description: 'Subject line of the invite email sent to the signer.',
required: false,
}),
message: Property.LongText({
displayName: 'Email Message',
description: 'Body message of the invite email sent to the signer.',
required: false,
}),
cc: Property.Array({
displayName: 'CC Recipients',
description: 'Email addresses to CC on the invite.',
required: false,
}),
cc_subject: Property.ShortText({
displayName: 'CC Email Subject',
description: 'Subject line of the email sent to CC recipients.',
required: false,
}),
cc_message: Property.LongText({
displayName: 'CC Email Message',
description: 'Body message of the email sent to CC recipients.',
required: false,
}),
language: Property.StaticDropdown({
displayName: 'Language',
description: 'Language for the signing session and notification emails.',
required: false,
options: {
options: [
{ label: 'English', value: 'en' },
{ label: 'Spanish', value: 'es' },
{ label: 'French', value: 'fr' },
],
},
}),
redirect_uri: Property.ShortText({
displayName: 'Redirect URL',
description: 'URL the signer is redirected to after signing.',
required: false,
}),
close_redirect_uri: Property.ShortText({
displayName: 'Close Redirect URL',
description: 'URL that opens when the signer clicks the Close button.',
required: false,
}),
redirect_target: Property.StaticDropdown({
displayName: 'Redirect Target',
description: 'Whether to open the redirect URL in a new tab or the same tab.',
required: false,
options: {
options: [
{ label: 'New tab', value: 'blank' },
{ label: 'Same tab', value: 'self' },
],
},
}),
},
async run(context) {
const {
template_id,
document_name,
to,
from,
subject,
message,
cc,
cc_subject,
cc_message,
language,
redirect_uri,
close_redirect_uri,
redirect_target,
} = context.propsValue;

const token = getSignNowBearerToken(context.auth);

// Step 1: Create document from template
let document_id: string;
let createdDocumentName: string;

try {
const createResponse = await httpClient.sendRequest<{ id: string; document_name: string }>({
method: HttpMethod.POST,
url: `https://api.signnow.com/template/${template_id}/copy`,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: {
...(document_name ? { document_name } : {}),
},
});
document_id = createResponse.body.id;
createdDocumentName = createResponse.body.document_name;
} catch (e) {
throw new Error(`Failed to create document from template: ${(e as Error).message}`);
}

// Step 2: Send free form invite
const inviteBody: Record<string, unknown> = { to, from };
if (subject) inviteBody['subject'] = subject;
if (message) inviteBody['message'] = message;
if (cc && (cc as string[]).length > 0) inviteBody['cc'] = cc;
if (cc_subject) inviteBody['cc_subject'] = cc_subject;
if (cc_message) inviteBody['cc_message'] = cc_message;
if (language) inviteBody['language'] = language;
if (redirect_uri) inviteBody['redirect_uri'] = redirect_uri;
if (close_redirect_uri) inviteBody['close_redirect_uri'] = close_redirect_uri;
if (redirect_target) inviteBody['redirect_target'] = redirect_target;

try {
const inviteResponse = await httpClient.sendRequest({
method: HttpMethod.POST,
url: `https://api.signnow.com/document/${document_id}/invite`,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: inviteBody,
});

return {
document_id,
document_name: createdDocumentName,
invite: inviteResponse.body,
};
} catch (e) {
throw new Error(
`Document was created (ID: ${document_id}, Name: "${createdDocumentName}") but sending the invite failed: ${(e as Error).message}`
);
}
},
});
Loading
Loading