n8n/packages/nodes-base/nodes/Cisco/Webex/GenericFunctions.ts
Iván Ovejero 70ae90fa3c
refactor: Apply more eslint-plugin-n8n-nodes-base autofixable rules (#3432)
*  Update `lintfix` script

* 👕 Remove unneeded lint exceptions

* 👕 Run baseline `lintfix`

* 👕 Apply `node-param-description-miscased-url` (#3441)

* 👕 Apply `rule node-param-placeholder-miscased-id` (#3443)

Co-authored-by: Iván Ovejero <ivov.src@gmail.com>

* 👕 Apply `node-param-option-name-wrong-for-upsert` (#3446)

* 👕 Apply `node-param-min-value-wrong-for-limit` (#3442)

Co-authored-by: Iván Ovejero <ivov.src@gmail.com>

* Apply `node-param-display-name-wrong-for-dynamic-options` (#3454)

* 🔨 fix

*  Fix `Assigned To` fields

Co-authored-by: Michael Kret <michael.k@radency.com>

* 👕 Apply `rule node-param-default-wrong-for-number` (#3453)

* 👕 Apply `node-param-default-wrong-for-string` (#3452)

Co-authored-by: Iván Ovejero <ivov.src@gmail.com>

* Apply `node-param-display-name-miscased` (#3449)

* 🔨 fix

* 🔨 exceptions

*  review fixes

* 👕 Apply `node-param-description-lowercase-first-char` (#3451)

*  fix

*  review fixes

*  fix

Co-authored-by: Iván Ovejero <ivov.src@gmail.com>

* 👕 Apply `node-param-description-wrong-for-dynamic-options` (#3456)

* Rule working as intended

* Add rule

* 🔥 Remove repetitions

* 👕 Add exceptions

Co-authored-by: Iván Ovejero <ivov.src@gmail.com>

* 👕 Small fix for `node-param-description-wrong-for-dynamic-options`

* 👕 Apply `node-param-default-wrong-for-fixed-collection` (#3460)

* 👕 Apply `node-param-description-line-break-html-tag` (#3462)

* 👕 Run baseline `lintfix`

* 👕 Apply `node-param-options-type-unsorted-items` (#3459)

*  fix

* 🔨 exceptions

* Add exception for Salesmate and Zoom

Co-authored-by: Michael Kret <michael.k@radency.com>
Co-authored-by: Iván Ovejero <ivov.src@gmail.com>

*  Restore `lintfix` command

Co-authored-by: Omar Ajoue <krynble@gmail.com>
Co-authored-by: Michael Kret <88898367+michael-radency@users.noreply.github.com>
Co-authored-by: agobrech <45268029+agobrech@users.noreply.github.com>
Co-authored-by: Michael Kret <michael.k@radency.com>
Co-authored-by: brianinoa <54530642+brianinoa@users.noreply.github.com>
2022-06-03 19:23:49 +02:00

658 lines
13 KiB
TypeScript

import {
OptionsWithUri,
} from 'request';
import {
IExecuteFunctions,
IHookFunctions,
ILoadOptionsFunctions,
} from 'n8n-core';
import {
ICredentialDataDecryptedObject,
IDataObject,
INodeProperties,
IWebhookFunctions,
NodeApiError,
} from 'n8n-workflow';
import {
upperFirst,
} from 'lodash';
import {
createHash,
} from 'crypto';
export async function webexApiRequest(this: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions | IWebhookFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
let options: OptionsWithUri = {
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).length === 0) {
delete options.body;
}
if (Object.keys(qs).length === 0) {
delete options.qs;
}
//@ts-ignore
return await this.helpers.requestOAuth2.call(this, 'ciscoWebexOAuth2Api', options, { tokenType: 'Bearer' });
} catch (error) {
throw new NodeApiError(this.getNode(), error);
}
}
export async function webexApiRequestAllItems(this: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions, propertyName: string, method: string, endpoint: string, body: any = {}, query: IDataObject = {}, options: IDataObject = {}): Promise<any> { // tslint:disable-line:no-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]);
} while (
responseData.headers['link'] !== undefined &&
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];
}
export function getAttachemnts(attachements: IDataObject[]) {
const _attachments: IDataObject[] = [];
for (const attachment of attachements) {
const body: IDataObject[] = [];
const actions: IDataObject[] = [];
for (const element of (attachment?.elementsUi as IDataObject).elementValues as IDataObject[] || []) {
// tslint:disable-next-line: no-any
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[] || []) {
// tslint:disable-next-line: no-any
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: 'Displays 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: 'If true, 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: 'When true, 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: 'If false, 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: 'If true, 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',
},
];
}
// tslint:disable-next-line: no-any
function removeEmptyProperties(rest: { [key: string]: any }) {
return Object.keys(rest)
.filter((k) => rest[k] !== '')
.reduce((a, k) => ({ ...a, [k]: rest[k] }), {});
}
export function getAutomaticSecret(credentials: ICredentialDataDecryptedObject) {
const data = `${credentials.clientId},${credentials.clientSecret}`;
return createHash('md5').update(data).digest('hex');
}