diff --git a/flows.yaml b/flows.yaml index ea11ace4..ae168fb3 100644 --- a/flows.yaml +++ b/flows.yaml @@ -889,7 +889,40 @@ integrations: endpoint: GET /event/invitees output: EventInvitee description: For all events (active and canceled) retrieve the event invitees + users: + runs: every day + description: Fetches a list of users from Calendly + output: User + track_deletes: true + sync_type: full + endpoint: GET /users + actions: + create-user: + description: Creates a user in Calendly + endpoint: POST /users + output: User + input: CreateUser + scopes: + - admin + delete-user: + description: Deletes a user in Calendly + endpoint: DELETE /users + output: SuccessResponse + input: IdEntity + scopes: + - admin models: + IdEntity: + id: string + SuccessResponse: + success: boolean + User: + id: string + email: string + firstName: string + lastName: string + CreateUser: + email: string Event: id: string uri: string diff --git a/integrations/calendly/actions/create-user.ts b/integrations/calendly/actions/create-user.ts new file mode 100644 index 00000000..75acdbcb --- /dev/null +++ b/integrations/calendly/actions/create-user.ts @@ -0,0 +1,45 @@ +import type { NangoAction, ProxyConfiguration, User, CreateUser } from '../../models'; +import { getOrganizationId } from '../helpers/get-organizationId.js'; +import { createUserSchema } from '../schema.zod.js'; +import type { OrganizationInvitation } from '../types'; + +/** + * Executes the create user action by validating input, constructing the request configuration, + * and making the Calendly API call to invitate (create) a new user to an organization. + */ +export default async function runAction(nango: NangoAction, input: CreateUser): Promise { + const parsedInput = createUserSchema.safeParse(input); + + if (!parsedInput.success) { + for (const error of parsedInput.error.errors) { + await nango.log(`Invalid input provided to create a user: ${error.message} at path ${error.path.join('.')}`, { level: 'error' }); + } + + throw new nango.ActionError({ + message: 'Invalid input provided to create a user' + }); + } + + const organization = await getOrganizationId(nango); + + const config: ProxyConfiguration = { + // https://developer.calendly.com/api-docs/094d15d2cd4ab-invite-user-to-organization + endpoint: `/organizations/${organization.id}/invitations`, + data: { + email: parsedInput.data.email + }, + retries: 10 + }; + + const response = await nango.post<{ resource: OrganizationInvitation }>(config); + + const newUser = response.data.resource; + const user: User = { + id: newUser.uri.split('/').pop() ?? '', + firstName: '', + lastName: '', + email: newUser.email + }; + + return user; +} diff --git a/integrations/calendly/actions/delete-user.ts b/integrations/calendly/actions/delete-user.ts new file mode 100644 index 00000000..59765deb --- /dev/null +++ b/integrations/calendly/actions/delete-user.ts @@ -0,0 +1,32 @@ +import type { NangoAction, ProxyConfiguration, SuccessResponse, IdEntity } from '../../models'; +import { idEntitySchema } from '../schema.zod.js'; + +/** + * Executes the delete user action by validating input, constructing the endpoint, + * and making the API call to Calendly to delete the user from an organization. + */ +export default async function runAction(nango: NangoAction, input: IdEntity): Promise { + const parsedInput = idEntitySchema.safeParse(input); + + if (!parsedInput.success) { + for (const error of parsedInput.error.errors) { + await nango.log(`Invalid input provided to delete a user: ${error.message} at path ${error.path.join('.')}`, { level: 'error' }); + } + + throw new nango.ActionError({ + message: 'Invalid input provided to delete a user' + }); + } + + const config: ProxyConfiguration = { + // https://developer.calendly.com/api-docs/269e89d9f559f-remove-user-from-organization + endpoint: `/organization_memberships/${parsedInput.data.id}`, + retries: 10 + }; + + await nango.delete(config); + + return { + success: true + }; +} diff --git a/integrations/calendly/fixtures/create-user.json b/integrations/calendly/fixtures/create-user.json new file mode 100644 index 00000000..f4ca6440 --- /dev/null +++ b/integrations/calendly/fixtures/create-user.json @@ -0,0 +1,3 @@ +{ + "email": "john@doe.com" +} diff --git a/integrations/calendly/fixtures/delete-user.json b/integrations/calendly/fixtures/delete-user.json new file mode 100644 index 00000000..f8af9152 --- /dev/null +++ b/integrations/calendly/fixtures/delete-user.json @@ -0,0 +1,3 @@ +{ + "id": "HBADPPGMUEGYL6RY" +} diff --git a/integrations/calendly/helpers/get-organizationId.ts b/integrations/calendly/helpers/get-organizationId.ts new file mode 100644 index 00000000..d1cfd71b --- /dev/null +++ b/integrations/calendly/helpers/get-organizationId.ts @@ -0,0 +1,42 @@ +import type { NangoAction, NangoSync } from '../../models'; +import type { CalendlyCurrentUser } from '../types'; + +/** + * Retrieves the current organization id (uri and id) associated with the + * logged-in user from the Calendly API. + */ +export async function getOrganizationId(nango: NangoAction | NangoSync): Promise<{ uri: string; id: string }> { + const connection = await nango.getConnection(); + let organizationBaseUri = connection.connection_config['organizationId']; + + if (organizationBaseUri) return mapOrganizationId(organizationBaseUri); + + await nango.log(`No organization id found in the connection config. Attempting to get it from fetching it from the logged-in user`); + + const response = await nango.get<{ resource: CalendlyCurrentUser }>({ + // https://developer.calendly.com/api-docs/005832c83aeae-get-current-user + endpoint: '/users/me', + retries: 10 + }); + + if (!response.data) { + throw new nango.ActionError({ message: 'failed to get request info' }); + } + + organizationBaseUri = response.data.resource.current_organization; + + if (!organizationBaseUri) { + throw new nango.ActionError({ message: 'failed to get organization id' }); + } + + await nango.log(`Got organization id`); + + return mapOrganizationId(organizationBaseUri); +} + +function mapOrganizationId(organizationBaseUri: string): { uri: string; id: string } { + return { + id: organizationBaseUri.split('/').pop() ?? '', + uri: organizationBaseUri + }; +} diff --git a/integrations/calendly/mocks/nango/get/proxy/organization_memberships/users.json b/integrations/calendly/mocks/nango/get/proxy/organization_memberships/users.json new file mode 100644 index 00000000..3a2396b4 --- /dev/null +++ b/integrations/calendly/mocks/nango/get/proxy/organization_memberships/users.json @@ -0,0 +1,49 @@ +{ + "collection": [ + { + "created_at": "2024-07-08T07:48:15.158893Z", + "organization": "https://api.calendly.com/organizations/fe1dd514-15c3-48de-a662-1c5f76ba5402", + "role": "owner", + "updated_at": "2024-07-08T07:48:15.158893Z", + "uri": "https://api.calendly.com/organization_memberships/885176bb-4e76-4cc9-9cfc-3e42b3463274", + "user": { + "avatar_url": null, + "created_at": "2024-07-08T07:48:15.090124Z", + "email": "barry@some-email.com", + "locale": "en", + "name": "Brian Beautiful", + "timezone": "Europe/Berlin", + "updated_at": "2024-10-09T15:35:58.139120Z", + "uri": "https://api.calendly.com/users/e46e2d95-7782-4f5f-ba84-188f9fc8961c", + "scheduling_url": "https://calendly.com/barry-nango", + "slug": "barry-nango" + } + }, + { + "created_at": "2024-07-08T07:50:46.134244Z", + "organization": "https://api.calendly.com/organizations/fe1dd514-15c3-48de-a662-1c5f76ba5402", + "role": "user", + "updated_at": "2024-07-08T07:50:46.134244Z", + "uri": "https://api.calendly.com/organization_memberships/7cd308d1-3312-414f-adcb-89a2eb737a54", + "user": { + "avatar_url": null, + "created_at": "2023-05-12T06:26:32.342945Z", + "email": "john@some-email.com", + "locale": "en", + "name": "John Faked", + "timezone": "Asia/Jerusalem", + "updated_at": "2024-10-09T14:57:44.698577Z", + "uri": "https://api.calendly.com/users/abcdegggggg", + "scheduling_url": "https://calendly.com/john-doe-nango", + "slug": "john-doe-nango" + } + } + ], + "pagination": { + "count": 2, + "next_page": null, + "next_page_token": null, + "previous_page": null, + "previous_page_token": null + } +} diff --git a/integrations/calendly/mocks/nango/get/proxy/users/me/create-user.json b/integrations/calendly/mocks/nango/get/proxy/users/me/create-user.json new file mode 100644 index 00000000..412a19cf --- /dev/null +++ b/integrations/calendly/mocks/nango/get/proxy/users/me/create-user.json @@ -0,0 +1,16 @@ +{ + "resource": { + "avatar_url": null, + "created_at": "2023-05-12T06:26:32.342945Z", + "current_organization": "https://api.calendly.com/organizations/fe1dd514-15c3-48de-a662-1c5f76ba5402", + "email": "john@some-email.com", + "locale": "en", + "name": "John Faked", + "resource_type": "User", + "scheduling_url": "https://calendly.com/john-doe-nango", + "slug": "john-doe-nango", + "timezone": "Asia/Jerusalem", + "updated_at": "2024-10-09T14:57:44.698577Z", + "uri": "https://api.calendly.com/users/abcdegggggg" + } +} diff --git a/integrations/calendly/mocks/nango/get/proxy/users/me/users.json b/integrations/calendly/mocks/nango/get/proxy/users/me/users.json new file mode 100644 index 00000000..412a19cf --- /dev/null +++ b/integrations/calendly/mocks/nango/get/proxy/users/me/users.json @@ -0,0 +1,16 @@ +{ + "resource": { + "avatar_url": null, + "created_at": "2023-05-12T06:26:32.342945Z", + "current_organization": "https://api.calendly.com/organizations/fe1dd514-15c3-48de-a662-1c5f76ba5402", + "email": "john@some-email.com", + "locale": "en", + "name": "John Faked", + "resource_type": "User", + "scheduling_url": "https://calendly.com/john-doe-nango", + "slug": "john-doe-nango", + "timezone": "Asia/Jerusalem", + "updated_at": "2024-10-09T14:57:44.698577Z", + "uri": "https://api.calendly.com/users/abcdegggggg" + } +} diff --git a/integrations/calendly/mocks/nango/getConnection.json b/integrations/calendly/mocks/nango/getConnection.json index f0f23670..aa31144b 100644 --- a/integrations/calendly/mocks/nango/getConnection.json +++ b/integrations/calendly/mocks/nango/getConnection.json @@ -1,6 +1,6 @@ { "metadata": null, "connection_config": { - "owner": "https://api.calendly.com/users/111" + "owner": "https://api.calendly.com/users/abcdegggggg" } } diff --git a/integrations/calendly/mocks/users/User/batchDelete.json b/integrations/calendly/mocks/users/User/batchDelete.json new file mode 100644 index 00000000..fe51488c --- /dev/null +++ b/integrations/calendly/mocks/users/User/batchDelete.json @@ -0,0 +1 @@ +[] diff --git a/integrations/calendly/mocks/users/User/batchSave.json b/integrations/calendly/mocks/users/User/batchSave.json new file mode 100644 index 00000000..8de96663 --- /dev/null +++ b/integrations/calendly/mocks/users/User/batchSave.json @@ -0,0 +1,14 @@ +[ + { + "id": "e46e2d95-7782-4f5f-ba84-188f9fc8961c", + "email": "barry@some-email.com", + "firstName": "Brian", + "lastName": "Beautiful" + }, + { + "id": "abcdegggggg", + "email": "john@some-email.com", + "firstName": "John", + "lastName": "Faked" + } +] diff --git a/integrations/calendly/nango.yaml b/integrations/calendly/nango.yaml index 975a8d4f..7a74e244 100644 --- a/integrations/calendly/nango.yaml +++ b/integrations/calendly/nango.yaml @@ -19,8 +19,45 @@ integrations: endpoint: GET /event/invitees output: EventInvitee description: For all events (active and canceled) retrieve the event invitees + users: + runs: every day + description: Fetches a list of users from Calendly + output: User + track_deletes: true + sync_type: full + endpoint: GET /users + actions: + create-user: + description: Creates a user in Calendly + endpoint: POST /users + output: User + input: CreateUser + scopes: + - admin + delete-user: + description: Deletes a user in Calendly + endpoint: DELETE /users + output: SuccessResponse + input: IdEntity + scopes: + - admin models: + # Generic + IdEntity: + id: string + SuccessResponse: + success: boolean + + # Users + User: + id: string + email: string + firstName: string + lastName: string + CreateUser: + email: string + Event: id: string uri: string diff --git a/integrations/calendly/schema.zod.ts b/integrations/calendly/schema.zod.ts index cdb293c1..06468c60 100644 --- a/integrations/calendly/schema.zod.ts +++ b/integrations/calendly/schema.zod.ts @@ -1,6 +1,25 @@ // Generated by ts-to-zod import { z } from 'zod'; +export const idEntitySchema = z.object({ + id: z.string() +}); + +export const successResponseSchema = z.object({ + success: z.boolean() +}); + +export const userSchema = z.object({ + id: z.string(), + email: z.string(), + firstName: z.string(), + lastName: z.string() +}); + +export const createUserSchema = z.object({ + email: z.string() +}); + export const eventLocationSchema = z.object({ type: z.string(), location: z.string().optional(), diff --git a/integrations/calendly/syncs/users.ts b/integrations/calendly/syncs/users.ts new file mode 100644 index 00000000..4e166949 --- /dev/null +++ b/integrations/calendly/syncs/users.ts @@ -0,0 +1,52 @@ +import type { NangoSync, ProxyConfiguration, User } from '../../models'; +import { getOrganizationId } from '../helpers/get-organizationId.js'; +import type { CalendlyOrganizationMember } from '../types'; + +/** + * Fetches user data from the Calendly API and saves it in batches. + */ +export default async function fetchData(nango: NangoSync) { + let totalRecords = 0; + const organization = await getOrganizationId(nango); + const proxyConfiguration: ProxyConfiguration = { + // https://developer.calendly.com/api-docs/eaed2e61a6bc3-list-organization-memberships + endpoint: `/organization_memberships`, + params: { + organization: organization.uri + }, + paginate: { + response_path: 'collection', + limit_name_in_request: 'count', + limit: 100 + } + }; + + for await (const orgMemberships of nango.paginate(proxyConfiguration)) { + const batchSize: number = orgMemberships.length || 0; + totalRecords += batchSize; + + const users: User[] = orgMemberships.map(mapUser) || []; + + await nango.log(`Saving batch of ${batchSize} users (total users: ${totalRecords})`); + + await nango.batchSave(users, 'User'); + } +} + +/** + * Maps a CalendlyOrganizationMember object to a User object (Nango User type). + */ +function mapUser(orgMember: CalendlyOrganizationMember): User { + const { name, uri, email } = orgMember.user; + // the id, .i.e., AAAAAAAAAAAAAAAA can be extracted from the + // uri https://api.calendly.com/users/AAAAAAAAAAAAAAAA + const id = uri.split('/').pop() ?? ''; + const [firstName = '', lastName = ''] = name.split(' '); + + return { + id, + email, + firstName, + lastName + }; +} diff --git a/integrations/calendly/tests/calendly-users.test.ts b/integrations/calendly/tests/calendly-users.test.ts new file mode 100644 index 00000000..1c6940f2 --- /dev/null +++ b/integrations/calendly/tests/calendly-users.test.ts @@ -0,0 +1,53 @@ +import { vi, expect, it, describe } from "vitest"; + +import fetchData from "../syncs/users.js"; + +describe("calendly users tests", () => { + const nangoMock = new global.vitest.NangoSyncMock({ + dirname: __dirname, + name: "users", + Model: "User" + }); + + const models = "User".split(','); + const batchSaveSpy = vi.spyOn(nangoMock, 'batchSave'); + + it("should get, map correctly the data and batchSave the result", async () => { + await fetchData(nangoMock); + + for (const model of models) { + const batchSaveData = await nangoMock.getBatchSaveData(model); + + const totalCalls = batchSaveSpy.mock.calls.length; + + if (totalCalls > models.length) { + const splitSize = Math.ceil(batchSaveData.length / totalCalls); + + const splitBatchSaveData = []; + for (let i = 0; i < totalCalls; i++) { + const chunk = batchSaveData.slice(i * splitSize, (i + 1) * splitSize); + splitBatchSaveData.push(chunk); + } + + splitBatchSaveData.forEach((data, index) => { + // @ts-ignore + expect(batchSaveSpy?.mock.calls[index][0]).toEqual(data); + }); + + } else { + expect(nangoMock.batchSave).toHaveBeenCalledWith(batchSaveData, model); + } + } + }); + + it('should get, map correctly the data and batchDelete the result', async () => { + await fetchData(nangoMock); + + for (const model of models) { + const batchDeleteData = await nangoMock.getBatchDeleteData(model); + if (batchDeleteData && batchDeleteData.length > 0) { + expect(nangoMock.batchDelete).toHaveBeenCalledWith(batchDeleteData, model); + } + } + }); +}); diff --git a/integrations/calendly/types.ts b/integrations/calendly/types.ts new file mode 100644 index 00000000..9287e82c --- /dev/null +++ b/integrations/calendly/types.ts @@ -0,0 +1,46 @@ +export interface CalendlyOrganizationMember { + uri: string; + role: string; + user: CalendlyUser; + organization: string; + updated_at: string; + created_at: string; +} + +export interface CalendlyUser { + uri: string; + name: string; + slug: string; + email: string; + scheduling_url: string; + timezone: string; + avatar_url: string; + locale: string; + created_at: string; + updated_at: string; +} + +export interface CalendlyCurrentUser { + uri: string; + name: string; + slug: string; + email: string; + scheduling_url: string; + timezone: string; + avatar_url: string; + created_at: string; + updated_at: string; + current_organization: string; + resource_type: string; + locale: string; +} + +export interface OrganizationInvitation { + created_at: string; + email: string; + last_sent_at: string; + organization: string; + status: string; + updated_at: string; + uri: string; +} diff --git a/integrations/outlook/schema.zod.ts b/integrations/outlook/schema.zod.ts new file mode 100644 index 00000000..58ae23d0 --- /dev/null +++ b/integrations/outlook/schema.zod.ts @@ -0,0 +1,31 @@ +// Generated by ts-to-zod +import { z } from 'zod'; + +export const optionalBackfillSettingSchema = z.object({ + backfillPeriodMs: z.number() +}); + +export const attachmentsSchema = z.object({ + filename: z.string(), + mimeType: z.string(), + size: z.number(), + attachmentId: z.string() +}); + +export const outlookEmailSchema = z.object({ + id: z.string(), + sender: z.string(), + recipients: z.union([z.string(), z.undefined()]).optional(), + date: z.string(), + subject: z.string(), + body: z.string(), + attachments: z.array(attachmentsSchema), + threadId: z.string() +}); + +export const documentInputSchema = z.object({ + threadId: z.string(), + attachmentId: z.string() +}); + +export const anonymousOutlookActionFetchattachmentOutputSchema = z.string(); diff --git a/integrations/zoho-crm/schema.zod.ts b/integrations/zoho-crm/schema.zod.ts new file mode 100644 index 00000000..395b609d --- /dev/null +++ b/integrations/zoho-crm/schema.zod.ts @@ -0,0 +1,245 @@ +// Generated by ts-to-zod +import { z } from 'zod'; + +export const zohoCRMAccountSchema = z.object({ + Owner: z.object({ + name: z.string(), + id: z.string(), + email: z.string() + }), + $currency_symbol: z.string(), + $field_states: z.string(), + Account_Type: z.string(), + SIC_Code: z.string(), + Last_Activity_Time: z.date(), + Industry: z.string(), + Account_Site: z.string(), + $state: z.string(), + $process_flow: z.boolean(), + Billing_Country: z.string(), + $locked_for_me: z.boolean(), + id: z.string(), + $approved: z.boolean(), + $approval: z.object({ + delegate: z.boolean(), + approve: z.boolean(), + reject: z.boolean(), + resubmit: z.boolean() + }), + Billing_Street: z.string(), + Created_Time: z.date(), + $editable: z.boolean(), + Billing_Code: z.string(), + Shipping_City: z.string(), + Shipping_Country: z.string(), + Shipping_Code: z.string(), + Billing_City: z.string(), + Created_By: z.object({ + name: z.string(), + id: z.string(), + email: z.string() + }), + $zia_owner_assignment: z.string(), + Annual_Revenue: z.number(), + Shipping_Street: z.string(), + Ownership: z.string(), + Description: z.string(), + Rating: z.number(), + Shipping_State: z.string(), + $review_process: z.object({ + approve: z.boolean(), + reject: z.boolean(), + resubmit: z.boolean() + }), + Website: z.string(), + Employees: z.number(), + Record_Image: z.string(), + Modified_By: z.object({ + name: z.string(), + id: z.string(), + email: z.string() + }), + $review: z.string(), + Phone: z.string(), + Account_Name: z.string(), + Account_Number: z.string(), + Ticker_Symbol: z.string(), + Modified_Time: z.date(), + $orchestration: z.boolean(), + Parent_Account: z.object({ + name: z.string(), + id: z.string() + }), + $in_merge: z.boolean(), + Locked__s: z.boolean(), + Billing_State: z.string(), + Tag: z.array(z.any()), + Fax: z.string(), + $approval_state: z.string() +}); + +export const zohoCRMContactSchema = z.object({ + Owner: z.object({ + name: z.string(), + id: z.string(), + email: z.string() + }), + Email: z.string(), + $currency_symbol: z.string(), + $field_states: z.string(), + Other_Phone: z.string(), + Mailing_State: z.string(), + Other_State: z.string(), + Other_Country: z.string(), + Last_Activity_Time: z.date(), + Department: z.string(), + $state: z.string(), + Unsubscribed_Mode: z.string(), + $process_flow: z.boolean(), + Assistant: z.string(), + Mailing_Country: z.string(), + $locked_for_me: z.string(), + id: z.string(), + $approved: z.boolean(), + Reporting_To: z.object({ + name: z.string(), + id: z.string() + }), + $approval: z.object({ + delegate: z.boolean(), + approve: z.boolean(), + reject: z.boolean(), + resubmit: z.boolean() + }), + Other_City: z.string(), + Created_Time: z.date(), + $editable: z.boolean(), + Home_Phone: z.string(), + Created_By: z.object({ + name: z.string(), + id: z.string(), + email: z.string() + }), + $zia_owner_assignment: z.string(), + Secondary_Email: z.string(), + Description: z.string(), + Vendor_Name: z.object({ + name: z.string(), + id: z.string() + }), + Mailing_Zip: z.string(), + $review_process: z.object({ + approve: z.boolean(), + reject: z.boolean(), + resubmit: z.boolean() + }), + Twitter: z.string(), + Other_Zip: z.string(), + Mailing_Street: z.string(), + Salutation: z.string(), + First_Name: z.string(), + Full_Name: z.string(), + Asst_Phone: z.string(), + Record_Image: z.string(), + Modified_By: z.object({ + name: z.string(), + id: z.string(), + email: z.string() + }), + $review: z.boolean(), + Skype_ID: z.string(), + Phone: z.string(), + Account_Name: z.object({ + name: z.string(), + id: z.string() + }), + Email_Opt_Out: z.boolean(), + Modified_Time: z.date(), + Date_of_Birth: z.date(), + Mailing_City: z.string(), + Unsubscribed_Time: z.date(), + Title: z.string(), + Other_Street: z.string(), + Mobile: z.string(), + $orchestration: z.boolean(), + Last_Name: z.string(), + $in_merge: z.boolean(), + Locked__s: z.boolean(), + Lead_Source: z.string(), + Tag: z.array(z.any()), + Fax: z.string(), + $approval_state: z.string() +}); + +export const zohoCRMDealSchema = z.object({ + Owner: z.object({ + name: z.string(), + id: z.string(), + email: z.string() + }), + Description: z.string(), + $currency_symbol: z.string(), + Campaign_Source: z.object({ + name: z.string(), + id: z.string() + }), + $field_states: z.string(), + $review_process: z.object({ + approve: z.boolean(), + reject: z.boolean(), + resubmit: z.boolean() + }), + Closing_Date: z.date(), + Reason_For_Loss__s: z.string(), + Last_Activity_Time: z.date(), + Modified_By: z.object({ + name: z.string(), + id: z.string(), + email: z.string() + }), + $review: z.string(), + Lead_Conversion_Time: z.date(), + $state: z.string(), + $process_flow: z.boolean(), + Deal_Name: z.string(), + Expected_Revenue: z.number(), + Overall_Sales_Duration: z.number(), + Stage: z.string(), + $locked_for_me: z.boolean(), + Account_Name: z.object({ + name: z.string(), + id: z.string() + }), + id: z.string(), + $approved: z.boolean(), + $approval: z.object({ + delegate: z.boolean(), + approve: z.boolean(), + reject: z.boolean(), + resubmit: z.boolean() + }), + Modified_Time: z.date(), + Created_Time: z.date(), + Amount: z.number(), + Next_Step: z.string(), + Probability: z.number(), + $editable: z.boolean(), + $orchestration: z.boolean(), + Contact_Name: z.object({ + name: z.string(), + id: z.string() + }), + Sales_Cycle_Duration: z.number(), + Type: z.string(), + $in_merge: z.boolean(), + Locked__s: z.boolean(), + Lead_Source: z.string(), + Created_By: z.object({ + name: z.string(), + id: z.string(), + email: z.string() + }), + Tag: z.array(z.any()), + $zia_owner_assignment: z.string(), + $approval_state: z.string() +}); diff --git a/integrations/zoom/mocks/nango/post/proxy/users/me/meetings/create-meeting.json b/integrations/zoom/mocks/nango/post/proxy/users/me/meetings/create-meeting.json index f229877c..efc7a131 100644 --- a/integrations/zoom/mocks/nango/post/proxy/users/me/meetings/create-meeting.json +++ b/integrations/zoom/mocks/nango/post/proxy/users/me/meetings/create-meeting.json @@ -1,8 +1,8 @@ { "uuid": "xKE6XWeFSOqlvUOuE3o9nA==", "id": 86725971976, - "host_id": "MoRLcTuVS12AoJ72n6L11Q", - "host_email": "bastien@nango.dev", + "host_id": "DaaaaaaaaROWhDGAklgKLug", + "host_email": "barry@some-email.com", "topic": "Project Kick-off Meeting", "type": 2, "status": "waiting",