From 946d3a0ea34bc99d15f66a5906736dfeadcb32af Mon Sep 17 00:00:00 2001 From: Dieter Stinglhamber Date: Tue, 31 Aug 2021 15:31:54 +0200 Subject: [PATCH] add DELETE route and logic --- .../controllers/__tests__/api-token.test.js | 51 +++++++++++++++++++ .../admin/server/controllers/api-token.js | 9 ++++ .../core/admin/server/routes/api-tokens.js | 11 ++++ .../services/__tests__/api-token.test.js | 39 ++++++++++++++ .../core/admin/server/services/api-token.js | 10 ++++ .../server/tests/admin-api-token.test.e2e.js | 20 ++++++++ 6 files changed, 140 insertions(+) diff --git a/packages/core/admin/server/controllers/__tests__/api-token.test.js b/packages/core/admin/server/controllers/__tests__/api-token.test.js index dcf0512747..e9b89f0aa7 100644 --- a/packages/core/admin/server/controllers/__tests__/api-token.test.js +++ b/packages/core/admin/server/controllers/__tests__/api-token.test.js @@ -96,4 +96,55 @@ describe('API Token Controller', () => { expect(send).toHaveBeenCalledWith({ data: tokens }); }); }); + + describe('Delete an API token', () => { + const token = { + id: 1, + name: 'api-token_tests-name', + description: 'api-token_tests-description', + type: 'read-only', + }; + + test('Deletes an API token successfully', async () => { + const revoke = jest.fn().mockResolvedValue(token); + const deleted = jest.fn(); + const ctx = createContext({ params: { id: token.id } }, { deleted }); + + global.strapi = { + admin: { + services: { + 'api-token': { + revoke, + }, + }, + }, + }; + + await apiTokenController.revoke(ctx); + + expect(revoke).toHaveBeenCalledWith(token.id); + expect(deleted).toHaveBeenCalledWith(); + }); + + test('Does not return an error if the ressource does not exists', async () => { + const revoke = jest.fn().mockResolvedValue(null); + const deleted = jest.fn(); + const ctx = createContext({ params: { id: token.id } }, { deleted }); + + global.strapi = { + admin: { + services: { + 'api-token': { + revoke, + }, + }, + }, + }; + + await apiTokenController.revoke(ctx); + + expect(revoke).toHaveBeenCalledWith(token.id); + expect(deleted).toHaveBeenCalledWith(); + }); + }); }); diff --git a/packages/core/admin/server/controllers/api-token.js b/packages/core/admin/server/controllers/api-token.js index ba6cad9b99..1714c39ec4 100644 --- a/packages/core/admin/server/controllers/api-token.js +++ b/packages/core/admin/server/controllers/api-token.js @@ -41,4 +41,13 @@ module.exports = { ctx.send({ data: apiTokens }); }, + + async revoke(ctx) { + const { id } = ctx.params; + const apiTokenService = getService('api-token'); + + await apiTokenService.revoke(id); + + ctx.deleted(); + }, }; diff --git a/packages/core/admin/server/routes/api-tokens.js b/packages/core/admin/server/routes/api-tokens.js index 9fbb978e4e..6c53c73589 100644 --- a/packages/core/admin/server/routes/api-tokens.js +++ b/packages/core/admin/server/routes/api-tokens.js @@ -23,4 +23,15 @@ module.exports = [ ], }, }, + { + method: 'DELETE', + path: '/api-tokens/:id', + handler: 'api-token.revoke', + config: { + policies: [ + 'admin::isAuthenticatedAdmin', + { name: 'admin::hasPermissions', options: { actions: ['admin::api-tokens.delete'] } }, + ], + }, + }, ]; diff --git a/packages/core/admin/server/services/__tests__/api-token.test.js b/packages/core/admin/server/services/__tests__/api-token.test.js index 4ef388f9ce..fdb043aa31 100644 --- a/packages/core/admin/server/services/__tests__/api-token.test.js +++ b/packages/core/admin/server/services/__tests__/api-token.test.js @@ -153,4 +153,43 @@ describe('API Token', () => { expect(res).toEqual(tokens); }); }); + + describe('revoke', () => { + const token = { + id: 1, + name: 'api-token_tests-name', + description: 'api-token_tests-description', + type: 'read-only', + }; + + test('It deletes the token', async () => { + const mockedDelete = jest.fn().mockResolvedValue(token); + + global.strapi = { + query() { + return { delete: mockedDelete }; + }, + }; + + const res = await apiTokenService.revoke(token.id); + + expect(mockedDelete).toHaveBeenCalledWith({ where: { id: token.id } }); + expect(res).toEqual(token); + }); + + test('It returns `null` if the resource does not exists', async () => { + const mockedDelete = jest.fn().mockResolvedValue(null); + + global.strapi = { + query() { + return { delete: mockedDelete }; + }, + }; + + const res = await apiTokenService.revoke(42); + + expect(mockedDelete).toHaveBeenCalledWith({ where: { id: 42 } }); + expect(res).toEqual(null); + }); + }); }); diff --git a/packages/core/admin/server/services/api-token.js b/packages/core/admin/server/services/api-token.js index 6602bc9cd1..f48bed5505 100644 --- a/packages/core/admin/server/services/api-token.js +++ b/packages/core/admin/server/services/api-token.js @@ -95,10 +95,20 @@ const list = async () => { }); }; +/** + * @param {string|number} id + * + * @returns {Promise} + */ +const revoke = async id => { + return strapi.query('admin::api-token').delete({ where: { id } }); +}; + module.exports = { create, exists, createSaltIfNotDefined, hash, list, + revoke, }; diff --git a/packages/core/admin/server/tests/admin-api-token.test.e2e.js b/packages/core/admin/server/tests/admin-api-token.test.e2e.js index a61f2b8859..2925974875 100644 --- a/packages/core/admin/server/tests/admin-api-token.test.e2e.js +++ b/packages/core/admin/server/tests/admin-api-token.test.e2e.js @@ -175,4 +175,24 @@ describe('Admin API Token CRUD (e2e)', () => { }, ]); }); + + test('7. Deletes a token (successfully)', async () => { + const res = await rq({ + url: '/admin/api-tokens/3', + method: 'DELETE', + }); + + expect(res.statusCode).toBe(204); + expect(res.body.data).toBeUndefined(); + }); + + test('8. Does not return an error if the ressource does not exists', async () => { + const res = await rq({ + url: '/admin/api-tokens/42', + method: 'DELETE', + }); + + expect(res.statusCode).toBe(204); + expect(res.body.data).toBeUndefined(); + }); });