From 269eaf44221a2cbc070ba7ffff58fb824b27f231 Mon Sep 17 00:00:00 2001 From: martmull Date: Tue, 12 Nov 2024 17:58:36 +0100 Subject: [PATCH] Update zapier trigger payload (#8464) - fixes zapier tests --- .../jwt/services/jwt-wrapper.service.ts | 12 ++++- .../twenty-zapier/src/creates/crud_record.ts | 25 +++++++++- .../src/test/triggers/list_record_ids.test.ts | 2 +- .../src/test/triggers/trigger_record.test.ts | 49 ++++++++++--------- .../src/triggers/list_record_ids.ts | 14 +----- .../twenty-zapier/src/utils/data.types.ts | 2 - .../src/utils/triggers/triggers.utils.ts | 10 ++-- 7 files changed, 65 insertions(+), 49 deletions(-) diff --git a/packages/twenty-server/src/engine/core-modules/jwt/services/jwt-wrapper.service.ts b/packages/twenty-server/src/engine/core-modules/jwt/services/jwt-wrapper.service.ts index 1a83e0ed1936..f3237e794162 100644 --- a/packages/twenty-server/src/engine/core-modules/jwt/services/jwt-wrapper.service.ts +++ b/packages/twenty-server/src/engine/core-modules/jwt/services/jwt-wrapper.service.ts @@ -1,4 +1,4 @@ -import { Injectable, UnauthorizedException } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { JwtService, JwtSignOptions, JwtVerifyOptions } from '@nestjs/jwt'; import { createHash } from 'crypto'; @@ -10,6 +10,7 @@ import { AuthExceptionCode, } from 'src/engine/core-modules/auth/auth.exception'; import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service'; +import { isDefined } from 'src/utils/is-defined'; export type WorkspaceTokenType = | 'ACCESS' @@ -53,9 +54,16 @@ export class JwtWrapperService { json: true, }); + if (!isDefined(payload)) { + throw new AuthException('No payload', AuthExceptionCode.UNAUTHENTICATED); + } + // TODO: check if this is really needed if (type !== 'FILE' && !payload.sub) { - throw new UnauthorizedException('No payload sub'); + throw new AuthException( + 'No payload sub', + AuthExceptionCode.UNAUTHENTICATED, + ); } try { diff --git a/packages/twenty-zapier/src/creates/crud_record.ts b/packages/twenty-zapier/src/creates/crud_record.ts index 43c34a3dc925..eaa4c2a3dd8a 100644 --- a/packages/twenty-zapier/src/creates/crud_record.ts +++ b/packages/twenty-zapier/src/creates/crud_record.ts @@ -64,15 +64,36 @@ const computeQueryParameters = ( } }; +const getOperationFromDatabaseEventAction = ( + z: ZObject, + databaseEventAction: DatabaseEventAction, +): 'create' | 'update' | 'delete' => { + switch (databaseEventAction) { + case DatabaseEventAction.CREATED: + return 'create'; + case DatabaseEventAction.UPDATED: + return 'update'; + case DatabaseEventAction.DELETED: + return 'delete'; + default: + throw new z.errors.Error( + `Unknown databaseEventAction: ${databaseEventAction}`, + 'Error', + 404, + ); + } +}; + const perform = async (z: ZObject, bundle: Bundle) => { const data = bundle.inputData; const operation = data.crudZapierOperation; + const queryOperation = getOperationFromDatabaseEventAction(z, operation); const nameSingular = data.nameSingular; delete data.nameSingular; delete data.crudZapierOperation; const query = ` - mutation ${operation}${capitalize(nameSingular)} { - ${operation}${capitalize(nameSingular)}( + mutation ${queryOperation}${capitalize(nameSingular)} { + ${queryOperation}${capitalize(nameSingular)}( ${computeQueryParameters(operation, data)} ) {id} diff --git a/packages/twenty-zapier/src/test/triggers/list_record_ids.test.ts b/packages/twenty-zapier/src/test/triggers/list_record_ids.test.ts index a0ca7e084af8..578b2f02a0cc 100644 --- a/packages/twenty-zapier/src/test/triggers/list_record_ids.test.ts +++ b/packages/twenty-zapier/src/test/triggers/list_record_ids.test.ts @@ -15,6 +15,6 @@ describe('triggers.list_record_ids', () => { ); expect(result).toBeDefined(); expect(result.length).toBeGreaterThan(1); - expect(result[0].id).toBeDefined(); + expect(result[0].record.id).toBeDefined(); }); }); diff --git a/packages/twenty-zapier/src/test/triggers/trigger_record.test.ts b/packages/twenty-zapier/src/test/triggers/trigger_record.test.ts index 14d75e3689b1..ec5d1d73e326 100644 --- a/packages/twenty-zapier/src/test/triggers/trigger_record.test.ts +++ b/packages/twenty-zapier/src/test/triggers/trigger_record.test.ts @@ -24,18 +24,18 @@ describe('triggers.trigger_record.created', () => { requestDb( z, bundle, - `query webhook {webhooks(filter: {id: {eq: "${result.id}"}}){edges {node {id operation}}}}`, + `query webhook {webhooks(filter: {id: {eq: "${result.id}"}}){edges {node {id operations}}}}`, ), bundle, ); - expect(checkDbResult.data.webhooks.edges[0].node.operation).toEqual( - 'create.company', + expect(checkDbResult.data.webhooks.edges[0].node.operations[0]).toEqual( + 'company.created', ); }); test('should succeed to unsubscribe', async () => { const bundle = getBundle({}); bundle.inputData.nameSingular = 'company'; - bundle.inputData.operation = 'create'; + bundle.inputData.operation = DatabaseEventAction.CREATED; bundle.targetUrl = 'https://test.com'; const result = await appTester( App.triggers[triggerRecordKey].operation.performSubscribe, @@ -54,7 +54,7 @@ describe('triggers.trigger_record.created', () => { requestDb( z, bundle, - `query webhook {webhooks(filter: {id: {eq: "${result.id}"}}){edges {node {id operation}}}}`, + `query webhook {webhooks(filter: {id: {eq: "${result.id}"}}){edges {node {id operations}}}}`, ), bundle, ); @@ -83,19 +83,19 @@ describe('triggers.trigger_record.created', () => { ); expect(results.length).toEqual(1); const company = results[0]; - expect(company.id).toEqual('d6ccb1d1-a90b-4822-a992-a0dd946592c9'); + expect(company.record.id).toEqual('d6ccb1d1-a90b-4822-a992-a0dd946592c9'); }); it('should load companies from list', async () => { const bundle = getBundle({}); bundle.inputData.nameSingular = 'company'; - bundle.inputData.operation = 'create'; + bundle.inputData.operation = DatabaseEventAction.CREATED; const results = await appTester( App.triggers[triggerRecordKey].operation.performList, bundle, ); expect(results.length).toBeGreaterThan(1); const firstCompany = results[0]; - expect(firstCompany).toBeDefined(); + expect(firstCompany.record).toBeDefined(); }); }); @@ -103,7 +103,7 @@ describe('triggers.trigger_record.update', () => { test('should succeed to subscribe', async () => { const bundle = getBundle({}); bundle.inputData.nameSingular = 'company'; - bundle.inputData.operation = 'update'; + bundle.inputData.operation = DatabaseEventAction.UPDATED; bundle.targetUrl = 'https://test.com'; const result = await appTester( App.triggers[triggerRecordKey].operation.performSubscribe, @@ -116,18 +116,18 @@ describe('triggers.trigger_record.update', () => { requestDb( z, bundle, - `query webhook {webhooks(filter: {id: {eq: "${result.id}"}}){edges {node {id operation}}}}`, + `query webhook {webhooks(filter: {id: {eq: "${result.id}"}}){edges {node {id operations}}}}`, ), bundle, ); - expect(checkDbResult.data.webhooks.edges[0].node.operation).toEqual( - 'update.company', + expect(checkDbResult.data.webhooks.edges[0].node.operations[0]).toEqual( + 'company.updated', ); }); test('should succeed to unsubscribe', async () => { const bundle = getBundle({}); bundle.inputData.nameSingular = 'company'; - bundle.inputData.operation = 'update'; + bundle.inputData.operation = DatabaseEventAction.UPDATED; bundle.targetUrl = 'https://test.com'; const result = await appTester( App.triggers[triggerRecordKey].operation.performSubscribe, @@ -146,7 +146,7 @@ describe('triggers.trigger_record.update', () => { requestDb( z, bundle, - `query webhook {webhooks(filter: {id: {eq: "${result.id}"}}){edges {node {id operation}}}}`, + `query webhook {webhooks(filter: {id: {eq: "${result.id}"}}){edges {node {id operations}}}}`, ), bundle, ); @@ -155,14 +155,15 @@ describe('triggers.trigger_record.update', () => { it('should load companies from list', async () => { const bundle = getBundle({}); bundle.inputData.nameSingular = 'company'; - bundle.inputData.operation = 'update'; + bundle.inputData.operation = DatabaseEventAction.UPDATED; const results = await appTester( App.triggers[triggerRecordKey].operation.performList, bundle, ); expect(results.length).toBeGreaterThan(1); const firstCompany = results[0]; - expect(firstCompany).toBeDefined(); + expect(firstCompany.record).toBeDefined(); + expect(firstCompany.updatedFields).toBeDefined(); }); }); @@ -170,7 +171,7 @@ describe('triggers.trigger_record.delete', () => { test('should succeed to subscribe', async () => { const bundle = getBundle({}); bundle.inputData.nameSingular = 'company'; - bundle.inputData.operation = 'delete'; + bundle.inputData.operation = DatabaseEventAction.DELETED; bundle.targetUrl = 'https://test.com'; const result = await appTester( App.triggers[triggerRecordKey].operation.performSubscribe, @@ -183,18 +184,18 @@ describe('triggers.trigger_record.delete', () => { requestDb( z, bundle, - `query webhook {webhooks(filter: {id: {eq: "${result.id}"}}){edges {node {id operation}}}}`, + `query webhook {webhooks(filter: {id: {eq: "${result.id}"}}){edges {node {id operations}}}}`, ), bundle, ); - expect(checkDbResult.data.webhooks.edges[0].node.operation).toEqual( - 'delete.company', + expect(checkDbResult.data.webhooks.edges[0].node.operations[0]).toEqual( + 'company.deleted', ); }); test('should succeed to unsubscribe', async () => { const bundle = getBundle({}); bundle.inputData.nameSingular = 'company'; - bundle.inputData.operation = 'delete'; + bundle.inputData.operation = DatabaseEventAction.DELETED; bundle.targetUrl = 'https://test.com'; const result = await appTester( App.triggers[triggerRecordKey].operation.performSubscribe, @@ -213,7 +214,7 @@ describe('triggers.trigger_record.delete', () => { requestDb( z, bundle, - `query webhook {webhooks(filter: {id: {eq: "${result.id}"}}){edges {node {id operation}}}}`, + `query webhook {webhooks(filter: {id: {eq: "${result.id}"}}){edges {node {id operations}}}}`, ), bundle, ); @@ -222,7 +223,7 @@ describe('triggers.trigger_record.delete', () => { it('should load companies from list', async () => { const bundle = getBundle({}); bundle.inputData.nameSingular = 'company'; - bundle.inputData.operation = 'delete'; + bundle.inputData.operation = DatabaseEventAction.DELETED; const results = await appTester( App.triggers[triggerRecordKey].operation.performList, bundle, @@ -230,7 +231,7 @@ describe('triggers.trigger_record.delete', () => { expect(results.length).toBeGreaterThan(1); const firstCompany = results[0]; expect(firstCompany).toBeDefined(); - expect(firstCompany.id).toBeDefined(); + expect(firstCompany.record.id).toBeDefined(); expect(Object.keys(firstCompany).length).toEqual(1); }); }); diff --git a/packages/twenty-zapier/src/triggers/list_record_ids.ts b/packages/twenty-zapier/src/triggers/list_record_ids.ts index 8f6345f48a24..9c91ebc7ac62 100644 --- a/packages/twenty-zapier/src/triggers/list_record_ids.ts +++ b/packages/twenty-zapier/src/triggers/list_record_ids.ts @@ -1,14 +1,4 @@ -import { Bundle, ZObject } from 'zapier-platform-core'; - -import { ObjectData } from '../utils/data.types'; -import { listSample } from '../utils/triggers/triggers.utils'; - -const listRecordIdsRequest = async ( - z: ZObject, - bundle: Bundle, -): Promise => { - return listSample(z, bundle, true); -}; +import { performList } from '../utils/triggers/triggers.utils'; export const listRecordIdsKey = 'list_record_ids'; @@ -21,6 +11,6 @@ export default { key: listRecordIdsKey, noun: 'Object', operation: { - perform: listRecordIdsRequest, + perform: performList, }, }; diff --git a/packages/twenty-zapier/src/utils/data.types.ts b/packages/twenty-zapier/src/utils/data.types.ts index 9c6b35d33b4b..776b8c8cc3e4 100644 --- a/packages/twenty-zapier/src/utils/data.types.ts +++ b/packages/twenty-zapier/src/utils/data.types.ts @@ -1,7 +1,5 @@ export type InputData = { [x: string]: any }; -export type ObjectData = { id: string } | { [x: string]: any }; - export type NodeField = { type: FieldMetadataType; name: string; diff --git a/packages/twenty-zapier/src/utils/triggers/triggers.utils.ts b/packages/twenty-zapier/src/utils/triggers/triggers.utils.ts index e757308f2cc7..cc0e8c83ac24 100644 --- a/packages/twenty-zapier/src/utils/triggers/triggers.utils.ts +++ b/packages/twenty-zapier/src/utils/triggers/triggers.utils.ts @@ -1,6 +1,5 @@ import { Bundle, ZObject } from 'zapier-platform-core'; -import { ObjectData } from '../../utils/data.types'; import handleQueryParams from '../../utils/handleQueryParams'; import requestDb, { requestDbViaRestApi, @@ -11,7 +10,6 @@ export enum DatabaseEventAction { CREATED = 'created', UPDATED = 'updated', DELETED = 'deleted', - DESTROYED = 'destroyed', } export const performSubscribe = async (z: ZObject, bundle: Bundle) => { @@ -81,7 +79,7 @@ const getNamePluralFromNameSingular = async ( export const performList = async ( z: ZObject, bundle: Bundle, -): Promise => { +): Promise<{ record: Record; updatedFields?: string[] }[]> => { const nameSingular = bundle.inputData.nameSingular; const namePlural = await getNamePluralFromNameSingular( z, @@ -92,9 +90,9 @@ export const performList = async ( return results.map((result) => ({ record: result, ...(bundle.inputData.operation === DatabaseEventAction.UPDATED && { - updatedFields: Object.keys(result).filter((key) => key !== 'id')?.[0] || [ - 'updatedField', - ], + updatedFields: [ + Object.keys(result).filter((key) => key !== 'id')?.[0], + ] || ['updatedField'], }), })); };