first commit
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"node": "n8n-nodes-base.ciscoWebex",
|
||||
"nodeVersion": "1.0",
|
||||
"codexVersion": "1.0",
|
||||
"categories": ["Communication"],
|
||||
"resources": {
|
||||
"credentialDocumentation": [
|
||||
{
|
||||
"url": "https://docs.n8n.io/integrations/builtin/credentials/ciscowebex/"
|
||||
}
|
||||
],
|
||||
"primaryDocumentation": [
|
||||
{
|
||||
"url": "https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.ciscowebex/"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,565 @@
|
||||
import moment from 'moment-timezone';
|
||||
import type {
|
||||
IDataObject,
|
||||
IExecuteFunctions,
|
||||
ILoadOptionsFunctions,
|
||||
INodeExecutionData,
|
||||
INodePropertyOptions,
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
} from 'n8n-workflow';
|
||||
import { NodeConnectionTypes } from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
meetingFields,
|
||||
meetingOperations,
|
||||
// meetingTranscriptFields,
|
||||
// meetingTranscriptOperations,
|
||||
messageFields,
|
||||
messageOperations,
|
||||
} from './descriptions';
|
||||
import { getAttachments, webexApiRequest, webexApiRequestAllItems } from './GenericFunctions';
|
||||
|
||||
export class CiscoWebex implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'Webex by Cisco',
|
||||
name: 'ciscoWebex',
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-icon-not-svg
|
||||
icon: 'file:ciscoWebex.png',
|
||||
group: ['transform'],
|
||||
version: 1,
|
||||
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
||||
description: 'Consume the Cisco Webex API',
|
||||
schemaPath: 'Cisco/Webex',
|
||||
defaults: {
|
||||
name: 'Webex by Cisco',
|
||||
},
|
||||
usableAsTool: true,
|
||||
credentials: [
|
||||
{
|
||||
name: 'ciscoWebexOAuth2Api',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
inputs: [NodeConnectionTypes.Main],
|
||||
outputs: [NodeConnectionTypes.Main],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Resource',
|
||||
name: 'resource',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
options: [
|
||||
{
|
||||
name: 'Meeting',
|
||||
value: 'meeting',
|
||||
},
|
||||
// {
|
||||
// name: 'Meeeting Transcript',
|
||||
// value: 'meetingTranscript',
|
||||
// },
|
||||
{
|
||||
name: 'Message',
|
||||
value: 'message',
|
||||
},
|
||||
],
|
||||
default: 'message',
|
||||
},
|
||||
...meetingOperations,
|
||||
...meetingFields,
|
||||
// ...meetingTranscriptOperations,
|
||||
// ...meetingTranscriptFields,
|
||||
...messageOperations,
|
||||
...messageFields,
|
||||
],
|
||||
};
|
||||
|
||||
methods = {
|
||||
loadOptions: {
|
||||
async getRooms(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const rooms = await webexApiRequestAllItems.call(this, 'items', 'GET', '/rooms');
|
||||
for (const room of rooms) {
|
||||
returnData.push({
|
||||
name: room.title,
|
||||
value: room.id,
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
async getSites(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const sites = await webexApiRequestAllItems.call(
|
||||
this,
|
||||
'sites',
|
||||
'GET',
|
||||
'/meetingPreferences/sites',
|
||||
);
|
||||
for (const site of sites) {
|
||||
returnData.push({
|
||||
name: site.siteUrl,
|
||||
value: site.siteUrl,
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
const items = this.getInputData();
|
||||
const returnData: INodeExecutionData[] = [];
|
||||
const timezone = this.getTimezone();
|
||||
const resource = this.getNodeParameter('resource', 0);
|
||||
const operation = this.getNodeParameter('operation', 0);
|
||||
|
||||
let responseData;
|
||||
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
try {
|
||||
if (resource === 'message') {
|
||||
// **********************************************************************
|
||||
// message
|
||||
// **********************************************************************
|
||||
|
||||
if (operation === 'create') {
|
||||
// ----------------------------------------
|
||||
// message: create
|
||||
// ----------------------------------------
|
||||
|
||||
// https://developer.webex.com/docs/api/v1/messages/create-a-message
|
||||
const destination = this.getNodeParameter('destination', i);
|
||||
const file = this.getNodeParameter(
|
||||
'additionalFields.fileUi.fileValue',
|
||||
i,
|
||||
{},
|
||||
) as IDataObject;
|
||||
const markdown = this.getNodeParameter('additionalFields.markdown', i, '') as boolean;
|
||||
const body = {} as IDataObject;
|
||||
if (destination === 'room') {
|
||||
body.roomId = this.getNodeParameter('roomId', i);
|
||||
}
|
||||
|
||||
if (destination === 'person') {
|
||||
const specifyPersonBy = this.getNodeParameter('specifyPersonBy', 0) as string;
|
||||
if (specifyPersonBy === 'id') {
|
||||
body.toPersonId = this.getNodeParameter('toPersonId', i);
|
||||
} else {
|
||||
body.toPersonEmail = this.getNodeParameter('toPersonEmail', i);
|
||||
}
|
||||
}
|
||||
|
||||
if (markdown) {
|
||||
body.markdown = markdown;
|
||||
}
|
||||
|
||||
body.text = this.getNodeParameter('text', i);
|
||||
|
||||
body.attachments = getAttachments(
|
||||
this.getNodeParameter(
|
||||
'additionalFields.attachmentsUi.attachmentValues',
|
||||
i,
|
||||
[],
|
||||
) as IDataObject[],
|
||||
);
|
||||
|
||||
if (Object.keys(file).length) {
|
||||
const isBinaryData = file.fileLocation === 'binaryData' ? true : false;
|
||||
|
||||
if (isBinaryData) {
|
||||
const binaryPropertyName = file.binaryPropertyName as string;
|
||||
const binaryData = this.helpers.assertBinaryData(i, binaryPropertyName);
|
||||
const binaryDataBuffer = await this.helpers.getBinaryDataBuffer(
|
||||
i,
|
||||
binaryPropertyName,
|
||||
);
|
||||
|
||||
const formData = {
|
||||
files: {
|
||||
value: binaryDataBuffer,
|
||||
options: {
|
||||
filename: binaryData.fileName,
|
||||
contentType: binaryData.mimeType,
|
||||
},
|
||||
},
|
||||
};
|
||||
Object.assign(body, formData);
|
||||
} else {
|
||||
const url = file.url as string;
|
||||
Object.assign(body, { files: url });
|
||||
}
|
||||
}
|
||||
|
||||
if (file.fileLocation === 'binaryData') {
|
||||
responseData = await webexApiRequest.call(
|
||||
this,
|
||||
'POST',
|
||||
'/messages',
|
||||
{},
|
||||
{},
|
||||
undefined,
|
||||
{ formData: body },
|
||||
);
|
||||
} else {
|
||||
responseData = await webexApiRequest.call(this, 'POST', '/messages', body);
|
||||
}
|
||||
responseData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(responseData as IDataObject[]),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
} else if (operation === 'delete') {
|
||||
// ----------------------------------------
|
||||
// message: delete
|
||||
// ----------------------------------------
|
||||
|
||||
// https://developer.webex.com/docs/api/v1/messages/delete-a-message
|
||||
const messageId = this.getNodeParameter('messageId', i);
|
||||
|
||||
const endpoint = `/messages/${messageId}`;
|
||||
responseData = await webexApiRequest.call(this, 'DELETE', endpoint);
|
||||
responseData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray({ success: true }),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
} else if (operation === 'get') {
|
||||
// ----------------------------------------
|
||||
// message: get
|
||||
// ----------------------------------------
|
||||
|
||||
// https://developer.webex.com/docs/api/v1/messages/get-message-details
|
||||
const messageId = this.getNodeParameter('messageId', i);
|
||||
|
||||
const endpoint = `/messages/${messageId}`;
|
||||
responseData = await webexApiRequest.call(this, 'GET', endpoint);
|
||||
responseData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(responseData as IDataObject[]),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
} else if (operation === 'getAll') {
|
||||
// ----------------------------------------
|
||||
// message: getAll
|
||||
// ----------------------------------------
|
||||
|
||||
// https://developer.webex.com/docs/api/v1/messages/list-messages
|
||||
const qs: IDataObject = {
|
||||
roomId: this.getNodeParameter('roomId', i),
|
||||
};
|
||||
const filters = this.getNodeParameter('filters', i);
|
||||
const returnAll = this.getNodeParameter('returnAll', i);
|
||||
|
||||
if (Object.keys(filters).length) {
|
||||
Object.assign(qs, filters);
|
||||
}
|
||||
|
||||
if (returnAll) {
|
||||
responseData = await webexApiRequestAllItems.call(
|
||||
this,
|
||||
'items',
|
||||
'GET',
|
||||
'/messages',
|
||||
{},
|
||||
qs,
|
||||
);
|
||||
} else {
|
||||
qs.max = this.getNodeParameter('limit', i);
|
||||
responseData = await webexApiRequest.call(this, 'GET', '/messages', {}, qs);
|
||||
responseData = responseData.items;
|
||||
}
|
||||
responseData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(responseData.items as IDataObject[]),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
} else if (operation === 'update') {
|
||||
// ----------------------------------------
|
||||
// message: update
|
||||
// ----------------------------------------
|
||||
|
||||
// https://developer.webex.com/docs/api/v1/messages/edit-a-message
|
||||
const messageId = this.getNodeParameter('messageId', i) as string;
|
||||
const markdown = this.getNodeParameter('markdown', i) as boolean;
|
||||
|
||||
const endpoint = `/messages/${messageId}`;
|
||||
|
||||
responseData = await webexApiRequest.call(this, 'GET', endpoint);
|
||||
|
||||
const body = {
|
||||
roomId: responseData.roomId,
|
||||
} as IDataObject;
|
||||
|
||||
if (markdown) {
|
||||
body.markdown = this.getNodeParameter('markdownText', i);
|
||||
} else {
|
||||
body.text = this.getNodeParameter('text', i);
|
||||
}
|
||||
|
||||
responseData = await webexApiRequest.call(this, 'PUT', endpoint, body);
|
||||
responseData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(responseData as IDataObject[]),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (resource === 'meeting') {
|
||||
if (operation === 'create') {
|
||||
const title = this.getNodeParameter('title', i) as string;
|
||||
const start = this.getNodeParameter('start', i) as string;
|
||||
const end = this.getNodeParameter('end', i) as string;
|
||||
const invitees = this.getNodeParameter(
|
||||
'additionalFields.inviteesUi.inviteeValues',
|
||||
i,
|
||||
[],
|
||||
) as IDataObject[];
|
||||
const additionalFields = this.getNodeParameter('additionalFields', i);
|
||||
|
||||
const body: IDataObject = {
|
||||
title,
|
||||
start: moment.tz(start, timezone).format(),
|
||||
end: moment.tz(end, timezone).format(),
|
||||
...additionalFields,
|
||||
};
|
||||
|
||||
if (body.requireRegistrationInfo) {
|
||||
body.registration = (body.requireRegistrationInfo as string[]).reduce(
|
||||
(obj, value) => Object.assign(obj, { [`${value}`]: true }),
|
||||
{},
|
||||
);
|
||||
delete body.requireRegistrationInfo;
|
||||
}
|
||||
|
||||
if (invitees) {
|
||||
body.invitees = invitees;
|
||||
delete body.inviteesUi;
|
||||
}
|
||||
|
||||
responseData = await webexApiRequest.call(this, 'POST', '/meetings', body);
|
||||
responseData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(responseData as IDataObject[]),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
}
|
||||
|
||||
if (operation === 'delete') {
|
||||
const meetingId = this.getNodeParameter('meetingId', i) as string;
|
||||
const options = this.getNodeParameter('options', i);
|
||||
|
||||
const qs: IDataObject = {
|
||||
...options,
|
||||
};
|
||||
|
||||
responseData = await webexApiRequest.call(
|
||||
this,
|
||||
'DELETE',
|
||||
`/meetings/${meetingId}`,
|
||||
{},
|
||||
qs,
|
||||
);
|
||||
responseData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray({ success: true }),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
}
|
||||
|
||||
if (operation === 'get') {
|
||||
const meetingId = this.getNodeParameter('meetingId', i) as string;
|
||||
const options = this.getNodeParameter('options', i);
|
||||
let headers = {};
|
||||
|
||||
const qs: IDataObject = {
|
||||
...options,
|
||||
};
|
||||
|
||||
if (options.passsword) {
|
||||
headers = {
|
||||
passsword: options.passsword,
|
||||
};
|
||||
}
|
||||
|
||||
responseData = await webexApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
`/meetings/${meetingId}`,
|
||||
{},
|
||||
qs,
|
||||
undefined,
|
||||
{ headers },
|
||||
);
|
||||
responseData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(responseData as IDataObject[]),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
}
|
||||
|
||||
if (operation === 'getAll') {
|
||||
const filters = this.getNodeParameter('filters', i);
|
||||
const returnAll = this.getNodeParameter('returnAll', i);
|
||||
|
||||
const qs: IDataObject = {
|
||||
...filters,
|
||||
};
|
||||
|
||||
if (qs.from) {
|
||||
qs.from = moment(qs.from as string)
|
||||
.utc(true)
|
||||
.format();
|
||||
}
|
||||
|
||||
if (qs.to) {
|
||||
qs.to = moment(qs.to as string)
|
||||
.utc(true)
|
||||
.format();
|
||||
}
|
||||
|
||||
if (returnAll) {
|
||||
responseData = await webexApiRequestAllItems.call(
|
||||
this,
|
||||
'items',
|
||||
'GET',
|
||||
'/meetings',
|
||||
{},
|
||||
qs,
|
||||
);
|
||||
} else {
|
||||
qs.max = this.getNodeParameter('limit', i);
|
||||
responseData = await webexApiRequest.call(this, 'GET', '/meetings', {}, qs);
|
||||
responseData = responseData.items;
|
||||
}
|
||||
responseData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(responseData as IDataObject[]),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
}
|
||||
|
||||
if (operation === 'update') {
|
||||
const meetingId = this.getNodeParameter('meetingId', i) as string;
|
||||
const invitees = this.getNodeParameter(
|
||||
'updateFields.inviteesUi.inviteeValues',
|
||||
i,
|
||||
[],
|
||||
) as IDataObject[];
|
||||
const updateFields = this.getNodeParameter('updateFields', i);
|
||||
|
||||
const { title, password, start, end } = await webexApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
`/meetings/${meetingId}`,
|
||||
);
|
||||
|
||||
const body: IDataObject = {
|
||||
...updateFields,
|
||||
};
|
||||
|
||||
if (body.requireRegistrationInfo) {
|
||||
body.registration = (body.requireRegistrationInfo as string[]).reduce(
|
||||
(obj, value) => Object.assign(obj, { [`${value}`]: true }),
|
||||
{},
|
||||
);
|
||||
delete body.requireRegistrationInfo;
|
||||
}
|
||||
|
||||
if (invitees.length) {
|
||||
body.invitees = invitees;
|
||||
}
|
||||
|
||||
if (body.start) {
|
||||
body.start = moment.tz(updateFields.start, timezone).format();
|
||||
} else {
|
||||
body.start = start;
|
||||
}
|
||||
|
||||
if (body.end) {
|
||||
body.end = moment.tz(updateFields.end, timezone).format();
|
||||
} else {
|
||||
body.end = end;
|
||||
}
|
||||
|
||||
if (!body.title) {
|
||||
body.title = title;
|
||||
}
|
||||
|
||||
if (!body.password) {
|
||||
body.password = password;
|
||||
}
|
||||
|
||||
responseData = await webexApiRequest.call(this, 'PUT', `/meetings/${meetingId}`, body);
|
||||
responseData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(responseData as IDataObject[]),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
returnData.push(...(responseData as INodeExecutionData[]));
|
||||
} catch (error) {
|
||||
if (this.continueOnFail()) {
|
||||
returnData.push({ error: error.toString(), json: {}, itemIndex: i });
|
||||
continue;
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// if (resource === 'meetingTranscript') {
|
||||
|
||||
// if (operation === 'download') {
|
||||
// for (let i = 0; i < items.length; i++) {
|
||||
// const transcriptId = this.getNodeParameter('transcriptId', i) as string;
|
||||
// const binaryPropertyName = this.getNodeParameter('binaryPropertyName', i);
|
||||
// const meetingId = this.getNodeParameter('meetingId', i) as string;
|
||||
// const options = this.getNodeParameter('options', i);
|
||||
|
||||
// const qs: IDataObject = {
|
||||
// meetingId,
|
||||
// ...options,
|
||||
// };
|
||||
// const transcription = await webexApiRequest.call(this, 'GET', `/meetingTranscripts/${transcriptId}/download`, {}, qs);
|
||||
|
||||
// responseData = {
|
||||
// json: {},
|
||||
// binary: {
|
||||
// [binaryPropertyName]: {
|
||||
// data: Buffer.from(transcription, BINARY_ENCODING),
|
||||
// //contentType:
|
||||
// //FILE
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (operation === 'getAll') {
|
||||
// for (let i = 0; i < items.length; i++) {
|
||||
// try {
|
||||
// const meetingId = this.getNodeParameter('meetingId', i) as string;
|
||||
// const filters = this.getNodeParameter('filters', i);
|
||||
// const returnAll = this.getNodeParameter('returnAll', i);
|
||||
|
||||
// const qs: IDataObject = {
|
||||
// meetingId,
|
||||
// ...filters,
|
||||
// };
|
||||
|
||||
// if (returnAll === true) {
|
||||
// responseData = await webexApiRequestAllItems.call(this, 'items', 'GET', '/meetingTranscripts', {}, qs);
|
||||
// returnData.push(...responseData);
|
||||
// } else {
|
||||
// qs.max = this.getNodeParameter('limit', i);
|
||||
// responseData = await webexApiRequest.call(this, 'GET', '/meetingTranscripts', {}, qs);
|
||||
// returnData.push(...responseData.items);
|
||||
// }
|
||||
// } catch (error) {
|
||||
// if (this.continueOnFail()) {
|
||||
// returnData.push({
|
||||
// error: error.message,
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
return [returnData];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"node": "n8n-nodes-base.ciscoWebexTrigger",
|
||||
"nodeVersion": "1.0",
|
||||
"codexVersion": "1.0",
|
||||
"categories": ["Communication"],
|
||||
"resources": {
|
||||
"credentialDocumentation": [
|
||||
{
|
||||
"url": "https://docs.n8n.io/integrations/builtin/credentials/ciscowebex/"
|
||||
}
|
||||
],
|
||||
"primaryDocumentation": [
|
||||
{
|
||||
"url": "https://docs.n8n.io/integrations/builtin/trigger-nodes/n8n-nodes-base.ciscowebextrigger/"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,605 @@
|
||||
import { createHmac } from 'crypto';
|
||||
import type {
|
||||
IHookFunctions,
|
||||
IWebhookFunctions,
|
||||
IDataObject,
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
IWebhookResponseData,
|
||||
} from 'n8n-workflow';
|
||||
import { NodeConnectionTypes } from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
getAutomaticSecret,
|
||||
getEvents,
|
||||
mapResource,
|
||||
webexApiRequest,
|
||||
webexApiRequestAllItems,
|
||||
} from './GenericFunctions';
|
||||
|
||||
export class CiscoWebexTrigger implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'Webex by Cisco Trigger',
|
||||
name: 'ciscoWebexTrigger',
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-icon-not-svg
|
||||
icon: 'file:ciscoWebex.png',
|
||||
group: ['trigger'],
|
||||
version: 1,
|
||||
subtitle: '={{$parameter["resource"] + ":" + $parameter["event"]}}',
|
||||
description: 'Starts the workflow when Cisco Webex events occur.',
|
||||
defaults: {
|
||||
name: 'Webex by Cisco Trigger',
|
||||
},
|
||||
inputs: [],
|
||||
outputs: [NodeConnectionTypes.Main],
|
||||
credentials: [
|
||||
{
|
||||
name: 'ciscoWebexOAuth2Api',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
webhooks: [
|
||||
{
|
||||
name: 'default',
|
||||
httpMethod: 'POST',
|
||||
responseMode: 'onReceived',
|
||||
path: 'webhook',
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Resource',
|
||||
name: 'resource',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
options: [
|
||||
{
|
||||
name: '[All]',
|
||||
value: 'all',
|
||||
},
|
||||
{
|
||||
name: 'Attachment Action',
|
||||
value: 'attachmentAction',
|
||||
},
|
||||
{
|
||||
name: 'Meeting',
|
||||
value: 'meeting',
|
||||
},
|
||||
{
|
||||
name: 'Membership',
|
||||
value: 'membership',
|
||||
},
|
||||
{
|
||||
name: 'Message',
|
||||
value: 'message',
|
||||
},
|
||||
// {
|
||||
// name: 'Telephony Call',
|
||||
// value: 'telephonyCall',
|
||||
// },
|
||||
{
|
||||
name: 'Recording',
|
||||
value: 'recording',
|
||||
},
|
||||
{
|
||||
name: 'Room',
|
||||
value: 'room',
|
||||
},
|
||||
],
|
||||
default: 'meeting',
|
||||
required: true,
|
||||
},
|
||||
...getEvents(),
|
||||
{
|
||||
displayName: 'Resolve Data',
|
||||
name: 'resolveData',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['attachmentAction'],
|
||||
},
|
||||
},
|
||||
default: true,
|
||||
// eslint-disable-next-line n8n-nodes-base/node-param-description-boolean-without-whether
|
||||
description:
|
||||
'By default the response only contain a reference to the data the user inputed. If this option gets activated, it will resolve the data automatically.',
|
||||
},
|
||||
{
|
||||
displayName: 'Filters',
|
||||
name: 'filters',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Filter',
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Has Files',
|
||||
name: 'hasFiles',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/resource': ['message'],
|
||||
'/event': ['created', 'deleted'],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'Whether to limit to messages which contain file content attachments',
|
||||
},
|
||||
{
|
||||
displayName: 'Is Locked',
|
||||
name: 'isLocked',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/resource': ['room'],
|
||||
'/event': ['created', 'updated'],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'Whether to limit to rooms that are locked',
|
||||
},
|
||||
{
|
||||
displayName: 'Is Moderator',
|
||||
name: 'isModerator',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/resource': ['membership'],
|
||||
'/event': ['created', 'updated', 'deleted'],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'Whether to limit to moderators of a room',
|
||||
},
|
||||
{
|
||||
displayName: 'Mentioned People',
|
||||
name: 'mentionedPeople',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/resource': ['message'],
|
||||
'/event': ['created', 'deleted'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description:
|
||||
'Limit to messages which contain these mentioned people, by person ID; accepts me as a shorthand for your own person ID; separate multiple values with commas',
|
||||
},
|
||||
{
|
||||
displayName: 'Message ID',
|
||||
name: 'messageId',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/resource': ['attachmentAction'],
|
||||
'/event': ['created'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'Limit to a particular message, by ID',
|
||||
},
|
||||
{
|
||||
displayName: 'Owned By',
|
||||
name: 'ownedBy',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/resource': ['meeting'],
|
||||
},
|
||||
},
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Person Email',
|
||||
name: 'personEmail',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/resource': ['membership'],
|
||||
'/event': ['created', 'updated', 'deleted'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'Limit to a particular person, by email',
|
||||
},
|
||||
{
|
||||
displayName: 'Person Email',
|
||||
name: 'personEmail',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/resource': ['message'],
|
||||
'/event': ['created', 'deleted'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'Limit to a particular person, by email',
|
||||
},
|
||||
{
|
||||
displayName: 'Person ID',
|
||||
name: 'personId',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/resource': ['attachmentAction'],
|
||||
'/event': ['created'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'Limit to a particular person, by ID',
|
||||
},
|
||||
{
|
||||
displayName: 'Person ID',
|
||||
name: 'personId',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/resource': ['membership'],
|
||||
'/event': ['created', 'updated', 'deleted'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'Limit to a particular person, by ID',
|
||||
},
|
||||
{
|
||||
displayName: 'Person ID',
|
||||
name: 'personId',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/resource': ['message'],
|
||||
'/event': ['created', 'deleted'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'Limit to a particular person, by ID',
|
||||
},
|
||||
|
||||
{
|
||||
displayName: 'Room ID',
|
||||
name: 'roomId',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/resource': ['attachmentAction'],
|
||||
'/event': ['created'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'Limit to a particular room, by ID',
|
||||
},
|
||||
{
|
||||
displayName: 'Room ID',
|
||||
name: 'roomId',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/resource': ['membership'],
|
||||
'/event': ['created', 'updated', 'deleted'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'Limit to a particular room, by ID',
|
||||
},
|
||||
{
|
||||
displayName: 'Room ID',
|
||||
name: 'roomId',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/resource': ['message'],
|
||||
'/event': ['created', 'updated'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'Limit to a particular room, by ID',
|
||||
},
|
||||
{
|
||||
displayName: 'Room Type',
|
||||
name: 'roomType',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Direct',
|
||||
value: 'direct',
|
||||
},
|
||||
{
|
||||
name: 'Group',
|
||||
value: 'group',
|
||||
},
|
||||
],
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/resource': ['message'],
|
||||
'/event': ['created', 'deleted'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'Limit to a particular room type',
|
||||
},
|
||||
{
|
||||
displayName: 'Type',
|
||||
name: 'type',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Direct',
|
||||
value: 'direct',
|
||||
},
|
||||
{
|
||||
name: 'Group',
|
||||
value: 'group',
|
||||
},
|
||||
],
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/resource': ['room'],
|
||||
'/event': ['created', 'updated'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'Limit to a particular room type',
|
||||
},
|
||||
// {
|
||||
// displayName: 'Call Type',
|
||||
// name: 'callType',
|
||||
// type: 'options',
|
||||
// options: [
|
||||
// {
|
||||
// name: 'Emergency',
|
||||
// value: 'emergency',
|
||||
// },
|
||||
// {
|
||||
// name: 'External',
|
||||
// value: 'external',
|
||||
// },
|
||||
// {
|
||||
// name: 'Location',
|
||||
// value: 'location',
|
||||
// },
|
||||
// {
|
||||
// name: 'Disconnected',
|
||||
// value: 'disconnected',
|
||||
// },
|
||||
// {
|
||||
// name: 'Organization',
|
||||
// value: 'organization',
|
||||
// },
|
||||
// {
|
||||
// name: 'Other',
|
||||
// value: 'other',
|
||||
// },
|
||||
// {
|
||||
// name: 'Repair',
|
||||
// value: 'repair',
|
||||
// },
|
||||
// ],
|
||||
// displayOptions: {
|
||||
// show: {
|
||||
// '/resource': [
|
||||
// 'telephonyCall',
|
||||
// ],
|
||||
// '/event': [
|
||||
// 'created',
|
||||
// 'deleted',
|
||||
// 'updated',
|
||||
// ],
|
||||
// },
|
||||
// },
|
||||
// default: '',
|
||||
// description: `Limit to a particular call type`,
|
||||
// },
|
||||
// {
|
||||
// displayName: 'Person ID',
|
||||
// name: 'personId',
|
||||
// type: 'string',
|
||||
// displayOptions: {
|
||||
// show: {
|
||||
// '/resource': [
|
||||
// 'telephonyCall',
|
||||
// ],
|
||||
// '/event': [
|
||||
// 'created',
|
||||
// 'deleted',
|
||||
// 'updated',
|
||||
// ],
|
||||
// },
|
||||
// },
|
||||
// default: '',
|
||||
// description: 'Limit to a particular person, by ID',
|
||||
// },
|
||||
// {
|
||||
// displayName: 'Personality',
|
||||
// name: 'personality',
|
||||
// type: 'options',
|
||||
// options: [
|
||||
// {
|
||||
// name: 'Click To Dial',
|
||||
// value: 'clickToDial',
|
||||
// },
|
||||
// {
|
||||
// name: 'Originator',
|
||||
// value: 'originator',
|
||||
// },
|
||||
// {
|
||||
// name: 'Terminator',
|
||||
// value: 'terminator',
|
||||
// },
|
||||
// ],
|
||||
// displayOptions: {
|
||||
// show: {
|
||||
// '/resource': [
|
||||
// 'telephonyCall',
|
||||
// ],
|
||||
// '/event': [
|
||||
// 'created',
|
||||
// 'deleted',
|
||||
// 'updated',
|
||||
// ],
|
||||
// },
|
||||
// },
|
||||
// default: '',
|
||||
// description: `Limit to a particular call personality`,
|
||||
// },
|
||||
// {
|
||||
// displayName: 'State',
|
||||
// name: 'state',
|
||||
// type: 'options',
|
||||
// options: [
|
||||
// {
|
||||
// name: 'Alerting',
|
||||
// value: 'alerting',
|
||||
// },
|
||||
// {
|
||||
// name: 'Connected',
|
||||
// value: 'connected',
|
||||
// },
|
||||
// {
|
||||
// name: 'Connecting',
|
||||
// value: 'connecting',
|
||||
// },
|
||||
// {
|
||||
// name: 'Disconnected',
|
||||
// value: 'disconnected',
|
||||
// },
|
||||
// {
|
||||
// name: 'Held',
|
||||
// value: 'held',
|
||||
// },
|
||||
// {
|
||||
// name: 'Remote Held',
|
||||
// value: 'remoteHeld',
|
||||
// },
|
||||
// ],
|
||||
// displayOptions: {
|
||||
// show: {
|
||||
// '/resource': [
|
||||
// 'telephonyCall',
|
||||
// ],
|
||||
// '/event': [
|
||||
// 'created',
|
||||
// 'deleted',
|
||||
// 'updated',
|
||||
// ],
|
||||
// },
|
||||
// },
|
||||
// default: '',
|
||||
// description: `Limit to a particular call state`,
|
||||
// },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
webhookMethods = {
|
||||
default: {
|
||||
async checkExists(this: IHookFunctions): Promise<boolean> {
|
||||
const webhookUrl = this.getNodeWebhookUrl('default');
|
||||
const webhookData = this.getWorkflowStaticData('node');
|
||||
const resource = this.getNodeParameter('resource') as string;
|
||||
const event = this.getNodeParameter('event') as string;
|
||||
|
||||
// Check all the webhooks which exist already if it is identical to the
|
||||
// one that is supposed to get created.
|
||||
const data = await webexApiRequestAllItems.call(this, 'items', 'GET', '/webhooks');
|
||||
for (const webhook of data) {
|
||||
if (
|
||||
webhook.url === webhookUrl &&
|
||||
webhook.resource === mapResource(resource) &&
|
||||
webhook.event === event &&
|
||||
webhook.status === 'active'
|
||||
) {
|
||||
webhookData.webhookId = webhook.id as string;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
async create(this: IHookFunctions): Promise<boolean> {
|
||||
const webhookData = this.getWorkflowStaticData('node');
|
||||
const webhookUrl = this.getNodeWebhookUrl('default');
|
||||
const event = this.getNodeParameter('event') as string;
|
||||
const resource = this.getNodeParameter('resource') as string;
|
||||
const filters = this.getNodeParameter('filters', {}) as IDataObject;
|
||||
const credentials = await this.getCredentials('ciscoWebexOAuth2Api');
|
||||
const secret = getAutomaticSecret(credentials);
|
||||
const filter = [];
|
||||
for (const key of Object.keys(filters)) {
|
||||
if (key !== 'ownedBy') {
|
||||
filter.push(`${key}=${filters[key]}`);
|
||||
}
|
||||
}
|
||||
const endpoint = '/webhooks';
|
||||
|
||||
const body: IDataObject = {
|
||||
name: `n8n-webhook:${webhookUrl}`,
|
||||
targetUrl: webhookUrl,
|
||||
event,
|
||||
resource: mapResource(resource),
|
||||
};
|
||||
|
||||
if (filters.ownedBy) {
|
||||
body.ownedBy = filters.ownedBy as string;
|
||||
}
|
||||
|
||||
body.secret = secret;
|
||||
|
||||
if (filter.length) {
|
||||
body.filter = filter.join('&');
|
||||
}
|
||||
|
||||
const responseData = await webexApiRequest.call(this, 'POST', endpoint, body);
|
||||
if (responseData.id === undefined) {
|
||||
// Required data is missing so was not successful
|
||||
return false;
|
||||
}
|
||||
|
||||
webhookData.webhookId = responseData.id as string;
|
||||
webhookData.secret = secret;
|
||||
return true;
|
||||
},
|
||||
async delete(this: IHookFunctions): Promise<boolean> {
|
||||
const webhookData = this.getWorkflowStaticData('node');
|
||||
if (webhookData.webhookId !== undefined) {
|
||||
const endpoint = `/webhooks/${webhookData.webhookId}`;
|
||||
try {
|
||||
await webexApiRequest.call(this, 'DELETE', endpoint);
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove from the static workflow data so that it is clear
|
||||
// that no webhooks are registered anymore
|
||||
delete webhookData.webhookId;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
|
||||
let bodyData = this.getBodyData();
|
||||
const webhookData = this.getWorkflowStaticData('node');
|
||||
const headers = this.getHeaderData() as IDataObject;
|
||||
const req = this.getRequestObject();
|
||||
const resolveData = this.getNodeParameter('resolveData', false) as boolean;
|
||||
|
||||
//@ts-ignore
|
||||
const computedSignature = createHmac('sha1', webhookData.secret)
|
||||
.update(req.rawBody)
|
||||
.digest('hex');
|
||||
if (headers['x-spark-signature'] !== computedSignature) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (resolveData) {
|
||||
const {
|
||||
data: { id },
|
||||
} = bodyData as { data: { id: string } };
|
||||
bodyData = await webexApiRequest.call(this, 'GET', `/attachment/actions/${id}`);
|
||||
}
|
||||
|
||||
return {
|
||||
workflowData: [this.helpers.returnJsonArray(bodyData)],
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,632 @@
|
||||
import { createHash } from 'crypto';
|
||||
import upperFirst from 'lodash/upperFirst';
|
||||
import type {
|
||||
ICredentialDataDecryptedObject,
|
||||
IDataObject,
|
||||
IExecuteFunctions,
|
||||
IHookFunctions,
|
||||
IHttpRequestMethods,
|
||||
ILoadOptionsFunctions,
|
||||
INodeProperties,
|
||||
IRequestOptions,
|
||||
IWebhookFunctions,
|
||||
JsonObject,
|
||||
} from 'n8n-workflow';
|
||||
import { NodeApiError } from 'n8n-workflow';
|
||||
|
||||
export async function webexApiRequest(
|
||||
this: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions | IWebhookFunctions,
|
||||
method: IHttpRequestMethods,
|
||||
resource: string,
|
||||
|
||||
body: any = {},
|
||||
qs: IDataObject = {},
|
||||
uri?: string,
|
||||
option: IDataObject = {},
|
||||
): Promise<any> {
|
||||
let options: IRequestOptions = {
|
||||
method,
|
||||
body,
|
||||
qs,
|
||||
uri: uri || `https://webexapis.com/v1${resource}`,
|
||||
json: true,
|
||||
};
|
||||
try {
|
||||
if (Object.keys(option).length !== 0) {
|
||||
options = Object.assign({}, options, option);
|
||||
}
|
||||
if (Object.keys(body as IDataObject).length === 0) {
|
||||
delete options.body;
|
||||
}
|
||||
if (Object.keys(qs).length === 0) {
|
||||
delete options.qs;
|
||||
}
|
||||
return await this.helpers.requestOAuth2.call(this, 'ciscoWebexOAuth2Api', options, {
|
||||
tokenType: 'Bearer',
|
||||
});
|
||||
} catch (error) {
|
||||
throw new NodeApiError(this.getNode(), error as JsonObject);
|
||||
}
|
||||
}
|
||||
|
||||
export async function webexApiRequestAllItems(
|
||||
this: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions,
|
||||
propertyName: string,
|
||||
method: IHttpRequestMethods,
|
||||
endpoint: string,
|
||||
|
||||
body: any = {},
|
||||
query: IDataObject = {},
|
||||
options: IDataObject = {},
|
||||
): Promise<any> {
|
||||
const returnData: IDataObject[] = [];
|
||||
|
||||
let responseData;
|
||||
let uri: string | undefined;
|
||||
query.max = 100;
|
||||
do {
|
||||
responseData = await webexApiRequest.call(this, method, endpoint, body, query, uri, {
|
||||
resolveWithFullResponse: true,
|
||||
...options,
|
||||
});
|
||||
if (responseData.headers.link) {
|
||||
uri = responseData.headers.link.split(';')[0].replace('<', '').replace('>', '');
|
||||
}
|
||||
returnData.push.apply(returnData, responseData.body[propertyName] as IDataObject[]);
|
||||
} while (responseData.headers.link?.includes('rel="next"'));
|
||||
return returnData;
|
||||
}
|
||||
|
||||
export function getEvents() {
|
||||
const resourceEvents: { [key: string]: string[] } = {
|
||||
attachmentAction: ['created', 'deleted', 'updated', '*'],
|
||||
membership: ['created', 'deleted', 'updated', '*'],
|
||||
message: ['created', 'deleted', 'updated', '*'],
|
||||
room: ['created', 'deleted', 'updated', '*'],
|
||||
meeting: ['created', 'deleted', 'updated', 'started', 'ended', '*'],
|
||||
recording: ['created', 'deleted', 'updated', '*'],
|
||||
telephonyCall: ['created', 'deleted', 'updated'],
|
||||
'*': ['created', 'updated', 'deleted', '*'],
|
||||
};
|
||||
|
||||
const elements: INodeProperties[] = [];
|
||||
|
||||
for (const resource of Object.keys(resourceEvents)) {
|
||||
elements.push({
|
||||
displayName: 'Event',
|
||||
name: 'event',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [resource === '*' ? 'all' : resource],
|
||||
},
|
||||
},
|
||||
options: resourceEvents[resource].map((event) => ({
|
||||
value: event === '*' ? 'all' : event,
|
||||
name: upperFirst(event),
|
||||
})),
|
||||
default: '',
|
||||
required: true,
|
||||
});
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
|
||||
export function mapResource(event: string) {
|
||||
return (
|
||||
{
|
||||
attachmentAction: 'attachmentActions',
|
||||
membership: 'memberships',
|
||||
message: 'messages',
|
||||
room: 'rooms',
|
||||
meeting: 'meetings',
|
||||
recording: 'recordings',
|
||||
telephonyCall: 'telephony_calls',
|
||||
all: 'all',
|
||||
} as { [key: string]: string }
|
||||
)[event];
|
||||
}
|
||||
|
||||
function removeEmptyProperties(rest: { [key: string]: any }) {
|
||||
return Object.keys(rest)
|
||||
.filter((k) => rest[k] !== '')
|
||||
.reduce((a, k) => ({ ...a, [k]: rest[k] }), {});
|
||||
}
|
||||
|
||||
export function getAttachments(attachments: IDataObject[]) {
|
||||
const _attachments: IDataObject[] = [];
|
||||
for (const attachment of attachments) {
|
||||
const body: IDataObject[] = [];
|
||||
const actions: IDataObject[] = [];
|
||||
for (const element of ((attachment?.elementsUi as IDataObject)
|
||||
.elementValues as IDataObject[]) || []) {
|
||||
const { type, ...rest } = element as { type: string; [key: string]: any };
|
||||
if (type.startsWith('input')) {
|
||||
body.push({
|
||||
type: `Input.${upperFirst(type.replace('input', ''))}`,
|
||||
...removeEmptyProperties(rest),
|
||||
});
|
||||
} else {
|
||||
body.push({ type: upperFirst(type), ...removeEmptyProperties(rest) });
|
||||
}
|
||||
}
|
||||
for (const action of ((attachment?.actionsUi as IDataObject).actionValues as IDataObject[]) ||
|
||||
[]) {
|
||||
const { type, ...rest } = action as { type: string; [key: string]: any };
|
||||
actions.push({ type: `Action.${upperFirst(type)}`, ...removeEmptyProperties(rest) });
|
||||
}
|
||||
_attachments.push({
|
||||
contentType: 'application/vnd.microsoft.card.adaptive',
|
||||
content: {
|
||||
$schema: 'http://adaptivecards.io/schemas/adaptive-card.json',
|
||||
type: 'AdaptiveCard',
|
||||
version: '1.2',
|
||||
body,
|
||||
actions,
|
||||
},
|
||||
});
|
||||
}
|
||||
return _attachments;
|
||||
}
|
||||
|
||||
export function getActionInheritedProperties(): INodeProperties[] {
|
||||
return [
|
||||
{
|
||||
displayName: 'Title',
|
||||
name: 'title',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
description: 'Label for button or link that represents this action',
|
||||
},
|
||||
{
|
||||
displayName: 'Icon URL',
|
||||
name: 'iconUrl',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
'Optional icon to be shown on the action in conjunction with the title. Supports data URI in version 1.2+.',
|
||||
},
|
||||
{
|
||||
displayName: 'Style',
|
||||
name: 'style',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Default',
|
||||
value: 'default',
|
||||
},
|
||||
{
|
||||
name: 'Positive',
|
||||
value: 'positive',
|
||||
},
|
||||
{
|
||||
name: 'Destructive',
|
||||
value: 'destructive',
|
||||
},
|
||||
],
|
||||
default: 'default',
|
||||
description:
|
||||
'Controls the style of an Action, which influences how the action is displayed, spoken, etc',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function getTextBlockProperties(): INodeProperties[] {
|
||||
return [
|
||||
{
|
||||
displayName: 'Text',
|
||||
name: 'text',
|
||||
type: 'string',
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
type: ['textBlock'],
|
||||
},
|
||||
},
|
||||
required: true,
|
||||
description:
|
||||
'Text to display. A subset of markdown is supported (https://aka.ms/ACTextFeatures).',
|
||||
},
|
||||
{
|
||||
displayName: 'Color',
|
||||
name: 'color',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
type: ['textBlock'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Accent',
|
||||
value: 'accent',
|
||||
},
|
||||
{
|
||||
name: 'Attention',
|
||||
value: 'attention',
|
||||
},
|
||||
{
|
||||
name: 'Dark',
|
||||
value: 'dark',
|
||||
},
|
||||
{
|
||||
name: 'Default',
|
||||
value: 'default',
|
||||
},
|
||||
{
|
||||
name: 'Good',
|
||||
value: 'good',
|
||||
},
|
||||
{
|
||||
name: 'Light',
|
||||
value: 'light',
|
||||
},
|
||||
{
|
||||
name: 'Warning',
|
||||
value: 'warning',
|
||||
},
|
||||
],
|
||||
default: 'default',
|
||||
description: 'Color of the TextBlock element',
|
||||
},
|
||||
{
|
||||
displayName: 'Font Type',
|
||||
name: 'fontType',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
type: ['textBlock'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Default',
|
||||
value: 'default',
|
||||
},
|
||||
{
|
||||
name: 'Monospace',
|
||||
value: 'monospace',
|
||||
},
|
||||
],
|
||||
default: 'default',
|
||||
description: 'Type of font to use for rendering',
|
||||
},
|
||||
{
|
||||
displayName: 'Horizontal Alignment',
|
||||
name: 'horizontalAlignment',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
type: ['textBlock'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Left',
|
||||
value: 'left',
|
||||
},
|
||||
{
|
||||
name: 'Center',
|
||||
value: 'center',
|
||||
},
|
||||
{
|
||||
name: 'Right',
|
||||
value: 'right',
|
||||
},
|
||||
],
|
||||
default: 'left',
|
||||
description: 'Controls the horizontal text alignment',
|
||||
},
|
||||
{
|
||||
displayName: 'Is Subtle',
|
||||
name: 'isSubtle',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
type: ['textBlock'],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'Whether to display text slightly toned down to appear less prominent',
|
||||
},
|
||||
{
|
||||
displayName: 'Max Lines',
|
||||
name: 'maxLines',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
type: ['textBlock'],
|
||||
},
|
||||
},
|
||||
default: 1,
|
||||
description: 'Specifies the maximum number of lines to display',
|
||||
},
|
||||
{
|
||||
displayName: 'Size',
|
||||
name: 'size',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
type: ['textBlock'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Default',
|
||||
value: 'default',
|
||||
},
|
||||
{
|
||||
name: 'Extra Large',
|
||||
value: 'extraLarge',
|
||||
},
|
||||
{
|
||||
name: 'Large',
|
||||
value: 'large',
|
||||
},
|
||||
{
|
||||
name: 'Medium',
|
||||
value: 'medium',
|
||||
},
|
||||
{
|
||||
name: 'Small',
|
||||
value: 'small',
|
||||
},
|
||||
],
|
||||
default: 'default',
|
||||
description: 'Controls size of text',
|
||||
},
|
||||
{
|
||||
displayName: 'Weight',
|
||||
name: 'weight',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
type: ['textBlock'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Default',
|
||||
value: 'default',
|
||||
},
|
||||
{
|
||||
name: 'Lighter',
|
||||
value: 'lighter',
|
||||
},
|
||||
{
|
||||
name: 'Bolder',
|
||||
value: 'bolder',
|
||||
},
|
||||
],
|
||||
default: 'default',
|
||||
description: 'Controls the weight of TextBlock elements',
|
||||
},
|
||||
{
|
||||
displayName: 'Wrap',
|
||||
name: 'wrap',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
type: ['textBlock'],
|
||||
},
|
||||
},
|
||||
default: true,
|
||||
description: 'Whether to allow text to wrap. Otherwise, text is clipped.',
|
||||
},
|
||||
{
|
||||
displayName: 'Height',
|
||||
name: 'height',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
type: ['textBlock'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Auto',
|
||||
value: 'auto',
|
||||
},
|
||||
{
|
||||
name: 'Stretch',
|
||||
value: 'stretch',
|
||||
},
|
||||
],
|
||||
default: 'auto',
|
||||
description: 'Specifies the height of the element',
|
||||
},
|
||||
{
|
||||
displayName: 'Separator',
|
||||
name: 'separator',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
displayOptions: {
|
||||
show: {
|
||||
type: ['textBlock'],
|
||||
},
|
||||
},
|
||||
description: 'Whether to draw a separating line at the top of the element',
|
||||
},
|
||||
{
|
||||
displayName: 'Spacing',
|
||||
name: 'spacing',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
type: ['textBlock'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Default',
|
||||
value: 'default',
|
||||
},
|
||||
{
|
||||
name: 'Extra Large',
|
||||
value: 'extraLarge',
|
||||
},
|
||||
{
|
||||
name: 'Large',
|
||||
value: 'large',
|
||||
},
|
||||
{
|
||||
name: 'Medium',
|
||||
value: 'medium',
|
||||
},
|
||||
{
|
||||
name: 'None',
|
||||
value: 'none',
|
||||
},
|
||||
{
|
||||
name: 'Padding',
|
||||
value: 'padding',
|
||||
},
|
||||
{
|
||||
name: 'Small',
|
||||
value: 'small',
|
||||
},
|
||||
],
|
||||
default: 'default',
|
||||
description: 'Controls the amount of spacing between this element and the preceding element',
|
||||
},
|
||||
{
|
||||
displayName: 'ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
type: ['textBlock'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'A unique identifier associated with the item',
|
||||
},
|
||||
{
|
||||
displayName: 'Is Visible',
|
||||
name: 'isVisible',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
type: ['textBlock'],
|
||||
},
|
||||
},
|
||||
default: true,
|
||||
description: 'Whether this item will be removed from the visual trees',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function getInputTextProperties(): INodeProperties[] {
|
||||
return [
|
||||
{
|
||||
displayName: 'ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
type: ['inputText'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description:
|
||||
'Unique identifier for the value. Used to identify collected input when the Submit action is performed.',
|
||||
},
|
||||
{
|
||||
displayName: 'Is Multiline',
|
||||
name: 'isMultiline',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
type: ['inputText'],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'Whether to allow multiple lines of input',
|
||||
},
|
||||
{
|
||||
displayName: 'Max Length',
|
||||
name: 'maxLength',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
type: ['inputText'],
|
||||
},
|
||||
},
|
||||
default: 1,
|
||||
description: 'Hint of maximum length characters to collect (may be ignored by some clients)',
|
||||
},
|
||||
{
|
||||
displayName: 'Placeholder',
|
||||
name: 'placeholder',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
type: ['inputText'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'Description of the input desired. Displayed when no text has been input.',
|
||||
},
|
||||
{
|
||||
displayName: 'Regex',
|
||||
name: 'regex',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
type: ['inputText'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'Regular expression indicating the required format of this text input',
|
||||
},
|
||||
{
|
||||
displayName: 'Style',
|
||||
name: 'style',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
type: ['inputText'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Text',
|
||||
value: 'text',
|
||||
},
|
||||
{
|
||||
name: 'Tel',
|
||||
value: 'tel',
|
||||
},
|
||||
{
|
||||
name: 'URL',
|
||||
value: 'url',
|
||||
},
|
||||
{
|
||||
name: 'Email',
|
||||
value: 'email',
|
||||
},
|
||||
],
|
||||
default: 'text',
|
||||
description: 'Style hint for text input',
|
||||
},
|
||||
{
|
||||
displayName: 'Value',
|
||||
name: 'value',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
type: ['inputText'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'The initial value for this field',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function getAutomaticSecret(credentials: ICredentialDataDecryptedObject) {
|
||||
const data = `${credentials.clientId},${credentials.clientSecret}`;
|
||||
return createHash('md5').update(data).digest('hex');
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"personEmail": {
|
||||
"type": "string"
|
||||
},
|
||||
"personId": {
|
||||
"type": "string"
|
||||
},
|
||||
"roomId": {
|
||||
"type": "string"
|
||||
},
|
||||
"roomType": {
|
||||
"type": "string"
|
||||
},
|
||||
"text": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"version": 1
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"personEmail": {
|
||||
"type": "string"
|
||||
},
|
||||
"personId": {
|
||||
"type": "string"
|
||||
},
|
||||
"roomId": {
|
||||
"type": "string"
|
||||
},
|
||||
"roomType": {
|
||||
"type": "string"
|
||||
},
|
||||
"text": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"version": 1
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 216 KiB |
@@ -0,0 +1,961 @@
|
||||
import type { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export const meetingOperations: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['meeting'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Create',
|
||||
value: 'create',
|
||||
action: 'Create a meeting',
|
||||
},
|
||||
{
|
||||
name: 'Delete',
|
||||
value: 'delete',
|
||||
action: 'Delete a meeting',
|
||||
},
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
action: 'Get a meeting',
|
||||
},
|
||||
{
|
||||
name: 'Get Many',
|
||||
value: 'getAll',
|
||||
action: 'Get many meetings',
|
||||
},
|
||||
{
|
||||
name: 'Update',
|
||||
value: 'update',
|
||||
action: 'Update a meeting',
|
||||
},
|
||||
],
|
||||
default: 'create',
|
||||
},
|
||||
];
|
||||
|
||||
export const meetingFields: INodeProperties[] = [
|
||||
// ----------------------------------------
|
||||
// meeting: create
|
||||
// ----------------------------------------
|
||||
{
|
||||
displayName: 'Title',
|
||||
name: 'title',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['meeting'],
|
||||
operation: ['create'],
|
||||
},
|
||||
},
|
||||
description: 'Meeting title. The title can be a maximum of 128 characters long.',
|
||||
},
|
||||
{
|
||||
displayName: 'Start',
|
||||
name: 'start',
|
||||
type: 'dateTime',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['meeting'],
|
||||
operation: ['create'],
|
||||
},
|
||||
},
|
||||
description:
|
||||
'Date and time for the start of the meeting. Acceptable <a href="https://datatracker.ietf.org/doc/html/rfc2445"> format</a>.',
|
||||
},
|
||||
{
|
||||
displayName: 'End',
|
||||
name: 'end',
|
||||
type: 'dateTime',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['meeting'],
|
||||
operation: ['create'],
|
||||
},
|
||||
},
|
||||
description:
|
||||
'Date and time for the end of the meeting. Acceptable <a href="https://datatracker.ietf.org/doc/html/rfc2445"> format</a>.',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['meeting'],
|
||||
operation: ['create'],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
placeholder: 'Add Field',
|
||||
options: [
|
||||
{
|
||||
displayName: 'Agenda',
|
||||
name: 'agenda',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Meeting agenda. The agenda can be a maximum of 1300 characters long.',
|
||||
},
|
||||
{
|
||||
displayName: 'Allow Any User To Be Co-Host',
|
||||
name: 'allowAnyUserToBeCoHost',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description:
|
||||
'Whether or not to allow any attendee with a host account on the target site to become a co-host when joining the meeting',
|
||||
},
|
||||
{
|
||||
displayName: 'Allow Authenticated Devices',
|
||||
name: 'allowAuthenticatedDevices',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description:
|
||||
"Whether or not to allow authenticated video devices in the meeting's organization to start or join the meeting without a prompt",
|
||||
},
|
||||
{
|
||||
displayName: 'Allow First User To Be Co-Host',
|
||||
name: 'allowFirstUserToBeCoHost',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description:
|
||||
'Whether or not to allow the first attendee of the meeting with a host account on the target site to become a co-host',
|
||||
},
|
||||
{
|
||||
displayName: 'Auto Accept Request',
|
||||
name: 'autoAcceptRequest',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether or not meeting registration request is accepted automatically',
|
||||
},
|
||||
{
|
||||
displayName: 'Enable Connect Audio Before Host',
|
||||
name: 'enableConnectAudioBeforeHost',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description:
|
||||
'Whether or not to allow any attendee to connect audio in the meeting before the host joins the meeting',
|
||||
},
|
||||
{
|
||||
displayName: 'Enabled Auto Record Meeting',
|
||||
name: 'enabledAutoRecordMeeting',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether or not meeting is recorded automatically',
|
||||
},
|
||||
{
|
||||
displayName: 'Enabled Join Before Host',
|
||||
name: 'enabledJoinBeforeHost',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description:
|
||||
'Whether or not to allow any attendee to join the meeting before the host joins the meeting',
|
||||
},
|
||||
{
|
||||
displayName: 'Exclude Password',
|
||||
name: 'excludePassword',
|
||||
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether or not to exclude password from the meeting email invitation',
|
||||
},
|
||||
{
|
||||
displayName: 'Host Email',
|
||||
name: 'hostEmail',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: "Email address for the meeting host. Can only be set if you're an admin.",
|
||||
},
|
||||
{
|
||||
displayName: 'Integration Tags',
|
||||
name: 'integrationTags',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
'External keys created by an integration application in its own domain. They could be Zendesk ticket IDs, Jira IDs, Salesforce Opportunity IDs, etc.',
|
||||
},
|
||||
{
|
||||
displayName: 'Invitees',
|
||||
name: 'inviteesUi',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
},
|
||||
default: {},
|
||||
placeholder: 'Add Invitee',
|
||||
options: [
|
||||
{
|
||||
displayName: 'Invitee',
|
||||
name: 'inviteeValues',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Email',
|
||||
name: 'email',
|
||||
type: 'string',
|
||||
placeholder: 'name@email.com',
|
||||
required: true,
|
||||
default: '',
|
||||
description: 'Email address of meeting invitee',
|
||||
},
|
||||
{
|
||||
displayName: 'Display Name',
|
||||
name: 'displayName',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Display name of meeting invitee',
|
||||
},
|
||||
{
|
||||
displayName: 'Co-Host',
|
||||
name: 'coHost',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether or not invitee is allowed to be a co-host for the meeting',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Join Before Host Minutes',
|
||||
name: 'joinBeforeHostMinutes',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: '0',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
name: '5',
|
||||
value: 5,
|
||||
},
|
||||
{
|
||||
name: '10',
|
||||
value: 10,
|
||||
},
|
||||
{
|
||||
name: '15',
|
||||
value: 15,
|
||||
},
|
||||
],
|
||||
default: 0,
|
||||
description:
|
||||
'The number of minutes an attendee can join the meeting before the meeting start time and the host joins',
|
||||
},
|
||||
{
|
||||
displayName: 'Public Meeting',
|
||||
name: 'publicMeeting',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether or not to allow the meeting to be listed on the public calendar',
|
||||
},
|
||||
{
|
||||
displayName: 'Recurrence',
|
||||
name: 'recurrence',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
'Rule for how the meeting should recur. Acceptable <a href="https://datatracker.ietf.org/doc/html/rfc2445"> format</a>.',
|
||||
},
|
||||
{
|
||||
displayName: 'Required Registration Info',
|
||||
name: 'requireRegistrationInfo',
|
||||
type: 'multiOptions',
|
||||
// eslint-disable-next-line n8n-nodes-base/node-param-multi-options-type-unsorted-items
|
||||
options: [
|
||||
{
|
||||
name: 'Require First Name',
|
||||
value: 'requireFirstName',
|
||||
},
|
||||
{
|
||||
name: 'Require Last Name',
|
||||
value: 'requireLastName',
|
||||
},
|
||||
{
|
||||
name: 'Require Email',
|
||||
value: 'requireEmail',
|
||||
},
|
||||
{
|
||||
name: 'Require Job Title',
|
||||
value: 'requireJobTitle',
|
||||
},
|
||||
{
|
||||
name: 'Require Company Name',
|
||||
value: 'requireCompanyName',
|
||||
},
|
||||
{
|
||||
name: 'Require Address 1',
|
||||
value: 'requireAddress1',
|
||||
},
|
||||
{
|
||||
name: 'Require Address 2',
|
||||
value: 'requireAddress2',
|
||||
},
|
||||
{
|
||||
name: 'Require City',
|
||||
value: 'requireCity',
|
||||
},
|
||||
{
|
||||
name: 'Require State',
|
||||
value: 'requireState',
|
||||
},
|
||||
{
|
||||
name: 'Require Zip Code',
|
||||
value: 'requireZipCode',
|
||||
},
|
||||
{
|
||||
name: 'Require Country Region',
|
||||
value: 'requireCountryRegion',
|
||||
},
|
||||
{
|
||||
name: 'Require Work Phone',
|
||||
value: 'requireWorkPhone',
|
||||
},
|
||||
{
|
||||
name: 'Require Fax',
|
||||
value: 'requireFax',
|
||||
},
|
||||
],
|
||||
default: [],
|
||||
description: 'Data required for meeting registration',
|
||||
},
|
||||
{
|
||||
displayName: 'Reminder Time',
|
||||
name: 'reminderTime',
|
||||
type: 'number',
|
||||
default: 1,
|
||||
description:
|
||||
'The number of minutes before the meeting begins, for sending an email reminder to the host',
|
||||
},
|
||||
{
|
||||
displayName: 'Send Email',
|
||||
name: 'sendEmail',
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
description: 'Whether or not to send emails to host and invitees',
|
||||
},
|
||||
{
|
||||
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
|
||||
displayName: 'Site URL',
|
||||
name: 'siteUrl',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getSites',
|
||||
},
|
||||
default: '',
|
||||
description:
|
||||
'URL of the Webex site which the meeting is created on. If not specified, the meeting is created on user\'s preferred site. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------------
|
||||
// meeting: delete
|
||||
// ----------------------------------------
|
||||
{
|
||||
displayName: 'Meeting ID',
|
||||
name: 'meetingId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['meeting'],
|
||||
operation: ['delete'],
|
||||
},
|
||||
},
|
||||
description: 'ID of the meeting',
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add option',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['meeting'],
|
||||
operation: ['delete'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Host Email',
|
||||
name: 'hostEmail',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
'Email address for the meeting host. This parameter is only used if the user or application calling the API has the admin-level scopes.',
|
||||
},
|
||||
{
|
||||
displayName: 'Send Email',
|
||||
name: 'sendEmail',
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
description: 'Whether or not to send emails to host and invitees',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------------
|
||||
// meeting: get
|
||||
// ----------------------------------------
|
||||
{
|
||||
displayName: 'Meeting ID',
|
||||
name: 'meetingId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['meeting'],
|
||||
operation: ['get'],
|
||||
},
|
||||
},
|
||||
description: 'ID of the meeting',
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add option',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['meeting'],
|
||||
operation: ['get'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Host Email',
|
||||
name: 'hostEmail',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
'Email address for the meeting host. This parameter is only used if the user or application calling the API has the admin-level scopes.',
|
||||
},
|
||||
{
|
||||
displayName: 'Password',
|
||||
name: 'password',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
description:
|
||||
"Meeting password. It's required when the meeting is protected by a password and the current user is not privileged to view it if they are not a host, co-host or invitee of the meeting.",
|
||||
},
|
||||
{
|
||||
displayName: 'Send Email',
|
||||
name: 'sendEmail',
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
description:
|
||||
'Whether or not to send emails to host and invitees. It is an optional field and default value is true.',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------------
|
||||
// meeting: getAll
|
||||
// ----------------------------------------
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether to return all results or only up to a given limit',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['meeting'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
default: 50,
|
||||
description: 'Max number of results to return',
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['meeting'],
|
||||
operation: ['getAll'],
|
||||
returnAll: [false],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Filters',
|
||||
name: 'filters',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Filter',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['meeting'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'From',
|
||||
name: 'from',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description:
|
||||
'Start date and time (inclusive) for the meeting. Acceptable <a href="https://datatracker.ietf.org/doc/html/rfc2445"> format</a>.',
|
||||
},
|
||||
{
|
||||
displayName: 'Host Email',
|
||||
name: 'hostEmail',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Email address for the meeting host',
|
||||
},
|
||||
{
|
||||
displayName: 'Integration Tag',
|
||||
name: 'integrationTag',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
'External tag created by another application, e.g. Zendesk ticket ID or Jira ID',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit to Current Meetings',
|
||||
name: 'current',
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
description: 'Whether to return just the current meeting or all meetings',
|
||||
},
|
||||
{
|
||||
displayName: 'Meeting Number',
|
||||
name: 'meetingNumber',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Meeting number for the meeting objects being requested',
|
||||
},
|
||||
{
|
||||
displayName: 'Meeting Type',
|
||||
name: 'meetingType',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Meeting Series',
|
||||
value: 'meetingSeries',
|
||||
description:
|
||||
'Master of a scheduled series of meetings which consists of one or more scheduled meeting based on a recurrence rule',
|
||||
},
|
||||
{
|
||||
name: 'Scheduled Meeting',
|
||||
value: 'scheduledMeeting',
|
||||
description: 'Instance from a master meeting series',
|
||||
},
|
||||
{
|
||||
name: 'Meeting',
|
||||
value: 'meeting',
|
||||
description: 'Meeting instance that is actually happening or has happened',
|
||||
},
|
||||
],
|
||||
default: 'meetingSeries',
|
||||
},
|
||||
{
|
||||
displayName: 'Participant Email',
|
||||
name: 'participantEmail',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Email of a person that must be a meeting participant',
|
||||
},
|
||||
{
|
||||
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
|
||||
displayName: 'Site URL',
|
||||
name: 'siteUrl',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getSites',
|
||||
},
|
||||
default: '',
|
||||
description:
|
||||
'URL of the Webex site which the API lists meetings from. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
||||
},
|
||||
{
|
||||
displayName: 'State',
|
||||
name: 'state',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Active',
|
||||
value: 'active',
|
||||
},
|
||||
{
|
||||
name: 'Ended',
|
||||
value: 'ended',
|
||||
},
|
||||
{
|
||||
name: 'Expired',
|
||||
value: 'expired',
|
||||
},
|
||||
{
|
||||
name: 'In Progress',
|
||||
value: 'inProgress',
|
||||
},
|
||||
{
|
||||
name: 'Lobby',
|
||||
value: 'lobby',
|
||||
},
|
||||
{
|
||||
name: 'Missed',
|
||||
value: 'missed',
|
||||
},
|
||||
{
|
||||
name: 'Ready',
|
||||
value: 'ready',
|
||||
},
|
||||
{
|
||||
name: 'Scheduled',
|
||||
value: 'scheduled',
|
||||
},
|
||||
],
|
||||
default: '',
|
||||
description: 'Meeting state for the meeting objects being requested',
|
||||
},
|
||||
{
|
||||
displayName: 'To',
|
||||
name: 'to',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description:
|
||||
'End date and time (inclusive) for the meeting. Acceptable <a href="https://datatracker.ietf.org/doc/html/rfc2445"> format</a>.',
|
||||
},
|
||||
{
|
||||
displayName: 'Weblink',
|
||||
name: 'webLink',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'URL encoded link to information page for the meeting objects being requested',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------------
|
||||
// meeting: update
|
||||
// ----------------------------------------
|
||||
{
|
||||
displayName: 'Meeting ID',
|
||||
name: 'meetingId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['meeting'],
|
||||
operation: ['update'],
|
||||
},
|
||||
},
|
||||
description: 'ID of the meeting',
|
||||
},
|
||||
{
|
||||
displayName: 'Update Fields',
|
||||
name: 'updateFields',
|
||||
type: 'collection',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['meeting'],
|
||||
operation: ['update'],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
placeholder: 'Add Field',
|
||||
options: [
|
||||
{
|
||||
displayName: 'Agenda',
|
||||
name: 'agenda',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: "The meeting's agenda. Cannot be longer that 1300 characters.",
|
||||
},
|
||||
{
|
||||
displayName: 'Allow Any User To Be Co-Host',
|
||||
name: 'allowAnyUserToBeCoHost',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description:
|
||||
'Whether or not to allow any attendee with a host account on the target site to become a co-host when joining the meeting',
|
||||
},
|
||||
{
|
||||
displayName: 'Allow Authenticated Devices',
|
||||
name: 'allowAuthenticatedDevices',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description:
|
||||
"Whether or not to allow authenticated video devices in the meeting's organization to start or join the meeting without a prompt",
|
||||
},
|
||||
{
|
||||
displayName: 'Allow First User To Be Co-Host',
|
||||
name: 'allowFirstUserToBeCoHost',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description:
|
||||
'Whether or not to allow the first attendee of the meeting with a host account on the target site to become a co-host',
|
||||
},
|
||||
{
|
||||
displayName: 'Enable Connect Audio Before Host',
|
||||
name: 'enableConnectAudioBeforeHost',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description:
|
||||
'Whether or not to allow any attendee to connect audio in the meeting before the host joins the meeting',
|
||||
},
|
||||
{
|
||||
displayName: 'Enabled Auto Record Meeting',
|
||||
name: 'enabledAutoRecordMeeting',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether or not meeting is recorded automatically',
|
||||
},
|
||||
{
|
||||
displayName: 'Enabled Join Before Host',
|
||||
name: 'enabledJoinBeforeHost',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description:
|
||||
'Whether or not to allow any attendee to join the meeting before the host joins the meeting',
|
||||
},
|
||||
{
|
||||
displayName: 'End',
|
||||
name: 'end',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description:
|
||||
'Date and time for the end of the meeting. Acceptable <a href="https://datatracker.ietf.org/doc/html/rfc2445"> format</a>.',
|
||||
},
|
||||
{
|
||||
displayName: 'Exclude Password',
|
||||
name: 'excludePassword',
|
||||
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether or not to exclude password from the meeting email invitation',
|
||||
},
|
||||
{
|
||||
displayName: 'Host Email',
|
||||
name: 'hostEmail',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
'Email address for the meeting host. This attribute should only be set if the user or application calling the API has the admin-level scopes.',
|
||||
},
|
||||
{
|
||||
displayName: 'Invitees',
|
||||
name: 'inviteesUi',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
},
|
||||
default: {},
|
||||
placeholder: 'Add Invitee',
|
||||
options: [
|
||||
{
|
||||
displayName: 'Invitee',
|
||||
name: 'inviteeValues',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Email',
|
||||
name: 'email',
|
||||
type: 'string',
|
||||
placeholder: 'name@email.com',
|
||||
required: true,
|
||||
default: '',
|
||||
description: 'Email address of meeting invitee',
|
||||
},
|
||||
{
|
||||
displayName: 'Display Name',
|
||||
name: 'displayName',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Display name of meeting invitee',
|
||||
},
|
||||
{
|
||||
displayName: 'Co-Host',
|
||||
name: 'coHost',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether or not invitee is allowed to be a co-host for the meeting',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Join Before Host Minutes',
|
||||
name: 'joinBeforeHostMinutes',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: '0',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
name: '5',
|
||||
value: 5,
|
||||
},
|
||||
{
|
||||
name: '10',
|
||||
value: 10,
|
||||
},
|
||||
{
|
||||
name: '15',
|
||||
value: 15,
|
||||
},
|
||||
],
|
||||
default: 0,
|
||||
description:
|
||||
'The number of minutes an attendee can join the meeting before the meeting start time and the host joins',
|
||||
},
|
||||
{
|
||||
displayName: 'Password',
|
||||
name: 'password',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
description:
|
||||
"Meeting password. Must conform to the site's password complexity settings. If not specified, a random password conforming to the site's password rules will be generated automatically",
|
||||
},
|
||||
{
|
||||
displayName: 'Public Meeting',
|
||||
name: 'publicMeeting',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether or not to allow the meeting to be listed on the public calendar',
|
||||
},
|
||||
{
|
||||
displayName: 'Recurrence',
|
||||
name: 'recurrence',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
'Meeting series recurrence rule (conforming with RFC 2445), applying only to meeting series',
|
||||
},
|
||||
{
|
||||
displayName: 'Required Registration Info',
|
||||
name: 'requireRegistrationInfo',
|
||||
type: 'multiOptions',
|
||||
// eslint-disable-next-line n8n-nodes-base/node-param-multi-options-type-unsorted-items
|
||||
options: [
|
||||
{
|
||||
name: 'Require First Name',
|
||||
value: 'requireFirstName',
|
||||
},
|
||||
{
|
||||
name: 'Require Last Name',
|
||||
value: 'requireLastName',
|
||||
},
|
||||
{
|
||||
name: 'Require Email',
|
||||
value: 'requireEmail',
|
||||
},
|
||||
{
|
||||
name: 'Require Job Title',
|
||||
value: 'requireJobTitle',
|
||||
},
|
||||
{
|
||||
name: 'Require Company Name',
|
||||
value: 'requireCompanyName',
|
||||
},
|
||||
{
|
||||
name: 'Require Address 1',
|
||||
value: 'requireAddress1',
|
||||
},
|
||||
{
|
||||
name: 'Require Address 2',
|
||||
value: 'requireAddress2',
|
||||
},
|
||||
{
|
||||
name: 'Require City',
|
||||
value: 'requireCity',
|
||||
},
|
||||
{
|
||||
name: 'Require State',
|
||||
value: 'requireState',
|
||||
},
|
||||
{
|
||||
name: 'Require Zip Code',
|
||||
value: 'requireZipCode',
|
||||
},
|
||||
{
|
||||
name: 'Require Country Region',
|
||||
value: 'requireCountryRegion',
|
||||
},
|
||||
{
|
||||
name: 'Require Work Phone',
|
||||
value: 'requireWorkPhone',
|
||||
},
|
||||
{
|
||||
name: 'Require Fax',
|
||||
value: 'requireFax',
|
||||
},
|
||||
],
|
||||
default: [],
|
||||
description: 'Data required for meeting registration',
|
||||
},
|
||||
{
|
||||
displayName: 'Reminder Time',
|
||||
name: 'reminderTime',
|
||||
type: 'number',
|
||||
default: 1,
|
||||
description:
|
||||
'The number of minutes before the meeting begins, for sending an email reminder to the host',
|
||||
},
|
||||
{
|
||||
displayName: 'Send Email',
|
||||
name: 'sendEmail',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description:
|
||||
'Whether or not to send emails to host and invitees. It is an optional field and default value is true.',
|
||||
},
|
||||
{
|
||||
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
|
||||
displayName: 'Site URL',
|
||||
name: 'siteUrl',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getSites',
|
||||
},
|
||||
default: '',
|
||||
description:
|
||||
'URL of the Webex site which the meeting is created on. If not specified, the meeting is created on user\'s preferred site. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
||||
},
|
||||
{
|
||||
displayName: 'Start',
|
||||
name: 'start',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description:
|
||||
'Date and time for the start of the meeting. Acceptable <a href="https://datatracker.ietf.org/doc/html/rfc2445"> format</a>.',
|
||||
},
|
||||
{
|
||||
displayName: 'Title',
|
||||
name: 'title',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Meeting title',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,166 @@
|
||||
import type { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export const meetingTranscriptOperations: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['meetingTranscript'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Download',
|
||||
value: 'download',
|
||||
action: 'Download a meeting transcript',
|
||||
},
|
||||
{
|
||||
name: 'Get Many',
|
||||
value: 'getAll',
|
||||
action: 'Get many meeting transcripts',
|
||||
},
|
||||
],
|
||||
default: 'download',
|
||||
},
|
||||
];
|
||||
|
||||
export const meetingTranscriptFields: INodeProperties[] = [
|
||||
// ----------------------------------------
|
||||
// meetingTranscript: download
|
||||
// ----------------------------------------
|
||||
{
|
||||
displayName: 'Transcript ID',
|
||||
name: 'transcriptId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['meetingTranscript'],
|
||||
operation: ['download'],
|
||||
},
|
||||
},
|
||||
description: 'Unique identifier for the meeting transcript',
|
||||
},
|
||||
{
|
||||
displayName: 'Meeting ID',
|
||||
name: 'meetingId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['meetingTranscript'],
|
||||
operation: ['download'],
|
||||
},
|
||||
},
|
||||
description: 'Unique identifier for the meeting instance which the transcripts belong to',
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['meetingTranscript'],
|
||||
operation: ['download'],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
placeholder: 'Add option',
|
||||
options: [
|
||||
{
|
||||
displayName: 'Format',
|
||||
name: 'format',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased
|
||||
name: 'txt',
|
||||
value: 'txt',
|
||||
},
|
||||
{
|
||||
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased
|
||||
name: 'vtt',
|
||||
value: 'vtt',
|
||||
},
|
||||
],
|
||||
default: 'vtt',
|
||||
description: 'Format for the downloaded meeting transcript',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------------
|
||||
// meetingTranscript: getAll
|
||||
// ----------------------------------------
|
||||
{
|
||||
displayName: 'Meeting ID',
|
||||
name: 'meetingId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['meetingTranscript'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
description: 'Unique identifier for the meeting instance which the transcripts belong to',
|
||||
},
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether to return all results or only up to a given limit',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['meetingTranscript'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
default: 50,
|
||||
description: 'Max number of results to return',
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['meetingTranscript'],
|
||||
operation: ['getAll'],
|
||||
returnAll: [false],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Filters',
|
||||
name: 'filters',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Filter',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['meetingTranscript'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Host Email',
|
||||
name: 'hostEmail',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Email address for the meetingTranscript host',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,569 @@
|
||||
import type { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
getActionInheritedProperties,
|
||||
getInputTextProperties,
|
||||
getTextBlockProperties,
|
||||
} from '../GenericFunctions';
|
||||
|
||||
export const messageOperations: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['message'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Create',
|
||||
value: 'create',
|
||||
action: 'Create a message',
|
||||
},
|
||||
{
|
||||
name: 'Delete',
|
||||
value: 'delete',
|
||||
action: 'Delete a message',
|
||||
},
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
action: 'Get a message',
|
||||
},
|
||||
{
|
||||
name: 'Get Many',
|
||||
value: 'getAll',
|
||||
action: 'Get many messages',
|
||||
},
|
||||
{
|
||||
name: 'Update',
|
||||
value: 'update',
|
||||
action: 'Update a message',
|
||||
},
|
||||
],
|
||||
default: 'create',
|
||||
},
|
||||
];
|
||||
|
||||
export const messageFields: INodeProperties[] = [
|
||||
// ----------------------------------------
|
||||
// message: create
|
||||
// ----------------------------------------
|
||||
{
|
||||
displayName: 'Destination',
|
||||
name: 'destination',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Room',
|
||||
value: 'room',
|
||||
},
|
||||
{
|
||||
name: 'Person',
|
||||
value: 'person',
|
||||
},
|
||||
],
|
||||
required: true,
|
||||
default: 'room',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['message'],
|
||||
operation: ['create'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Room Name or ID',
|
||||
name: 'roomId',
|
||||
type: 'options',
|
||||
description:
|
||||
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getRooms',
|
||||
},
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['message'],
|
||||
operation: ['create'],
|
||||
destination: ['room'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Specify Person By',
|
||||
name: 'specifyPersonBy',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Email',
|
||||
value: 'email',
|
||||
},
|
||||
{
|
||||
name: 'ID',
|
||||
value: 'id',
|
||||
},
|
||||
],
|
||||
required: true,
|
||||
default: 'email',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['message'],
|
||||
operation: ['create'],
|
||||
destination: ['person'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Person ID',
|
||||
name: 'toPersonId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['message'],
|
||||
operation: ['create'],
|
||||
specifyPersonBy: ['id'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Person Email',
|
||||
name: 'toPersonEmail',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['message'],
|
||||
operation: ['create'],
|
||||
specifyPersonBy: ['email'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Text',
|
||||
name: 'text',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['message'],
|
||||
operation: ['create'],
|
||||
},
|
||||
},
|
||||
description: 'The message, in plain text',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['message'],
|
||||
operation: ['create'],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
placeholder: 'Add Field',
|
||||
options: [
|
||||
{
|
||||
displayName: 'Attachments',
|
||||
name: 'attachmentsUi',
|
||||
type: 'fixedCollection',
|
||||
default: {},
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
},
|
||||
placeholder: 'Add Attachment',
|
||||
options: [
|
||||
{
|
||||
displayName: 'Attachment',
|
||||
name: 'attachmentValues',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Elements',
|
||||
name: 'elementsUi',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
},
|
||||
default: {},
|
||||
placeholder: 'Add Element',
|
||||
options: [
|
||||
{
|
||||
displayName: 'Element',
|
||||
name: 'elementValues',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Type',
|
||||
name: 'type',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Text Block',
|
||||
value: 'textBlock',
|
||||
},
|
||||
{
|
||||
name: 'Input Text',
|
||||
value: 'inputText',
|
||||
},
|
||||
],
|
||||
default: 'textBlock',
|
||||
},
|
||||
...getTextBlockProperties(),
|
||||
...getInputTextProperties(),
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Actions',
|
||||
name: 'actionsUi',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
},
|
||||
default: {},
|
||||
placeholder: 'Add Action',
|
||||
options: [
|
||||
{
|
||||
displayName: 'Action',
|
||||
name: 'actionValues',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Type',
|
||||
name: 'type',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Execute',
|
||||
value: 'execute',
|
||||
},
|
||||
{
|
||||
name: 'Open URL',
|
||||
value: 'openUrl',
|
||||
},
|
||||
{
|
||||
name: 'Submit',
|
||||
value: 'submit',
|
||||
},
|
||||
],
|
||||
default: 'openUrl',
|
||||
},
|
||||
{
|
||||
displayName: 'URL',
|
||||
name: 'url',
|
||||
type: 'string',
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
type: ['openUrl'],
|
||||
},
|
||||
},
|
||||
description: 'The URL to open',
|
||||
},
|
||||
{
|
||||
displayName: 'Data',
|
||||
name: 'data',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
type: ['submit', 'execute'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description:
|
||||
'Any extra data to pass along. These are essentially ‘hidden’ properties.',
|
||||
},
|
||||
{
|
||||
displayName: 'Verb',
|
||||
name: 'verb',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
type: ['execute'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'The card author-defined verb associated with this action',
|
||||
},
|
||||
...getActionInheritedProperties(),
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'File',
|
||||
name: 'fileUi',
|
||||
placeholder: 'Add File',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: false,
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
name: 'fileValue',
|
||||
displayName: 'File',
|
||||
values: [
|
||||
{
|
||||
displayName: 'File Location',
|
||||
name: 'fileLocation',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'URL',
|
||||
value: 'url',
|
||||
},
|
||||
{
|
||||
name: 'Binary File',
|
||||
value: 'binaryData',
|
||||
},
|
||||
],
|
||||
default: 'url',
|
||||
},
|
||||
{
|
||||
displayName: 'Input Field With File',
|
||||
name: 'binaryPropertyName',
|
||||
type: 'string',
|
||||
default: 'data',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
fileLocation: ['binaryData'],
|
||||
},
|
||||
},
|
||||
description: 'The field in the node input containing the binary file data',
|
||||
},
|
||||
{
|
||||
displayName: 'URL',
|
||||
name: 'url',
|
||||
type: 'string',
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
fileLocation: ['url'],
|
||||
},
|
||||
},
|
||||
description: 'The public URL of the file',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Markdown',
|
||||
name: 'markdown',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
'The message in markdown format. When used the text parameter is used to provide alternate text for UI clients that do not support rich text.',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------------
|
||||
// message: delete
|
||||
// ----------------------------------------
|
||||
{
|
||||
displayName: 'Message ID',
|
||||
name: 'messageId',
|
||||
description: 'ID of the message to delete',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['message'],
|
||||
operation: ['delete'],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// ----------------------------------------
|
||||
// message: get
|
||||
// ----------------------------------------
|
||||
{
|
||||
displayName: 'Message ID',
|
||||
name: 'messageId',
|
||||
description: 'ID of the message to retrieve',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['message'],
|
||||
operation: ['get'],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// ----------------------------------------
|
||||
// message: getAll
|
||||
// ----------------------------------------
|
||||
{
|
||||
displayName: 'Room Name or ID',
|
||||
name: 'roomId',
|
||||
description:
|
||||
'List messages in a room, by ID. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getRooms',
|
||||
},
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['message'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether to return all results or only up to a given limit',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['message'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
default: 50,
|
||||
description: 'Max number of results to return',
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['message'],
|
||||
operation: ['getAll'],
|
||||
returnAll: [false],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Filters',
|
||||
name: 'filters',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Filter',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['message'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Before',
|
||||
name: 'before',
|
||||
description: 'List messages sent before a date and time',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Before Message',
|
||||
name: 'beforeMessage',
|
||||
description: 'List messages sent before a message, by ID',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Parent Message ID',
|
||||
name: 'parentId',
|
||||
description: 'List messages with a parent, by ID',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Mentioned Person',
|
||||
name: 'mentionedPeople',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
"List only messages with certain person mentioned. Enter their ID. You can use 'me' as a shorthand for yourself",
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------------
|
||||
// message: update
|
||||
// ----------------------------------------
|
||||
{
|
||||
displayName: 'Message ID',
|
||||
name: 'messageId',
|
||||
description: 'ID of the message to update',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['message'],
|
||||
operation: ['update'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Is Markdown',
|
||||
name: 'markdown',
|
||||
description: 'Whether the message uses markdown',
|
||||
type: 'boolean',
|
||||
required: true,
|
||||
default: false,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['message'],
|
||||
operation: ['update'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Text',
|
||||
name: 'text',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['message'],
|
||||
operation: ['update'],
|
||||
markdown: [false],
|
||||
},
|
||||
},
|
||||
description: 'The message, in plain text',
|
||||
},
|
||||
{
|
||||
displayName: 'Markdown',
|
||||
name: 'markdownText',
|
||||
description: 'The message, in Markdown format. The maximum message length is 7439 bytes.',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['message'],
|
||||
operation: ['update'],
|
||||
markdown: [true],
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from './MessageDescription';
|
||||
export * from './MeetingDescription';
|
||||
export * from './MeetingTranscript';
|
||||
Reference in New Issue
Block a user