mirror of
https://github.com/lingble/twenty.git
synced 2025-11-02 13:47:55 +00:00
@@ -1,4 +1,4 @@
|
|||||||
import { Injectable, UnauthorizedException } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { JwtService, JwtSignOptions, JwtVerifyOptions } from '@nestjs/jwt';
|
import { JwtService, JwtSignOptions, JwtVerifyOptions } from '@nestjs/jwt';
|
||||||
|
|
||||||
import { createHash } from 'crypto';
|
import { createHash } from 'crypto';
|
||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
AuthExceptionCode,
|
AuthExceptionCode,
|
||||||
} from 'src/engine/core-modules/auth/auth.exception';
|
} from 'src/engine/core-modules/auth/auth.exception';
|
||||||
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
||||||
|
import { isDefined } from 'src/utils/is-defined';
|
||||||
|
|
||||||
export type WorkspaceTokenType =
|
export type WorkspaceTokenType =
|
||||||
| 'ACCESS'
|
| 'ACCESS'
|
||||||
@@ -53,9 +54,16 @@ export class JwtWrapperService {
|
|||||||
json: true,
|
json: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!isDefined(payload)) {
|
||||||
|
throw new AuthException('No payload', AuthExceptionCode.UNAUTHENTICATED);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: check if this is really needed
|
// TODO: check if this is really needed
|
||||||
if (type !== 'FILE' && !payload.sub) {
|
if (type !== 'FILE' && !payload.sub) {
|
||||||
throw new UnauthorizedException('No payload sub');
|
throw new AuthException(
|
||||||
|
'No payload sub',
|
||||||
|
AuthExceptionCode.UNAUTHENTICATED,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -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 perform = async (z: ZObject, bundle: Bundle) => {
|
||||||
const data = bundle.inputData;
|
const data = bundle.inputData;
|
||||||
const operation = data.crudZapierOperation;
|
const operation = data.crudZapierOperation;
|
||||||
|
const queryOperation = getOperationFromDatabaseEventAction(z, operation);
|
||||||
const nameSingular = data.nameSingular;
|
const nameSingular = data.nameSingular;
|
||||||
delete data.nameSingular;
|
delete data.nameSingular;
|
||||||
delete data.crudZapierOperation;
|
delete data.crudZapierOperation;
|
||||||
const query = `
|
const query = `
|
||||||
mutation ${operation}${capitalize(nameSingular)} {
|
mutation ${queryOperation}${capitalize(nameSingular)} {
|
||||||
${operation}${capitalize(nameSingular)}(
|
${queryOperation}${capitalize(nameSingular)}(
|
||||||
${computeQueryParameters(operation, data)}
|
${computeQueryParameters(operation, data)}
|
||||||
)
|
)
|
||||||
{id}
|
{id}
|
||||||
|
|||||||
@@ -15,6 +15,6 @@ describe('triggers.list_record_ids', () => {
|
|||||||
);
|
);
|
||||||
expect(result).toBeDefined();
|
expect(result).toBeDefined();
|
||||||
expect(result.length).toBeGreaterThan(1);
|
expect(result.length).toBeGreaterThan(1);
|
||||||
expect(result[0].id).toBeDefined();
|
expect(result[0].record.id).toBeDefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -24,18 +24,18 @@ describe('triggers.trigger_record.created', () => {
|
|||||||
requestDb(
|
requestDb(
|
||||||
z,
|
z,
|
||||||
bundle,
|
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,
|
bundle,
|
||||||
);
|
);
|
||||||
expect(checkDbResult.data.webhooks.edges[0].node.operation).toEqual(
|
expect(checkDbResult.data.webhooks.edges[0].node.operations[0]).toEqual(
|
||||||
'create.company',
|
'company.created',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
test('should succeed to unsubscribe', async () => {
|
test('should succeed to unsubscribe', async () => {
|
||||||
const bundle = getBundle({});
|
const bundle = getBundle({});
|
||||||
bundle.inputData.nameSingular = 'company';
|
bundle.inputData.nameSingular = 'company';
|
||||||
bundle.inputData.operation = 'create';
|
bundle.inputData.operation = DatabaseEventAction.CREATED;
|
||||||
bundle.targetUrl = 'https://test.com';
|
bundle.targetUrl = 'https://test.com';
|
||||||
const result = await appTester(
|
const result = await appTester(
|
||||||
App.triggers[triggerRecordKey].operation.performSubscribe,
|
App.triggers[triggerRecordKey].operation.performSubscribe,
|
||||||
@@ -54,7 +54,7 @@ describe('triggers.trigger_record.created', () => {
|
|||||||
requestDb(
|
requestDb(
|
||||||
z,
|
z,
|
||||||
bundle,
|
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,
|
bundle,
|
||||||
);
|
);
|
||||||
@@ -83,19 +83,19 @@ describe('triggers.trigger_record.created', () => {
|
|||||||
);
|
);
|
||||||
expect(results.length).toEqual(1);
|
expect(results.length).toEqual(1);
|
||||||
const company = results[0];
|
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 () => {
|
it('should load companies from list', async () => {
|
||||||
const bundle = getBundle({});
|
const bundle = getBundle({});
|
||||||
bundle.inputData.nameSingular = 'company';
|
bundle.inputData.nameSingular = 'company';
|
||||||
bundle.inputData.operation = 'create';
|
bundle.inputData.operation = DatabaseEventAction.CREATED;
|
||||||
const results = await appTester(
|
const results = await appTester(
|
||||||
App.triggers[triggerRecordKey].operation.performList,
|
App.triggers[triggerRecordKey].operation.performList,
|
||||||
bundle,
|
bundle,
|
||||||
);
|
);
|
||||||
expect(results.length).toBeGreaterThan(1);
|
expect(results.length).toBeGreaterThan(1);
|
||||||
const firstCompany = results[0];
|
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 () => {
|
test('should succeed to subscribe', async () => {
|
||||||
const bundle = getBundle({});
|
const bundle = getBundle({});
|
||||||
bundle.inputData.nameSingular = 'company';
|
bundle.inputData.nameSingular = 'company';
|
||||||
bundle.inputData.operation = 'update';
|
bundle.inputData.operation = DatabaseEventAction.UPDATED;
|
||||||
bundle.targetUrl = 'https://test.com';
|
bundle.targetUrl = 'https://test.com';
|
||||||
const result = await appTester(
|
const result = await appTester(
|
||||||
App.triggers[triggerRecordKey].operation.performSubscribe,
|
App.triggers[triggerRecordKey].operation.performSubscribe,
|
||||||
@@ -116,18 +116,18 @@ describe('triggers.trigger_record.update', () => {
|
|||||||
requestDb(
|
requestDb(
|
||||||
z,
|
z,
|
||||||
bundle,
|
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,
|
bundle,
|
||||||
);
|
);
|
||||||
expect(checkDbResult.data.webhooks.edges[0].node.operation).toEqual(
|
expect(checkDbResult.data.webhooks.edges[0].node.operations[0]).toEqual(
|
||||||
'update.company',
|
'company.updated',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
test('should succeed to unsubscribe', async () => {
|
test('should succeed to unsubscribe', async () => {
|
||||||
const bundle = getBundle({});
|
const bundle = getBundle({});
|
||||||
bundle.inputData.nameSingular = 'company';
|
bundle.inputData.nameSingular = 'company';
|
||||||
bundle.inputData.operation = 'update';
|
bundle.inputData.operation = DatabaseEventAction.UPDATED;
|
||||||
bundle.targetUrl = 'https://test.com';
|
bundle.targetUrl = 'https://test.com';
|
||||||
const result = await appTester(
|
const result = await appTester(
|
||||||
App.triggers[triggerRecordKey].operation.performSubscribe,
|
App.triggers[triggerRecordKey].operation.performSubscribe,
|
||||||
@@ -146,7 +146,7 @@ describe('triggers.trigger_record.update', () => {
|
|||||||
requestDb(
|
requestDb(
|
||||||
z,
|
z,
|
||||||
bundle,
|
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,
|
bundle,
|
||||||
);
|
);
|
||||||
@@ -155,14 +155,15 @@ describe('triggers.trigger_record.update', () => {
|
|||||||
it('should load companies from list', async () => {
|
it('should load companies from list', async () => {
|
||||||
const bundle = getBundle({});
|
const bundle = getBundle({});
|
||||||
bundle.inputData.nameSingular = 'company';
|
bundle.inputData.nameSingular = 'company';
|
||||||
bundle.inputData.operation = 'update';
|
bundle.inputData.operation = DatabaseEventAction.UPDATED;
|
||||||
const results = await appTester(
|
const results = await appTester(
|
||||||
App.triggers[triggerRecordKey].operation.performList,
|
App.triggers[triggerRecordKey].operation.performList,
|
||||||
bundle,
|
bundle,
|
||||||
);
|
);
|
||||||
expect(results.length).toBeGreaterThan(1);
|
expect(results.length).toBeGreaterThan(1);
|
||||||
const firstCompany = results[0];
|
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 () => {
|
test('should succeed to subscribe', async () => {
|
||||||
const bundle = getBundle({});
|
const bundle = getBundle({});
|
||||||
bundle.inputData.nameSingular = 'company';
|
bundle.inputData.nameSingular = 'company';
|
||||||
bundle.inputData.operation = 'delete';
|
bundle.inputData.operation = DatabaseEventAction.DELETED;
|
||||||
bundle.targetUrl = 'https://test.com';
|
bundle.targetUrl = 'https://test.com';
|
||||||
const result = await appTester(
|
const result = await appTester(
|
||||||
App.triggers[triggerRecordKey].operation.performSubscribe,
|
App.triggers[triggerRecordKey].operation.performSubscribe,
|
||||||
@@ -183,18 +184,18 @@ describe('triggers.trigger_record.delete', () => {
|
|||||||
requestDb(
|
requestDb(
|
||||||
z,
|
z,
|
||||||
bundle,
|
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,
|
bundle,
|
||||||
);
|
);
|
||||||
expect(checkDbResult.data.webhooks.edges[0].node.operation).toEqual(
|
expect(checkDbResult.data.webhooks.edges[0].node.operations[0]).toEqual(
|
||||||
'delete.company',
|
'company.deleted',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
test('should succeed to unsubscribe', async () => {
|
test('should succeed to unsubscribe', async () => {
|
||||||
const bundle = getBundle({});
|
const bundle = getBundle({});
|
||||||
bundle.inputData.nameSingular = 'company';
|
bundle.inputData.nameSingular = 'company';
|
||||||
bundle.inputData.operation = 'delete';
|
bundle.inputData.operation = DatabaseEventAction.DELETED;
|
||||||
bundle.targetUrl = 'https://test.com';
|
bundle.targetUrl = 'https://test.com';
|
||||||
const result = await appTester(
|
const result = await appTester(
|
||||||
App.triggers[triggerRecordKey].operation.performSubscribe,
|
App.triggers[triggerRecordKey].operation.performSubscribe,
|
||||||
@@ -213,7 +214,7 @@ describe('triggers.trigger_record.delete', () => {
|
|||||||
requestDb(
|
requestDb(
|
||||||
z,
|
z,
|
||||||
bundle,
|
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,
|
bundle,
|
||||||
);
|
);
|
||||||
@@ -222,7 +223,7 @@ describe('triggers.trigger_record.delete', () => {
|
|||||||
it('should load companies from list', async () => {
|
it('should load companies from list', async () => {
|
||||||
const bundle = getBundle({});
|
const bundle = getBundle({});
|
||||||
bundle.inputData.nameSingular = 'company';
|
bundle.inputData.nameSingular = 'company';
|
||||||
bundle.inputData.operation = 'delete';
|
bundle.inputData.operation = DatabaseEventAction.DELETED;
|
||||||
const results = await appTester(
|
const results = await appTester(
|
||||||
App.triggers[triggerRecordKey].operation.performList,
|
App.triggers[triggerRecordKey].operation.performList,
|
||||||
bundle,
|
bundle,
|
||||||
@@ -230,7 +231,7 @@ describe('triggers.trigger_record.delete', () => {
|
|||||||
expect(results.length).toBeGreaterThan(1);
|
expect(results.length).toBeGreaterThan(1);
|
||||||
const firstCompany = results[0];
|
const firstCompany = results[0];
|
||||||
expect(firstCompany).toBeDefined();
|
expect(firstCompany).toBeDefined();
|
||||||
expect(firstCompany.id).toBeDefined();
|
expect(firstCompany.record.id).toBeDefined();
|
||||||
expect(Object.keys(firstCompany).length).toEqual(1);
|
expect(Object.keys(firstCompany).length).toEqual(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,14 +1,4 @@
|
|||||||
import { Bundle, ZObject } from 'zapier-platform-core';
|
import { performList } from '../utils/triggers/triggers.utils';
|
||||||
|
|
||||||
import { ObjectData } from '../utils/data.types';
|
|
||||||
import { listSample } from '../utils/triggers/triggers.utils';
|
|
||||||
|
|
||||||
const listRecordIdsRequest = async (
|
|
||||||
z: ZObject,
|
|
||||||
bundle: Bundle,
|
|
||||||
): Promise<ObjectData[]> => {
|
|
||||||
return listSample(z, bundle, true);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const listRecordIdsKey = 'list_record_ids';
|
export const listRecordIdsKey = 'list_record_ids';
|
||||||
|
|
||||||
@@ -21,6 +11,6 @@ export default {
|
|||||||
key: listRecordIdsKey,
|
key: listRecordIdsKey,
|
||||||
noun: 'Object',
|
noun: 'Object',
|
||||||
operation: {
|
operation: {
|
||||||
perform: listRecordIdsRequest,
|
perform: performList,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
export type InputData = { [x: string]: any };
|
export type InputData = { [x: string]: any };
|
||||||
|
|
||||||
export type ObjectData = { id: string } | { [x: string]: any };
|
|
||||||
|
|
||||||
export type NodeField = {
|
export type NodeField = {
|
||||||
type: FieldMetadataType;
|
type: FieldMetadataType;
|
||||||
name: string;
|
name: string;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { Bundle, ZObject } from 'zapier-platform-core';
|
import { Bundle, ZObject } from 'zapier-platform-core';
|
||||||
|
|
||||||
import { ObjectData } from '../../utils/data.types';
|
|
||||||
import handleQueryParams from '../../utils/handleQueryParams';
|
import handleQueryParams from '../../utils/handleQueryParams';
|
||||||
import requestDb, {
|
import requestDb, {
|
||||||
requestDbViaRestApi,
|
requestDbViaRestApi,
|
||||||
@@ -11,7 +10,6 @@ export enum DatabaseEventAction {
|
|||||||
CREATED = 'created',
|
CREATED = 'created',
|
||||||
UPDATED = 'updated',
|
UPDATED = 'updated',
|
||||||
DELETED = 'deleted',
|
DELETED = 'deleted',
|
||||||
DESTROYED = 'destroyed',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const performSubscribe = async (z: ZObject, bundle: Bundle) => {
|
export const performSubscribe = async (z: ZObject, bundle: Bundle) => {
|
||||||
@@ -81,7 +79,7 @@ const getNamePluralFromNameSingular = async (
|
|||||||
export const performList = async (
|
export const performList = async (
|
||||||
z: ZObject,
|
z: ZObject,
|
||||||
bundle: Bundle,
|
bundle: Bundle,
|
||||||
): Promise<ObjectData[]> => {
|
): Promise<{ record: Record<string, any>; updatedFields?: string[] }[]> => {
|
||||||
const nameSingular = bundle.inputData.nameSingular;
|
const nameSingular = bundle.inputData.nameSingular;
|
||||||
const namePlural = await getNamePluralFromNameSingular(
|
const namePlural = await getNamePluralFromNameSingular(
|
||||||
z,
|
z,
|
||||||
@@ -92,9 +90,9 @@ export const performList = async (
|
|||||||
return results.map((result) => ({
|
return results.map((result) => ({
|
||||||
record: result,
|
record: result,
|
||||||
...(bundle.inputData.operation === DatabaseEventAction.UPDATED && {
|
...(bundle.inputData.operation === DatabaseEventAction.UPDATED && {
|
||||||
updatedFields: Object.keys(result).filter((key) => key !== 'id')?.[0] || [
|
updatedFields: [
|
||||||
'updatedField',
|
Object.keys(result).filter((key) => key !== 'id')?.[0],
|
||||||
],
|
] || ['updatedField'],
|
||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user