n8n/packages/nodes-base/nodes/GoToWebinar/GoToWebinar.node.ts

692 lines
22 KiB
TypeScript
Raw Normal View History

:sparkles: GoToWebinar node (#1422) * Create scaffolding for node * Add SVG logo * Create scaffolding for generic functions * Add index for descriptions * Simplify retrieval of details * Introduce minor fixes in generic functions * Add attendee description * Fix attendee description operation * Add coorganizer description * Add panelist description * Add registrant description * Add session description * Add webinar description * Register node and credentials * Add scaffolding for credentials * Minor creds fixes * Fix SVG icon size and position * Fix capitalization in description * Fix credentials connection * Add attendee fields * Populate webinar description * Remove organizer key from params * Add timezones array constant * Implement webinar:create * Implement webinar:delete * Convert times to fixed collection * Add missing segments to endpoints * Fix webinar:update operation * Implement all-items request * Add params for session:getAll * Add params for webinar:getAll * Implement session:getAll and webinar:getAll * Implement session:get and session:getDetails * Implement coorganizer:create * Implement coorganizer:delete * Implement coorganizer:getAll * Implement coorganizer:delete * Refactor time range for getAll operations * Implement coorganizer:reinvite * Implement panelist:create and panelist:getAll * Implement panelist:delete and panelist:reinvite * Remove array body helper types * Implement registrant:create and registrant:getAll * Implement registrant:delete * Prettify error handling * Add returnAll toggle and limit for all operations * Preload webinars * Preload webinar key in more fields * Refactor getAll as handler * Add descriptions for session * Add descriptions for attendee * Add descriptions for co-organizer * Add descriptions for panelist * Add descriptions for registrant * Add descriptions for webinar * Add 403 check for refresh token * Fix defaults for webinar loader * Add descriptions for webinar types * :zap: Improvements * Remove unneeded return type annotation * Add handler for continue on fail * Remove 403 check in error handler The Go To Webinar API returns 403 for a range of various errors, so this check ended up overriding more specific error messages not related to 403 Forbidden errors. * Remove logging * :zap: Small improvement * :zap: Minor improvements * :zap: Improvements * :zap: Minor improvements Co-authored-by: ricardo <ricardoespinoza105@gmail.com> Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
2021-02-21 23:49:00 -08:00
import {
IExecuteFunctions,
} from 'n8n-core';
import {
IDataObject,
ILoadOptionsFunctions,
INodeExecutionData,
INodePropertyOptions,
INodeType,
INodeTypeDescription,
:sparkles: Improve node error handling (#1309) * Add path mapping and response error interfaces * Add error handling and throwing functionality * Refactor error handling into a single function * Re-implement error handling in Hacker News node * Fix linting details * Re-implement error handling in Spotify node * Re-implement error handling in G Suite Admin node * :construction: create basic setup NodeError * :construction: add httpCodes * :construction: add path priolist * :construction: handle statusCode in error, adjust interfaces * :construction: fixing type issues w/Ivan * :construction: add error exploration * 👔 fix linter issues * :wrench: improve object check * :construction: remove path passing from NodeApiError * :construction: add multi error + refactor findProperty method * 👔 allow any * :wrench: handle multi error message callback * :zap: change return type of callback * :zap: add customCallback to MultiError * :construction: refactor to use INode * :hammer: handle arrays, continue search after first null property found * 🚫 refactor method access * :construction: setup NodeErrorView * :zap: change timestamp to Date.now * :books: Add documentation for methods and constants * :construction: change message setting * 🚚 move NodeErrors to workflow * :sparkles: add new ErrorView for Nodes * :art: improve error notification * :art: refactor interfaces * :zap: add WorkflowOperationError, refactor error throwing * 👕 fix linter issues * :art: rename param * :bug: fix handling normal errors * :zap: add usage of NodeApiError * :art: fix throw new error instead of constructor * :art: remove unnecessary code/comments * :art: adjusted spacing + updated status messages * :art: fix tab indentation * ✨ Replace current errors with custom errors (#1576) * :zap: Introduce NodeApiError in catch blocks * :zap: Introduce NodeOperationError in nodes * :zap: Add missing errors and remove incompatible * :zap: Fix NodeOperationError in incompatible nodes * :wrench: Adjust error handling in missed nodes PayPal, FileMaker, Reddit, Taiga and Facebook Graph API nodes * :hammer: Adjust Strava Trigger node error handling * :hammer: Adjust AWS nodes error handling * :hammer: Remove duplicate instantiation of NodeApiError * :bug: fix strava trigger node error handling * Add XML parsing to NodeApiError constructor (#1633) * :bug: Remove type annotation from catch variable * :sparkles: Add XML parsing to NodeApiError * :zap: Simplify error handling in Rekognition node * :zap: Pass in XML flag in generic functions * :fire: Remove try/catch wrappers at call sites * :hammer: Refactor setting description from XML * :hammer: Refactor let to const in resource loaders * :zap: Find property in parsed XML * :zap: Change let to const * :fire: Remove unneeded try/catch block * :shirt: Fix linting issues * :bug: Fix errors from merge conflict resolution * :zap: Add custom errors to latest contributions * :shirt: Fix linting issues * :zap: Refactor MongoDB helpers for custom errors * :bug: Correct custom error type * :zap: Apply feedback to A nodes * :zap: Apply feedback to missed A node * :zap: Apply feedback to B-D nodes * :zap: Apply feedback to E-F nodes * :zap: Apply feedback to G nodes * :zap: Apply feedback to H-L nodes * :zap: Apply feedback to M nodes * :zap: Apply feedback to P nodes * :zap: Apply feedback to R nodes * :zap: Apply feedback to S nodes * :zap: Apply feedback to T nodes * :zap: Apply feedback to V-Z nodes * :zap: Add HTTP code to iterable node error * :hammer: Standardize e as error * :hammer: Standardize err as error * :zap: Fix error handling for non-standard nodes Co-authored-by: Ben Hesseldieck <b.hesseldieck@gmail.com> Co-authored-by: Ben Hesseldieck <b.hesseldieck@gmail.com> Co-authored-by: Ben Hesseldieck <1849459+BHesseldieck@users.noreply.github.com>
2021-04-16 09:33:36 -07:00
NodeOperationError,
:sparkles: GoToWebinar node (#1422) * Create scaffolding for node * Add SVG logo * Create scaffolding for generic functions * Add index for descriptions * Simplify retrieval of details * Introduce minor fixes in generic functions * Add attendee description * Fix attendee description operation * Add coorganizer description * Add panelist description * Add registrant description * Add session description * Add webinar description * Register node and credentials * Add scaffolding for credentials * Minor creds fixes * Fix SVG icon size and position * Fix capitalization in description * Fix credentials connection * Add attendee fields * Populate webinar description * Remove organizer key from params * Add timezones array constant * Implement webinar:create * Implement webinar:delete * Convert times to fixed collection * Add missing segments to endpoints * Fix webinar:update operation * Implement all-items request * Add params for session:getAll * Add params for webinar:getAll * Implement session:getAll and webinar:getAll * Implement session:get and session:getDetails * Implement coorganizer:create * Implement coorganizer:delete * Implement coorganizer:getAll * Implement coorganizer:delete * Refactor time range for getAll operations * Implement coorganizer:reinvite * Implement panelist:create and panelist:getAll * Implement panelist:delete and panelist:reinvite * Remove array body helper types * Implement registrant:create and registrant:getAll * Implement registrant:delete * Prettify error handling * Add returnAll toggle and limit for all operations * Preload webinars * Preload webinar key in more fields * Refactor getAll as handler * Add descriptions for session * Add descriptions for attendee * Add descriptions for co-organizer * Add descriptions for panelist * Add descriptions for registrant * Add descriptions for webinar * Add 403 check for refresh token * Fix defaults for webinar loader * Add descriptions for webinar types * :zap: Improvements * Remove unneeded return type annotation * Add handler for continue on fail * Remove 403 check in error handler The Go To Webinar API returns 403 for a range of various errors, so this check ended up overriding more specific error messages not related to 403 Forbidden errors. * Remove logging * :zap: Small improvement * :zap: Minor improvements * :zap: Improvements * :zap: Minor improvements Co-authored-by: ricardo <ricardoespinoza105@gmail.com> Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
2021-02-21 23:49:00 -08:00
} from 'n8n-workflow';
import {
attendeeFields,
attendeeOperations,
coorganizerFields,
coorganizerOperations,
panelistFields,
panelistOperations,
registrantFields,
registrantOperations,
sessionFields,
sessionOperations,
webinarFields,
webinarOperations,
} from './descriptions';
import {
goToWebinarApiRequest,
goToWebinarApiRequestAllItems,
handleGetAll,
loadAnswers,
loadRegistranMultiChoiceQuestions,
loadRegistranSimpleQuestions,
loadWebinars,
loadWebinarSessions,
} from './GenericFunctions';
import {
isEmpty,
omit,
} from 'lodash';
import * as moment from 'moment-timezone';
export class GoToWebinar implements INodeType {
description: INodeTypeDescription = {
displayName: 'GoToWebinar',
2021-02-22 05:22:54 -08:00
name: 'goToWebinar',
:sparkles: GoToWebinar node (#1422) * Create scaffolding for node * Add SVG logo * Create scaffolding for generic functions * Add index for descriptions * Simplify retrieval of details * Introduce minor fixes in generic functions * Add attendee description * Fix attendee description operation * Add coorganizer description * Add panelist description * Add registrant description * Add session description * Add webinar description * Register node and credentials * Add scaffolding for credentials * Minor creds fixes * Fix SVG icon size and position * Fix capitalization in description * Fix credentials connection * Add attendee fields * Populate webinar description * Remove organizer key from params * Add timezones array constant * Implement webinar:create * Implement webinar:delete * Convert times to fixed collection * Add missing segments to endpoints * Fix webinar:update operation * Implement all-items request * Add params for session:getAll * Add params for webinar:getAll * Implement session:getAll and webinar:getAll * Implement session:get and session:getDetails * Implement coorganizer:create * Implement coorganizer:delete * Implement coorganizer:getAll * Implement coorganizer:delete * Refactor time range for getAll operations * Implement coorganizer:reinvite * Implement panelist:create and panelist:getAll * Implement panelist:delete and panelist:reinvite * Remove array body helper types * Implement registrant:create and registrant:getAll * Implement registrant:delete * Prettify error handling * Add returnAll toggle and limit for all operations * Preload webinars * Preload webinar key in more fields * Refactor getAll as handler * Add descriptions for session * Add descriptions for attendee * Add descriptions for co-organizer * Add descriptions for panelist * Add descriptions for registrant * Add descriptions for webinar * Add 403 check for refresh token * Fix defaults for webinar loader * Add descriptions for webinar types * :zap: Improvements * Remove unneeded return type annotation * Add handler for continue on fail * Remove 403 check in error handler The Go To Webinar API returns 403 for a range of various errors, so this check ended up overriding more specific error messages not related to 403 Forbidden errors. * Remove logging * :zap: Small improvement * :zap: Minor improvements * :zap: Improvements * :zap: Minor improvements Co-authored-by: ricardo <ricardoespinoza105@gmail.com> Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
2021-02-21 23:49:00 -08:00
icon: 'file:gotowebinar.svg',
group: ['transform'],
version: 1,
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
description: 'Consume the GoToWebinar API',
defaults: {
name: 'GoToWebinar',
color: '#0097e1',
},
inputs: ['main'],
outputs: ['main'],
credentials: [
{
name: 'goToWebinarOAuth2Api',
required: true,
},
],
properties: [
{
displayName: 'Resource',
name: 'resource',
type: 'options',
options: [
{
name: 'Attendee',
value: 'attendee',
},
{
name: 'Co-Organizer',
value: 'coorganizer',
},
{
name: 'Panelist',
value: 'panelist',
},
{
name: 'Registrant',
value: 'registrant',
},
{
name: 'Session',
value: 'session',
},
{
name: 'Webinar',
value: 'webinar',
},
],
default: 'attendee',
description: 'Resource to consume',
},
...attendeeOperations,
...attendeeFields,
...coorganizerOperations,
...coorganizerFields,
...panelistOperations,
...panelistFields,
...registrantOperations,
...registrantFields,
...sessionOperations,
...sessionFields,
...webinarOperations,
...webinarFields,
],
};
methods = {
loadOptions: {
async getWebinars(this: ILoadOptionsFunctions) {
return await loadWebinars.call(this);
},
async getAnswers(this: ILoadOptionsFunctions) {
return await loadAnswers.call(this);
},
async getWebinarSessions(this: ILoadOptionsFunctions) {
return await loadWebinarSessions.call(this);
},
// Get all the timezones to display them to user so that he can
// select them easily
async getTimezones(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
for (const timezone of moment.tz.names()) {
const timezoneName = timezone;
const timezoneId = timezone;
returnData.push({
name: timezoneName,
value: timezoneId,
});
}
return returnData;
},
async getRegistranSimpleQuestions(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
return await loadRegistranSimpleQuestions.call(this);
},
async getRegistranMultiChoiceQuestions(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
return await loadRegistranMultiChoiceQuestions.call(this);
},
},
};
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData();
const resource = this.getNodeParameter('resource', 0) as string;
const operation = this.getNodeParameter('operation', 0) as string;
let responseData;
const returnData: IDataObject[] = [];
const { oauthTokenData } = this.getCredentials('goToWebinarOAuth2Api') as {
oauthTokenData: { account_key: string, organizer_key: string }
};
const accountKey = oauthTokenData.account_key;
const organizerKey = oauthTokenData.organizer_key;
for (let i = 0; i < items.length; i++) {
try {
if (resource === 'attendee') {
// *********************************************************************
// attendee
// *********************************************************************
// https://developer.goto.com/GoToWebinarV2/#tag/Attendees
if (operation === 'get') {
// ----------------------------------
// attendee: get
// ----------------------------------
const webinarKey = this.getNodeParameter('webinarKey', i) as string;
const sessionKey = this.getNodeParameter('sessionKey', i) as string;
const registrantKey = this.getNodeParameter('registrantKey', i) as string;
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/sessions/${sessionKey}/attendees/${registrantKey}`;
responseData = await goToWebinarApiRequest.call(this, 'GET', endpoint, {}, {});
} else if (operation === 'getAll') {
// ----------------------------------
// attendee: getAll
// ----------------------------------
const webinarKey = this.getNodeParameter('webinarKey', i) as string;
const sessionKey = this.getNodeParameter('sessionKey', i) as string;
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/sessions/${sessionKey}/attendees`;
responseData = await handleGetAll.call(this, endpoint, {}, {}, resource);
} else if (operation === 'getDetails') {
// ----------------------------------
// attendee: getDetails
// ----------------------------------
const webinarKey = this.getNodeParameter('webinarKey', i) as string;
const sessionKey = this.getNodeParameter('sessionKey', i) as string;
const registrantKey = this.getNodeParameter('registrantKey', i) as string;
const details = this.getNodeParameter('details', i) as string;
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/sessions/${sessionKey}/attendees/${registrantKey}/${details}`;
responseData = await goToWebinarApiRequest.call(this, 'GET', endpoint, {}, {});
}
} else if (resource === 'coorganizer') {
// *********************************************************************
// coorganizer
// *********************************************************************
// https://developer.goto.com/GoToWebinarV2/#tag/Co-organizers
if (operation === 'create') {
// ----------------------------------
// coorganizer: create
// ----------------------------------
const webinarKey = this.getNodeParameter('webinarKey', i) as string;
const body = {
external: this.getNodeParameter('isExternal', i) as boolean,
} as IDataObject;
if (body.external === false) {
body.organizerKey = this.getNodeParameter('organizerKey', i) as string;
}
if (body.external === true) {
body.givenName = this.getNodeParameter('givenName', i) as string;
body.email = this.getNodeParameter('email', i) as string;
}
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/coorganizers`;
responseData = await goToWebinarApiRequest.call(this, 'POST', endpoint, {}, [body]);
} else if (operation === 'delete') {
// ----------------------------------
// coorganizer: delete
// ----------------------------------
const webinarKey = this.getNodeParameter('webinarKey', i) as string;
const coorganizerKey = this.getNodeParameter('coorganizerKey', i) as string;
const qs = {
external: this.getNodeParameter('isExternal', i) as boolean,
};
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/coorganizers/${coorganizerKey}`;
responseData = await goToWebinarApiRequest.call(this, 'DELETE', endpoint, qs, {});
responseData = { success: true };
} else if (operation === 'getAll') {
// ----------------------------------
// coorganizer: getAll
// ----------------------------------
const webinarKey = this.getNodeParameter('webinarKey', i) as string;
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/coorganizers`;
responseData = await handleGetAll.call(this, endpoint, {}, {}, resource);
} else if (operation === 'reinvite') {
// ----------------------------------
// coorganizer: reinvite
// ----------------------------------
const webinarKey = this.getNodeParameter('webinarKey', i) as string;
const coorganizerKey = this.getNodeParameter('coorganizerKey', i) as string;
const qs = {
external: this.getNodeParameter('isExternal', i) as boolean,
};
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/coorganizers/${coorganizerKey}/resendInvitation`;
responseData = await goToWebinarApiRequest.call(this, 'POST', endpoint, qs, {});
responseData = { success: true };
}
} else if (resource === 'panelist') {
// *********************************************************************
// panelist
// *********************************************************************
// https://developer.goto.com/GoToWebinarV2/#tag/Panelists
if (operation === 'create') {
// ----------------------------------
// panelist: create
// ----------------------------------
const webinarKey = this.getNodeParameter('webinarKey', i) as string;
const body = [
{
name: this.getNodeParameter('name', i) as string,
email: this.getNodeParameter('email', i) as string,
},
] as IDataObject[];
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/panelists`;
responseData = await goToWebinarApiRequest.call(this, 'POST', endpoint, {}, body);
} else if (operation === 'delete') {
// ----------------------------------
// panelist: delete
// ----------------------------------
const webinarKey = this.getNodeParameter('webinarKey', i) as string;
const panelistKey = this.getNodeParameter('panelistKey', i) as string;
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/panelists/${panelistKey}`;
responseData = await goToWebinarApiRequest.call(this, 'DELETE', endpoint, {}, {});
responseData = { success: true };
} else if (operation === 'getAll') {
// ----------------------------------
// panelist: getAll
// ----------------------------------
const webinarKey = this.getNodeParameter('webinarKey', i) as string;
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/panelists`;
responseData = await handleGetAll.call(this, endpoint, {}, {}, resource);
} else if (operation === 'reinvite') {
// ----------------------------------
// panelist: reinvite
// ----------------------------------
const webinarKey = this.getNodeParameter('webinarKey', i) as string;
const panelistKey = this.getNodeParameter('panelistKey', i) as string;
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/panelists/${panelistKey}/resendInvitation`;
responseData = await goToWebinarApiRequest.call(this, 'POST', endpoint, {}, {});
responseData = { success: true };
}
} else if (resource === 'registrant') {
// *********************************************************************
// registrant
// *********************************************************************
// https://developer.goto.com/GoToWebinarV2/#tag/Registrants
if (operation === 'create') {
// ----------------------------------
// registrant: create
// ----------------------------------
const webinarKey = this.getNodeParameter('webinarKey', i) as string;
const qs = {} as IDataObject;
const body = {
firstName: this.getNodeParameter('firstName', i) as string,
lastName: this.getNodeParameter('lastName', i) as string,
email: this.getNodeParameter('email', i) as string,
responses: [],
} as IDataObject;
let additionalFields = this.getNodeParameter('additionalFields', i) as Partial<{
resendConfirmation: boolean,
fullAddress: {
details: { [key: string]: string }
}
simpleResponses: [
{ [key: string]: string }
],
multiChoiceResponses: [
{ [key: string]: string }
],
}>;
if (additionalFields.resendConfirmation) {
qs.resendConfirmation = additionalFields.resendConfirmation;
additionalFields = omit(additionalFields, ['resendConfirmation']);
}
if (additionalFields.fullAddress) {
Object.assign(body, additionalFields.fullAddress.details);
additionalFields = omit(additionalFields, ['fullAddress']);
}
if (additionalFields.simpleResponses) {
//@ts-ignore
body.responses.push(...additionalFields.simpleResponses.details);
additionalFields = omit(additionalFields, ['simpleResponses']);
}
if (additionalFields.multiChoiceResponses) {
//@ts-ignore
body.responses.push(...additionalFields.multiChoiceResponses.details);
additionalFields = omit(additionalFields, ['multiChoiceResponses']);
}
Object.assign(body, additionalFields);
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/registrants`;
responseData = await goToWebinarApiRequest.call(this, 'POST', endpoint, qs, body);
} else if (operation === 'delete') {
// ----------------------------------
// registrant: delete
// ----------------------------------
const webinarKey = this.getNodeParameter('webinarKey', i) as string;
const registrantKey = this.getNodeParameter('registrantKey', i) as string;
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/registrants/${registrantKey}`;
responseData = await goToWebinarApiRequest.call(this, 'DELETE', endpoint, {}, {});
responseData = { success: true };
} else if (operation === 'get') {
// ----------------------------------
// registrant: get
// ----------------------------------
const webinarKey = this.getNodeParameter('webinarKey', i) as string;
const registrantKey = this.getNodeParameter('registrantKey', i) as string;
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/registrants/${registrantKey}`;
responseData = await goToWebinarApiRequest.call(this, 'GET', endpoint, {}, {});
} else if (operation === 'getAll') {
// ----------------------------------
// registrant: getAll
// ----------------------------------
const webinarKey = this.getNodeParameter('webinarKey', i) as string;
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/registrants`;
responseData = await handleGetAll.call(this, endpoint, {}, {}, resource);
}
} else if (resource === 'session') {
// *********************************************************************
// session
// *********************************************************************
// https://developer.goto.com/GoToWebinarV2/#tag/Sessions
if (operation === 'get') {
// ----------------------------------
// session: get
// ----------------------------------
const webinarKey = this.getNodeParameter('webinarKey', i) as string;
const sessionKey = this.getNodeParameter('sessionKey', i) as string;
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/sessions/${sessionKey}`;
responseData = await goToWebinarApiRequest.call(this, 'GET', endpoint, {}, {});
} else if (operation === 'getAll') {
// ----------------------------------
// session: getAll
// ----------------------------------
const qs = {} as IDataObject;
const returnAll = this.getNodeParameter('returnAll', 0) as boolean;
if (!returnAll) {
qs.limit = this.getNodeParameter('limit', 0) as number;
}
const {
webinarKey,
times,
} = this.getNodeParameter('additionalFields', i) as {
filterByWebinar: boolean,
webinarKey: string,
times: {
timesProperties: { [key: string]: string }
}
};
if (times) {
qs.fromTime = moment(times.timesProperties.fromTime).format();
qs.toTime = moment(times.timesProperties.toTime).format();
} else {
qs.fromTime = moment().subtract(1, 'years').format();
qs.toTime = moment().format();
}
if (webinarKey !== undefined) {
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/sessions`;
responseData = await goToWebinarApiRequestAllItems.call(this, 'GET', endpoint, qs, {}, resource);
} else {
const endpoint = `organizers/${organizerKey}/sessions`;
responseData = await goToWebinarApiRequestAllItems.call(this, 'GET', endpoint, qs, {}, resource);
}
} else if (operation === 'getDetails') {
// ----------------------------------
// session: getDetails
// ----------------------------------
const webinarKey = this.getNodeParameter('webinarKey', i) as string;
const sessionKey = this.getNodeParameter('sessionKey', i) as string;
const details = this.getNodeParameter('details', i) as string;
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/sessions/${sessionKey}/${details}`;
responseData = await goToWebinarApiRequest.call(this, 'GET', endpoint, {}, {});
}
} else if (resource === 'webinar') {
// *********************************************************************
// webinar
// *********************************************************************
// https://developer.goto.com/GoToWebinarV2/#tag/Webinars
if (operation === 'create') {
// ----------------------------------
// webinar: create
// ----------------------------------
const timesProperties = this.getNodeParameter('times.timesProperties', i, []) as IDataObject;
const body = {
subject: this.getNodeParameter('subject', i) as string,
times: timesProperties,
} as IDataObject;
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
Object.assign(body, additionalFields);
const endpoint = `organizers/${organizerKey}/webinars`;
responseData = await goToWebinarApiRequest.call(this, 'POST', endpoint, {}, body);
} else if (operation === 'delete') {
// ----------------------------------
// webinar: delete
// ----------------------------------
const webinarKey = this.getNodeParameter('webinarKey', i) as string;
const { sendCancellationEmails } = this.getNodeParameter('additionalFields', i) as IDataObject;
const qs = {} as IDataObject;
if (sendCancellationEmails) {
qs.sendCancellationEmails = sendCancellationEmails;
}
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}`;
await goToWebinarApiRequest.call(this, 'DELETE', endpoint, qs, {});
responseData = { success: true };
} else if (operation === 'get') {
// ----------------------------------
// webinar: get
// ----------------------------------
const webinarKey = this.getNodeParameter('webinarKey', i) as string;
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}`;
responseData = await goToWebinarApiRequest.call(this, 'GET', endpoint, {}, {});
} else if (operation === 'getAll') {
// ----------------------------------
// webinar: getAll
// ----------------------------------
const qs = {} as IDataObject;
const returnAll = this.getNodeParameter('returnAll', 0) as boolean;
if (!returnAll) {
qs.limit = this.getNodeParameter('limit', 0) as number;
}
const { times } = this.getNodeParameter('additionalFields', i) as {
times: {
timesProperties: { [key: string]: string }
}
};
if (times) {
qs.fromTime = moment(times.timesProperties.fromTime).format();
qs.toTime = moment(times.timesProperties.toTime).format();
} else {
qs.fromTime = moment().subtract(1, 'years').format();
qs.toTime = moment().format();
}
const endpoint = `accounts/${accountKey}/webinars`;
responseData = await goToWebinarApiRequestAllItems.call(this, 'GET', endpoint, qs, {}, resource);
} else if (operation === 'update') {
// ----------------------------------
// webinar: update
// ----------------------------------
const webinarKey = this.getNodeParameter('webinarKey', i) as string;
const qs = {
notifyParticipants: this.getNodeParameter('notifyParticipants', i) as boolean,
} as IDataObject;
let body = {};
let updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
if (updateFields.times) {
const { times } = updateFields as {
times: { timesProperties: Array<{ startTime: string, endTime: string }> }
};
body = {
times: times.timesProperties,
} as IDataObject;
updateFields = omit(updateFields, ['times']);
}
Object.assign(body, updateFields);
if (isEmpty(updateFields)) {
:sparkles: Improve node error handling (#1309) * Add path mapping and response error interfaces * Add error handling and throwing functionality * Refactor error handling into a single function * Re-implement error handling in Hacker News node * Fix linting details * Re-implement error handling in Spotify node * Re-implement error handling in G Suite Admin node * :construction: create basic setup NodeError * :construction: add httpCodes * :construction: add path priolist * :construction: handle statusCode in error, adjust interfaces * :construction: fixing type issues w/Ivan * :construction: add error exploration * 👔 fix linter issues * :wrench: improve object check * :construction: remove path passing from NodeApiError * :construction: add multi error + refactor findProperty method * 👔 allow any * :wrench: handle multi error message callback * :zap: change return type of callback * :zap: add customCallback to MultiError * :construction: refactor to use INode * :hammer: handle arrays, continue search after first null property found * 🚫 refactor method access * :construction: setup NodeErrorView * :zap: change timestamp to Date.now * :books: Add documentation for methods and constants * :construction: change message setting * 🚚 move NodeErrors to workflow * :sparkles: add new ErrorView for Nodes * :art: improve error notification * :art: refactor interfaces * :zap: add WorkflowOperationError, refactor error throwing * 👕 fix linter issues * :art: rename param * :bug: fix handling normal errors * :zap: add usage of NodeApiError * :art: fix throw new error instead of constructor * :art: remove unnecessary code/comments * :art: adjusted spacing + updated status messages * :art: fix tab indentation * ✨ Replace current errors with custom errors (#1576) * :zap: Introduce NodeApiError in catch blocks * :zap: Introduce NodeOperationError in nodes * :zap: Add missing errors and remove incompatible * :zap: Fix NodeOperationError in incompatible nodes * :wrench: Adjust error handling in missed nodes PayPal, FileMaker, Reddit, Taiga and Facebook Graph API nodes * :hammer: Adjust Strava Trigger node error handling * :hammer: Adjust AWS nodes error handling * :hammer: Remove duplicate instantiation of NodeApiError * :bug: fix strava trigger node error handling * Add XML parsing to NodeApiError constructor (#1633) * :bug: Remove type annotation from catch variable * :sparkles: Add XML parsing to NodeApiError * :zap: Simplify error handling in Rekognition node * :zap: Pass in XML flag in generic functions * :fire: Remove try/catch wrappers at call sites * :hammer: Refactor setting description from XML * :hammer: Refactor let to const in resource loaders * :zap: Find property in parsed XML * :zap: Change let to const * :fire: Remove unneeded try/catch block * :shirt: Fix linting issues * :bug: Fix errors from merge conflict resolution * :zap: Add custom errors to latest contributions * :shirt: Fix linting issues * :zap: Refactor MongoDB helpers for custom errors * :bug: Correct custom error type * :zap: Apply feedback to A nodes * :zap: Apply feedback to missed A node * :zap: Apply feedback to B-D nodes * :zap: Apply feedback to E-F nodes * :zap: Apply feedback to G nodes * :zap: Apply feedback to H-L nodes * :zap: Apply feedback to M nodes * :zap: Apply feedback to P nodes * :zap: Apply feedback to R nodes * :zap: Apply feedback to S nodes * :zap: Apply feedback to T nodes * :zap: Apply feedback to V-Z nodes * :zap: Add HTTP code to iterable node error * :hammer: Standardize e as error * :hammer: Standardize err as error * :zap: Fix error handling for non-standard nodes Co-authored-by: Ben Hesseldieck <b.hesseldieck@gmail.com> Co-authored-by: Ben Hesseldieck <b.hesseldieck@gmail.com> Co-authored-by: Ben Hesseldieck <1849459+BHesseldieck@users.noreply.github.com>
2021-04-16 09:33:36 -07:00
throw new NodeOperationError(this.getNode(), `Please enter at least one field to update for the ${resource}.`);
:sparkles: GoToWebinar node (#1422) * Create scaffolding for node * Add SVG logo * Create scaffolding for generic functions * Add index for descriptions * Simplify retrieval of details * Introduce minor fixes in generic functions * Add attendee description * Fix attendee description operation * Add coorganizer description * Add panelist description * Add registrant description * Add session description * Add webinar description * Register node and credentials * Add scaffolding for credentials * Minor creds fixes * Fix SVG icon size and position * Fix capitalization in description * Fix credentials connection * Add attendee fields * Populate webinar description * Remove organizer key from params * Add timezones array constant * Implement webinar:create * Implement webinar:delete * Convert times to fixed collection * Add missing segments to endpoints * Fix webinar:update operation * Implement all-items request * Add params for session:getAll * Add params for webinar:getAll * Implement session:getAll and webinar:getAll * Implement session:get and session:getDetails * Implement coorganizer:create * Implement coorganizer:delete * Implement coorganizer:getAll * Implement coorganizer:delete * Refactor time range for getAll operations * Implement coorganizer:reinvite * Implement panelist:create and panelist:getAll * Implement panelist:delete and panelist:reinvite * Remove array body helper types * Implement registrant:create and registrant:getAll * Implement registrant:delete * Prettify error handling * Add returnAll toggle and limit for all operations * Preload webinars * Preload webinar key in more fields * Refactor getAll as handler * Add descriptions for session * Add descriptions for attendee * Add descriptions for co-organizer * Add descriptions for panelist * Add descriptions for registrant * Add descriptions for webinar * Add 403 check for refresh token * Fix defaults for webinar loader * Add descriptions for webinar types * :zap: Improvements * Remove unneeded return type annotation * Add handler for continue on fail * Remove 403 check in error handler The Go To Webinar API returns 403 for a range of various errors, so this check ended up overriding more specific error messages not related to 403 Forbidden errors. * Remove logging * :zap: Small improvement * :zap: Minor improvements * :zap: Improvements * :zap: Minor improvements Co-authored-by: ricardo <ricardoespinoza105@gmail.com> Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
2021-02-21 23:49:00 -08:00
}
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}`;
await goToWebinarApiRequest.call(this, 'PUT', endpoint, qs, body);
responseData = { success: true };
}
}
} catch (error) {
if (this.continueOnFail()) {
returnData.push({ error: error.message });
continue;
}
throw error;
}
Array.isArray(responseData)
? returnData.push(...responseData)
: returnData.push(responseData);
}
return [this.helpers.returnJsonArray(returnData)];
}
}