From 7ac45ca748a8532e9bba158b1a98f7b1989adf2c Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Mon, 8 Aug 2022 18:34:13 +0800 Subject: [PATCH] Add deleteIntegration API and integration tests --- .../api/src/resolvers/function_resolvers.ts | 3 + .../api/src/resolvers/integrations/index.ts | 70 +++++++++++++++++++ .../api/test/resolvers/integrations.test.ts | 46 ++++++++++++ 3 files changed, 119 insertions(+) diff --git a/packages/api/src/resolvers/function_resolvers.ts b/packages/api/src/resolvers/function_resolvers.ts index 2102994dd..a19bdd11f 100644 --- a/packages/api/src/resolvers/function_resolvers.ts +++ b/packages/api/src/resolvers/function_resolvers.ts @@ -32,6 +32,7 @@ import { createReminderResolver, deleteAccountResolver, deleteHighlightResolver, + deleteIntegrationResolver, deleteLabelResolver, deleteNewsletterEmailResolver, deleteReminderResolver, @@ -168,6 +169,7 @@ export const functionResolvers = { setLabelsForHighlight: setLabelsForHighlightResolver, moveLabel: moveLabelResolver, setIntegration: setIntegrationResolver, + deleteIntegration: deleteIntegrationResolver, }, Query: { me: getMeUserResolver, @@ -598,4 +600,5 @@ export const functionResolvers = { ...resultResolveTypeResolver('MoveLabel'), ...resultResolveTypeResolver('SetIntegration'), ...resultResolveTypeResolver('Integrations'), + ...resultResolveTypeResolver('DeleteIntegration'), } diff --git a/packages/api/src/resolvers/integrations/index.ts b/packages/api/src/resolvers/integrations/index.ts index 43b8842af..1ae83b55b 100644 --- a/packages/api/src/resolvers/integrations/index.ts +++ b/packages/api/src/resolvers/integrations/index.ts @@ -1,8 +1,12 @@ import { authorized } from '../../utils/helpers' import { + DeleteIntegrationError, + DeleteIntegrationErrorCode, + DeleteIntegrationSuccess, IntegrationsError, IntegrationsErrorCode, IntegrationsSuccess, + MutationDeleteIntegrationArgs, MutationSetIntegrationArgs, SetIntegrationError, SetIntegrationErrorCode, @@ -127,6 +131,8 @@ export const integrationsResolver = authorized< IntegrationsSuccess, IntegrationsError >(async (_, __, { claims: { uid }, log }) => { + log.info('integrationsResolver') + try { const user = await getRepository(User).findOneBy({ id: uid }) if (!user) { @@ -149,3 +155,67 @@ export const integrationsResolver = authorized< } } }) + +export const deleteIntegrationResolver = authorized< + DeleteIntegrationSuccess, + DeleteIntegrationError, + MutationDeleteIntegrationArgs +>(async (_, { id }, { claims: { uid }, log }) => { + log.info('deleteIntegrationResolver') + + try { + const user = await getRepository(User).findOneBy({ id: uid }) + if (!user) { + return { + errorCodes: [DeleteIntegrationErrorCode.Unauthorized], + } + } + + const integration = await getRepository(Integration).findOne({ + where: { id }, + relations: ['user'], + }) + + if (!integration) { + return { + errorCodes: [DeleteIntegrationErrorCode.NotFound], + } + } + + if (integration.user.id !== uid) { + return { + errorCodes: [DeleteIntegrationErrorCode.Unauthorized], + } + } + + if (integration.taskName) { + // delete the task if task exists + await deleteTask(integration.taskName) + log.info('task deleted', integration.taskName) + } + + const deletedIntegration = await getRepository(Integration).remove( + integration + ) + deletedIntegration.id = id + + analytics.track({ + userId: uid, + event: 'integration_delete', + properties: { + integrationId: deletedIntegration.id, + env: env.server.apiEnv, + }, + }) + + return { + integration: deletedIntegration, + } + } catch (error) { + log.error(error) + + return { + errorCodes: [DeleteIntegrationErrorCode.BadRequest], + } + } +}) diff --git a/packages/api/test/resolvers/integrations.test.ts b/packages/api/test/resolvers/integrations.test.ts index 4df89e4b3..582160680 100644 --- a/packages/api/test/resolvers/integrations.test.ts +++ b/packages/api/test/resolvers/integrations.test.ts @@ -345,4 +345,50 @@ describe('Integrations resolvers', () => { ) }) }) + + describe('deleteIntegration API', () => { + const query = (id: string) => ` + mutation { + deleteIntegration(id: "${id}") { + ... on DeleteIntegrationSuccess { + integration { + id + } + } + ... on DeleteIntegrationError { + errorCodes + } + } + } + ` + + context('when integration exists', () => { + let existingIntegration: Integration + + beforeEach(async () => { + existingIntegration = await getRepository(Integration).save({ + user: loginUser, + type: DataIntegrationType.Readwise, + token: 'fakeToken', + taskName: 'some task name', + }) + }) + + it('deletes the integration and cloud task', async () => { + const res = await graphqlRequest( + query(existingIntegration.id), + authToken + ) + const integration = await getRepository(Integration).findOneBy({ + id: existingIntegration.id, + }) + + expect(res.body.data.deleteIntegration.integration).to.be.an('object') + expect(res.body.data.deleteIntegration.integration.id).to.eql( + existingIntegration.id + ) + expect(integration).to.be.null + }) + }) + }) })