Add Activepieces integration for workflow automation
- Add Activepieces fork with SmoothSchedule custom piece - Create integrations app with Activepieces service layer - Add embed token endpoint for iframe integration - Create Automations page with embedded workflow builder - Add sidebar visibility fix for embed mode - Add list inactive customers endpoint to Public API - Include SmoothSchedule triggers: event created/updated/cancelled - Include SmoothSchedule actions: create/update/cancel events, list resources/services/customers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
import {
|
||||
HttpRequest,
|
||||
HttpMethod,
|
||||
AuthenticationType,
|
||||
httpClient,
|
||||
} from '@activepieces/pieces-common';
|
||||
import { RegistrationResponse } from '../common/models';
|
||||
import { getRegistarantProps } from '../common/props';
|
||||
import { zoomAuth } from '../..';
|
||||
|
||||
export const zoomCreateMeetingRegistrant = createAction({
|
||||
auth: zoomAuth,
|
||||
name: 'zoom_create_meeting_registrant',
|
||||
displayName: 'Create Zoom Meeting Registrant',
|
||||
description: "Create and submit a user's registration to a meeting.",
|
||||
props: getRegistarantProps(),
|
||||
async run(context) {
|
||||
const body: Record<string, unknown> = {
|
||||
first_name: context.propsValue.first_name,
|
||||
last_name: context.propsValue.last_name,
|
||||
email: context.propsValue.email,
|
||||
address: context.propsValue.address,
|
||||
city: context.propsValue.city,
|
||||
state: context.propsValue.state,
|
||||
zip: context.propsValue.zip,
|
||||
country: context.propsValue.country,
|
||||
phone: context.propsValue.phone,
|
||||
comments: context.propsValue.comments,
|
||||
industry: context.propsValue.industry,
|
||||
job_title: context.propsValue.job_title,
|
||||
no_of_employees: context.propsValue.no_of_employees,
|
||||
org: context.propsValue.org,
|
||||
purchasing_time_frame: context.propsValue.purchasing_time_frame,
|
||||
role_in_purchase_process: context.propsValue.role_in_purchase_process,
|
||||
};
|
||||
|
||||
if (
|
||||
context.propsValue.custom_questions &&
|
||||
Object.keys(context.propsValue.custom_questions).length > 0
|
||||
) {
|
||||
body.custom_questions = Object.entries(
|
||||
context.propsValue.custom_questions
|
||||
).map(([key, value]) => ({ title: key, value: value }));
|
||||
}
|
||||
|
||||
const request: HttpRequest = {
|
||||
method: HttpMethod.POST,
|
||||
url: `https://api.zoom.us/v2/meetings/${context.propsValue.meeting_id}/registrants`,
|
||||
body,
|
||||
authentication: {
|
||||
type: AuthenticationType.BEARER_TOKEN,
|
||||
token: context.auth.access_token,
|
||||
},
|
||||
queryParams: {},
|
||||
};
|
||||
|
||||
const result = await httpClient.sendRequest<RegistrationResponse>(request);
|
||||
console.debug('Meeting registration response', result);
|
||||
|
||||
if (result.status === 201) {
|
||||
return result.body;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,155 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import {
|
||||
HttpRequest,
|
||||
HttpMethod,
|
||||
AuthenticationType,
|
||||
httpClient,
|
||||
} from '@activepieces/pieces-common';
|
||||
import { MeetingMessageBody, MeetingResponseBody } from '../common/models';
|
||||
import { zoomAuth } from '../..';
|
||||
|
||||
const defaults = {
|
||||
agenda: 'My Meeting',
|
||||
default_password: false,
|
||||
duration: 30,
|
||||
pre_schedule: false,
|
||||
|
||||
settings: {
|
||||
allow_multiple_devices: true,
|
||||
approval_type: 2,
|
||||
audio: 'telephony',
|
||||
|
||||
calendar_type: 1,
|
||||
close_registration: false,
|
||||
|
||||
email_notification: true,
|
||||
host_video: true,
|
||||
join_before_host: false,
|
||||
meeting_authentication: true,
|
||||
mute_upon_entry: false,
|
||||
participant_video: false,
|
||||
private_meeting: false,
|
||||
registrants_confirmation_email: true,
|
||||
registrants_email_notification: true,
|
||||
registration_type: 1,
|
||||
show_share_button: true,
|
||||
host_save_video_order: true,
|
||||
},
|
||||
|
||||
timezone: 'UTC',
|
||||
type: 2,
|
||||
};
|
||||
|
||||
const action = () => {
|
||||
return createAction({
|
||||
auth: zoomAuth,
|
||||
name: 'zoom_create_meeting', // Must be a unique across the piece, this shouldn't be changed.
|
||||
displayName: 'Create Zoom Meeting',
|
||||
description: 'Create a new Zoom Meeting',
|
||||
props: {
|
||||
topic: Property.ShortText({
|
||||
displayName: "Meeting's topic",
|
||||
description: "The meeting's topic",
|
||||
required: true,
|
||||
}),
|
||||
start_time: Property.ShortText({
|
||||
displayName: 'Start Time',
|
||||
description: 'Meeting start date-time',
|
||||
required: false,
|
||||
}),
|
||||
duration: Property.Number({
|
||||
displayName: 'Duration (in Minutes)',
|
||||
description: 'Duration of the meeting',
|
||||
required: false,
|
||||
}),
|
||||
auto_recording: Property.StaticDropdown({
|
||||
displayName: 'Auto Recording',
|
||||
required: false,
|
||||
options: {
|
||||
disabled: false,
|
||||
options: [
|
||||
{ label: 'Local', value: 'local' },
|
||||
{ label: 'Cloud', value: 'cloud' },
|
||||
{ label: 'None', value: 'none' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
audio: Property.StaticDropdown({
|
||||
displayName: 'Audio',
|
||||
required: false,
|
||||
options: {
|
||||
disabled: false,
|
||||
options: [
|
||||
{ label: 'Both telephony and VoIP', value: 'both' },
|
||||
{ label: 'Telephony only', value: 'telephony' },
|
||||
{ label: 'VoIP only', value: 'voip' },
|
||||
{ label: 'Third party audio conference', value: 'thirdParty' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
agenda: Property.LongText({
|
||||
displayName: 'Agenda',
|
||||
description: "The meeting's agenda",
|
||||
required: false,
|
||||
}),
|
||||
password: Property.ShortText({
|
||||
displayName: 'Password',
|
||||
description:
|
||||
'The password required to join the meeting. By default, a password can only have a maximum length of 10 characters and only contain alphanumeric characters and the @, -, _, and * characters.',
|
||||
required: false,
|
||||
}),
|
||||
pre_schedule: Property.Checkbox({
|
||||
displayName: 'Pre Schedule',
|
||||
description:
|
||||
'Whether the prescheduled meeting was created via the GSuite app.',
|
||||
required: false,
|
||||
}),
|
||||
schedule_for: Property.ShortText({
|
||||
displayName: 'Schedule for',
|
||||
description:
|
||||
'The email address or user ID of the user to schedule a meeting for.',
|
||||
required: false,
|
||||
}),
|
||||
join_url: Property.LongText({
|
||||
displayName: 'Join URL',
|
||||
description: 'URL for participants to join the meeting.',
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const body: MeetingMessageBody = {
|
||||
...defaults,
|
||||
...context.propsValue,
|
||||
};
|
||||
|
||||
if (context.propsValue.auto_recording) {
|
||||
body.settings.auto_recording = context.propsValue.auto_recording;
|
||||
}
|
||||
|
||||
if (context.propsValue.audio) {
|
||||
body.settings.audio = context.propsValue.audio;
|
||||
}
|
||||
delete body['auth'];
|
||||
const request: HttpRequest<MeetingMessageBody> = {
|
||||
method: HttpMethod.POST,
|
||||
url: `https://api.zoom.us/v2/users/me/meetings`,
|
||||
body: body,
|
||||
authentication: {
|
||||
type: AuthenticationType.BEARER_TOKEN,
|
||||
token: context.auth.access_token,
|
||||
},
|
||||
queryParams: {},
|
||||
};
|
||||
|
||||
const result = await httpClient.sendRequest<MeetingResponseBody>(request);
|
||||
|
||||
if (result.status === 201) {
|
||||
return result.body;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const zoomCreateMeeting = action();
|
||||
@@ -0,0 +1,252 @@
|
||||
import { HttpMessageBody } from '@activepieces/pieces-common';
|
||||
|
||||
export interface MeetingRegistrant {
|
||||
first_name: string;
|
||||
last_name?: string;
|
||||
email: string;
|
||||
address?: string;
|
||||
city?: string;
|
||||
state?: string;
|
||||
zip?: string;
|
||||
country?: string;
|
||||
phone?: string;
|
||||
comments?: string;
|
||||
custom_questions?: {
|
||||
title: string;
|
||||
value: string;
|
||||
}[];
|
||||
industry?: string;
|
||||
job_title?: string;
|
||||
no_of_employees?: string;
|
||||
org?: string;
|
||||
purchasing_time_frame?: string;
|
||||
role_in_purchase_process?: string;
|
||||
language?: string;
|
||||
auto_approve?: boolean;
|
||||
}
|
||||
|
||||
export interface RegistrationResponse extends HttpMessageBody {
|
||||
id: number;
|
||||
join_url: string;
|
||||
registrant_id: string;
|
||||
start_time: string;
|
||||
topic: string;
|
||||
occurrences: {
|
||||
duration: number;
|
||||
occurrence_id: string;
|
||||
start_time: string;
|
||||
status: string;
|
||||
}[];
|
||||
participant_pin_code: number;
|
||||
}
|
||||
|
||||
export interface MeetingResponseBody extends HttpMessageBody {
|
||||
id?: number;
|
||||
assistant_id?: string;
|
||||
host_email?: string;
|
||||
registration_url?: string;
|
||||
agenda?: string;
|
||||
created_at?: string;
|
||||
duration?: number;
|
||||
join_url?: string;
|
||||
occurrences?: {
|
||||
duration?: number;
|
||||
occurrence_id?: string;
|
||||
start_time?: string;
|
||||
status?: string;
|
||||
}[];
|
||||
password?: string;
|
||||
pmi?: string;
|
||||
pre_schedule?: boolean;
|
||||
recurrence?: {
|
||||
end_date_time?: string;
|
||||
end_times?: number;
|
||||
monthly_day?: number;
|
||||
monthly_week?: number;
|
||||
monthly_week_day?: number;
|
||||
repeat_interval?: number;
|
||||
type: number;
|
||||
weekly_days?: string;
|
||||
};
|
||||
settings: {
|
||||
allow_multiple_devices: boolean;
|
||||
alternative_hosts: number;
|
||||
alternative_hosts_email_notification: boolean;
|
||||
alternative_host_update_polls: boolean;
|
||||
approval_type: number;
|
||||
approved_or_denied_countries_or_regions: {
|
||||
approved_list: string[];
|
||||
denied_list: string[];
|
||||
enable: boolean;
|
||||
method: string;
|
||||
};
|
||||
audio: string;
|
||||
authentication_domains: string;
|
||||
authentication_exception: {
|
||||
email: string;
|
||||
name: string;
|
||||
join_url: string;
|
||||
}[];
|
||||
authentication_name: string;
|
||||
authentication_option: string;
|
||||
auto_recording: string;
|
||||
breakout_room: {
|
||||
enable: boolean;
|
||||
rooms: {
|
||||
name: string;
|
||||
participants: string[];
|
||||
}[];
|
||||
};
|
||||
calendar_type: number;
|
||||
close_registration: boolean;
|
||||
contact_email: string;
|
||||
contact_name: string;
|
||||
custom_keys: {
|
||||
key: string;
|
||||
value: string;
|
||||
}[];
|
||||
email_notification: boolean;
|
||||
encryption_type: string;
|
||||
focus_mode: boolean;
|
||||
global_dial_in_countries: string[];
|
||||
global_dial_in_numbers: {
|
||||
city: string;
|
||||
country: string;
|
||||
country_name: string;
|
||||
number: string;
|
||||
type: string;
|
||||
}[];
|
||||
host_video: boolean;
|
||||
jbh_time: number;
|
||||
join_before_host: boolean;
|
||||
language_interpretation: {
|
||||
enable: boolean;
|
||||
interpreters: {
|
||||
email: string;
|
||||
languages: string;
|
||||
}[];
|
||||
};
|
||||
meeting_authentication: boolean;
|
||||
mute_upon_entry: boolean;
|
||||
participant_video: boolean;
|
||||
private_meeting: boolean;
|
||||
registrants_confirmation_email: boolean;
|
||||
registrants_email_notification: boolean;
|
||||
registration_type: number;
|
||||
show_share_button: boolean;
|
||||
use_pmi: boolean;
|
||||
waiting_room: boolean;
|
||||
watermark: boolean;
|
||||
host_save_video_order: boolean;
|
||||
};
|
||||
|
||||
start_time: string;
|
||||
start_url: string;
|
||||
timezone: string;
|
||||
topic: string;
|
||||
type: number;
|
||||
tracking_fields: {
|
||||
field: string;
|
||||
value: string;
|
||||
visible: boolean;
|
||||
}[];
|
||||
}
|
||||
|
||||
export interface MeetingMessageBody extends HttpMessageBody {
|
||||
agenda?: string;
|
||||
password?: string;
|
||||
duration?: number;
|
||||
pre_schedule?: boolean;
|
||||
recurrence?: {
|
||||
end_date_time: string;
|
||||
end_times: number;
|
||||
monthly_day: number;
|
||||
monthly_week: number;
|
||||
monthly_week_day: number;
|
||||
repeat_interval: number;
|
||||
type: number;
|
||||
weekly_days: string;
|
||||
};
|
||||
settings: {
|
||||
allow_multiple_devices?: boolean;
|
||||
alternative_hosts?: number;
|
||||
alternative_hosts_email_notification?: boolean;
|
||||
alternative_host_update_polls?: boolean;
|
||||
approval_type?: number;
|
||||
approved_or_denied_countries_or_regions?: {
|
||||
approved_list?: string[];
|
||||
denied_list?: string[];
|
||||
enable?: boolean;
|
||||
method?: string;
|
||||
};
|
||||
audio?: string;
|
||||
authentication_domains?: string;
|
||||
authentication_exception?: {
|
||||
email?: string;
|
||||
name?: string;
|
||||
join_url?: string;
|
||||
}[];
|
||||
authentication_name?: string;
|
||||
authentication_option?: string;
|
||||
auto_recording?: string;
|
||||
breakout_room?: {
|
||||
enable?: boolean;
|
||||
rooms?: {
|
||||
name: string;
|
||||
participants: string[];
|
||||
}[];
|
||||
};
|
||||
calendar_type?: number;
|
||||
close_registration?: boolean;
|
||||
contact_email?: string;
|
||||
contact_name?: string;
|
||||
custom_keys?: {
|
||||
key?: string;
|
||||
value?: string;
|
||||
}[];
|
||||
email_notification?: boolean;
|
||||
encryption_type?: string;
|
||||
focus_mode?: boolean;
|
||||
global_dial_in_countries?: string[];
|
||||
global_dial_in_numbers?: {
|
||||
city?: string;
|
||||
country?: string;
|
||||
country_name?: string;
|
||||
number?: string;
|
||||
type?: string;
|
||||
}[];
|
||||
host_video?: boolean;
|
||||
jbh_time?: number;
|
||||
join_before_host?: boolean;
|
||||
language_interpretation?: {
|
||||
enable?: boolean;
|
||||
interpreters?: {
|
||||
email?: string;
|
||||
languages?: string;
|
||||
}[];
|
||||
};
|
||||
meeting_authentication?: boolean;
|
||||
mute_upon_entry?: boolean;
|
||||
participant_video?: boolean;
|
||||
private_meeting?: boolean;
|
||||
registrants_confirmation_email?: boolean;
|
||||
registrants_email_notification?: boolean;
|
||||
registration_type?: number;
|
||||
show_share_button?: boolean;
|
||||
use_pmi?: boolean;
|
||||
waiting_room?: boolean;
|
||||
watermark?: boolean;
|
||||
host_save_video_order?: boolean;
|
||||
};
|
||||
|
||||
start_time?: string;
|
||||
start_url?: string;
|
||||
timezone?: string;
|
||||
topic?: string;
|
||||
type?: number;
|
||||
tracking_fields?: {
|
||||
field: string;
|
||||
value?: string;
|
||||
visible?: boolean;
|
||||
}[];
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
import { Property } from '@activepieces/pieces-framework';
|
||||
|
||||
export const getRegistarantProps = () => ({
|
||||
meeting_id: Property.ShortText({
|
||||
displayName: 'Meeting ID',
|
||||
description: 'The meeting ID.',
|
||||
required: true,
|
||||
}),
|
||||
first_name: Property.ShortText({
|
||||
displayName: 'First name',
|
||||
description: "The registrant's first name.",
|
||||
required: true,
|
||||
}),
|
||||
last_name: Property.ShortText({
|
||||
displayName: 'Last name',
|
||||
description: "The registrant's last name.",
|
||||
required: false,
|
||||
}),
|
||||
email: Property.ShortText({
|
||||
displayName: 'Email',
|
||||
description: "The registrant's email address.",
|
||||
required: true,
|
||||
}),
|
||||
address: Property.ShortText({
|
||||
displayName: 'Address',
|
||||
description: "The registrant's address",
|
||||
required: false,
|
||||
}),
|
||||
city: Property.ShortText({
|
||||
displayName: 'City',
|
||||
description: "The registrant's city",
|
||||
required: false,
|
||||
}),
|
||||
state: Property.ShortText({
|
||||
displayName: 'State',
|
||||
description: "The registrant's state or province.",
|
||||
required: false,
|
||||
}),
|
||||
zip: Property.ShortText({
|
||||
displayName: 'Zip',
|
||||
description: "The registrant's zip or postal code.",
|
||||
required: false,
|
||||
}),
|
||||
country: Property.ShortText({
|
||||
displayName: 'Country',
|
||||
description: "The registrant's two-letter country code.",
|
||||
required: false,
|
||||
}),
|
||||
phone: Property.ShortText({
|
||||
displayName: 'Phone',
|
||||
description: "The registrant's phone number.",
|
||||
required: false,
|
||||
}),
|
||||
comments: Property.LongText({
|
||||
displayName: 'Comments',
|
||||
description: "The registrant's questions and comments.",
|
||||
required: false,
|
||||
}),
|
||||
custom_questions: Property.Object({
|
||||
displayName: 'Custom questions',
|
||||
description: '',
|
||||
required: false,
|
||||
}),
|
||||
industry: Property.ShortText({
|
||||
displayName: 'Industry',
|
||||
description: "The registrant's industry.",
|
||||
required: false,
|
||||
}),
|
||||
job_title: Property.ShortText({
|
||||
displayName: 'Job title',
|
||||
description: "The registrant's job title.",
|
||||
required: false,
|
||||
}),
|
||||
no_of_employees: Property.StaticDropdown({
|
||||
displayName: 'No of employees',
|
||||
description: "The registrant's number of employees.",
|
||||
required: false,
|
||||
options: {
|
||||
disabled: false,
|
||||
options: [
|
||||
{ label: '1-20', value: '1-20' },
|
||||
{ label: '21-50', value: '21-50' },
|
||||
{ label: '51-100', value: '51-100' },
|
||||
{ label: '101-500', value: '101-500' },
|
||||
{ label: '500-1,000', value: '500-1,000' },
|
||||
{ label: '1,001-5,000', value: '1,001-5,000' },
|
||||
{ label: '5,001-10,000', value: '5,001-10,000' },
|
||||
{ label: 'More than 10,000', value: 'More than 10,000' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
org: Property.ShortText({
|
||||
displayName: 'Organization',
|
||||
description: "The registrant's organization.",
|
||||
required: false,
|
||||
}),
|
||||
purchasing_time_frame: Property.StaticDropdown({
|
||||
displayName: 'Purchasing time frame',
|
||||
description: "The registrant's purchasing time frame.",
|
||||
required: false,
|
||||
options: {
|
||||
disabled: false,
|
||||
options: [
|
||||
{ label: 'Within a month', value: 'Within a month' },
|
||||
{ label: '1-3 months', value: '1-3 months' },
|
||||
{ label: '4-6 months', value: '4-6 months' },
|
||||
{ label: 'More than 6 months', value: 'More than 6 months' },
|
||||
{ label: 'No timeframe', value: 'No timeframe' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
role_in_purchase_process: Property.StaticDropdown({
|
||||
displayName: 'Role in purchase process',
|
||||
description: "The registrant's role in the purchase process.",
|
||||
required: false,
|
||||
options: {
|
||||
disabled: false,
|
||||
options: [
|
||||
{ label: 'Decision Maker', value: 'Decision Maker' },
|
||||
{ label: 'Evaluator/Recommender', value: 'Evaluator/Recommender' },
|
||||
{ label: 'Influencer', value: 'Influencer' },
|
||||
{ label: 'Not involved', value: 'Not involved' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
});
|
||||
Reference in New Issue
Block a user