From a30960727084fa666fc8dd8474f7f37233207952 Mon Sep 17 00:00:00 2001 From: petruki <31597636+petruki@users.noreply.github.com> Date: Sun, 22 Oct 2023 11:53:36 -0700 Subject: [PATCH 1/2] Removed deprecated slack route --- requests/Switcher API.postman_collection.json | 67 ---------- src/api-docs/paths/path-api-management.js | 43 ------ src/api-docs/paths/path-slack.js | 40 ------ src/api-docs/swagger-document.js | 4 +- src/app.js | 2 - src/external/switcher-api-facade.js | 37 +----- src/routers/api-management.js | 23 ---- src/routers/slack.js | 9 -- src/services/slack.js | 6 +- tests/api-management.test.js | 122 ------------------ tests/slack.test.js | 91 ++----------- 11 files changed, 11 insertions(+), 433 deletions(-) delete mode 100644 src/api-docs/paths/path-api-management.js delete mode 100644 src/routers/api-management.js delete mode 100644 tests/api-management.test.js diff --git a/requests/Switcher API.postman_collection.json b/requests/Switcher API.postman_collection.json index c5f7f93..d4f505f 100644 --- a/requests/Switcher API.postman_collection.json +++ b/requests/Switcher API.postman_collection.json @@ -4786,34 +4786,6 @@ }, "response": [] }, - { - "name": "Slack - Feature Availability", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\r\n \"feature\": \"SLACK_INTEGRATION\"\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{url}}/slack/v1/availability", - "host": [ - "{{url}}" - ], - "path": [ - "slack", - "v1", - "availability" - ] - } - }, - "response": [] - }, { "name": "Slack - Ticket History Reset", "request": { @@ -5741,45 +5713,6 @@ } ] }, - { - "name": "API Management", - "item": [ - { - "name": "Management - Feature", - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "name": "Content-Type", - "type": "text", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n\t\"feature\": \"FEATURE\",\n\t\"parameters\": {\n \"value\": \"test\"\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{url}}/api-management/feature", - "host": [ - "{{url}}" - ], - "path": [ - "api-management", - "feature" - ] - } - }, - "response": [] - } - ] - }, { "name": "API Check", "event": [ diff --git a/src/api-docs/paths/path-api-management.js b/src/api-docs/paths/path-api-management.js deleted file mode 100644 index 5b43296..0000000 --- a/src/api-docs/paths/path-api-management.js +++ /dev/null @@ -1,43 +0,0 @@ -export default { - '/api-management/feature': { - post: { - tags: ['API Management'], - description: 'Run feature validation', - security: [{ appAuth: [] }], - requestBody: { - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - feature: { - type: 'string' - }, - parameters: { - type: 'object' - } - } - } - } - } - }, - responses: { - 200: { - description: 'Success', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - status: { - type: 'boolean' - } - } - } - } - } - } - } - } - } -}; \ No newline at end of file diff --git a/src/api-docs/paths/path-slack.js b/src/api-docs/paths/path-slack.js index 7fdf7b4..693bf42 100644 --- a/src/api-docs/paths/path-slack.js +++ b/src/api-docs/paths/path-slack.js @@ -2,46 +2,6 @@ import { pathParameter, queryParameter } from '../schemas/common'; import { commonSchemaContent } from './common'; export default { - '/slack/v1/availability': { - post: { - tags: ['Switcher Slack App'], - description: 'Check if the feature is available', - security: [{ bearerAuth: [] }], - requestBody: { - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - feature: { - type: 'string', - description: 'The feature to check' - } - } - } - } - } - }, - responses: { - 200: { - description: 'The feature is available', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - result: { - type: 'boolean', - description: 'The feature is available' - } - } - } - } - } - } - } - } - }, '/slack/v1/installation': { post: { tags: ['Slack App'], diff --git a/src/api-docs/swagger-document.js b/src/api-docs/swagger-document.js index d31742d..8c3824a 100644 --- a/src/api-docs/swagger-document.js +++ b/src/api-docs/swagger-document.js @@ -10,7 +10,6 @@ import pathPermission from './paths/path-permission'; import pathMetric from './paths/path-metric'; import pathSlack from './paths/path-slack'; import pathClient from './paths/path-client'; -import pathApiManagement from './paths/path-api-management'; import { commonSchema } from './schemas/common'; import adminSchema from './schemas/admin'; @@ -91,7 +90,6 @@ export default { ...pathPermission, ...pathMetric, ...pathClient, - ...pathSlack, - ...pathApiManagement + ...pathSlack } }; \ No newline at end of file diff --git a/src/app.js b/src/app.js index dcc8fca..1186f80 100644 --- a/src/app.js +++ b/src/app.js @@ -20,7 +20,6 @@ import metricRouter from './routers/metric'; import teamRouter from './routers/team'; import permissionRouter from './routers/permission'; import slackRouter from './routers/slack'; -import apiManagementRouter from './routers/api-management'; import schema from './client/schema'; import { appAuth, auth, resourcesAuth, slackAuth } from './middleware/auth'; import { clientLimiter, defaultLimiter } from './middleware/limiter'; @@ -51,7 +50,6 @@ app.use(metricRouter); app.use(teamRouter); app.use(permissionRouter); app.use(slackRouter); -app.use(apiManagementRouter); /** * GraphQL Routes diff --git a/src/external/switcher-api-facade.js b/src/external/switcher-api-facade.js index b5d3a25..b69b287 100644 --- a/src/external/switcher-api-facade.js +++ b/src/external/switcher-api-facade.js @@ -25,7 +25,6 @@ export const SwitcherKeys = Object.freeze({ ACCOUNT_IN_NOTIFY: 'ACCOUNT_IN_NOTIFY', ACCOUNT_OUT_NOTIFY: 'ACCOUNT_OUT_NOTIFY', SLACK_INTEGRATION: 'SLACK_INTEGRATION', - SLACK_UPDATE: 'SLACK_UPDATE', RATE_LIMIT: 'RATE_LIMIT', HTTPS_AGENT: 'HTTPS_AGENT' }); @@ -36,13 +35,8 @@ function switcherFlagResult(flag, message) { } } -export async function checkFeature(feature, params, restrictTo = SwitcherKeys) { +async function checkFeature(feature, params) { const switcher = Switcher.factory(); - const key = Object.values(restrictTo).find(element => element === feature); - - if (!key) - throw new BadRequestError('Invalid feature'); - return switcher.isItOn(feature, params, true); } @@ -191,21 +185,6 @@ export async function checkSlackIntegration(value) { ]), 'Slack Integration is not available.'); } -export async function checkSlackAvailability(admin, feature) { - if (process.env.SWITCHER_API_ENABLE != 'true') - return true; - - if (!process.env.SWITCHER_SLACK_JWT_SECRET) - return false; - - const result = await checkFeature(feature, [checkValue(admin._id)], [ - SwitcherKeys.SLACK_INTEGRATION, - SwitcherKeys.SLACK_UPDATE - ]); - - return result; -} - export function notifyAcCreation(adminid) { if (process.env.SWITCHER_API_ENABLE != 'true') return; @@ -247,18 +226,4 @@ export async function checkHttpsAgent(value) { return; return checkFeature(SwitcherKeys.HTTPS_AGENT, [checkRegex(value)]); -} - -export async function checkManagementFeature(feature, params) { - if (process.env.SWITCHER_API_ENABLE != 'true') - return true; - - const switcher = Switcher.factory(); - const entries = []; - - if (params?.value) { - entries.push(checkValue(params.value)); - } - - return switcher.isItOn(feature, entries); } \ No newline at end of file diff --git a/src/routers/api-management.js b/src/routers/api-management.js deleted file mode 100644 index baefa15..0000000 --- a/src/routers/api-management.js +++ /dev/null @@ -1,23 +0,0 @@ -import express from 'express'; -import { auth } from '../middleware/auth'; -import { responseException } from '../exceptions'; -import * as SwitcherAPI from '../external/switcher-api-facade'; -import { validate, verifyInputUpdateParameters } from '../middleware/validators'; -import { body } from 'express-validator'; - -const router = new express.Router(); - -router.post('/api-management/feature', auth, -verifyInputUpdateParameters(['feature', 'parameters']), [ - body('feature').isString().notEmpty(), - body('parameters').optional().isObject() -], validate, async (req, res) => { - try { - const status = await SwitcherAPI.checkManagementFeature(req.body.feature, req.body.parameters); - res.send({ status }); - } catch (e) { - responseException(res, e, 400); - } -}); - -export default router; \ No newline at end of file diff --git a/src/routers/slack.js b/src/routers/slack.js index f845ecc..cc228a9 100644 --- a/src/routers/slack.js +++ b/src/routers/slack.js @@ -46,15 +46,6 @@ const createTicketContent = (req) => { }; }; -router.post('/slack/v1/availability', auth, async (req, res) => { - try { - const result = await Services.checkAvailability(req.admin, req.body.feature); - res.send({ result }); - } catch (e) { - responseException(res, e, 400, req.body.feature); - } -}); - router.post('/slack/v1/installation', slackAuth, [ check('installation_payload').exists(), check('bot_payload').exists() diff --git a/src/services/slack.js b/src/services/slack.js index e5b5714..d7599ef 100644 --- a/src/services/slack.js +++ b/src/services/slack.js @@ -1,7 +1,7 @@ import Slack from '../models/slack'; import { TicketStatusType, SLACK_SUB, TicketValidationType } from '../models/slack_ticket'; import { BadRequestError, NotFoundError, PermissionError } from '../exceptions'; -import { checkSlackIntegration, checkSlackAvailability } from '../external/switcher-api-facade'; +import { checkSlackIntegration } from '../external/switcher-api-facade'; import { getConfig } from './config'; import { getDomainById } from './domain'; import { getEnvironment } from './environment'; @@ -68,10 +68,6 @@ export async function getSlack(where) { return query.exec(); } -export async function checkAvailability(admin, feature) { - return checkSlackAvailability(admin, feature); -} - export async function createSlackInstallation(args) { await checkSlackIntegration(args.team_id); diff --git a/tests/api-management.test.js b/tests/api-management.test.js deleted file mode 100644 index 6b8665b..0000000 --- a/tests/api-management.test.js +++ /dev/null @@ -1,122 +0,0 @@ -import mongoose from 'mongoose'; -import app from '../src/app'; -import request from 'supertest'; -import { - adminMasterAccount, - setupDatabase -} from './fixtures/db_api'; -import { Switcher } from 'switcher-client'; - -afterAll(async () => { - await new Promise(resolve => setTimeout(resolve, 1000)); - await mongoose.disconnect(); -}); - -describe('API Management', () => { - - let token; - - beforeAll(async () => { - await setupDatabase(); - - const res = await request(app) - .post('/admin/login') - .send({ - email: adminMasterAccount.email, - password: adminMasterAccount.password - }).expect(200); - - token = res.body.jwt.token; - }); - - beforeEach(async () => { - process.env.SWITCHER_API_ENABLE = true; - Switcher.forget('MY_FEATURE'); - }); - - test('API_MANAGEMENT - Should return TRUE when SWITCHER_API_ENABLE disabled', async () => { - process.env.SWITCHER_API_ENABLE = false; - - const res = await request(app) - .post('/api-management/feature') - .set('Authorization', `Bearer ${token}`) - .send({ - feature: 'MY_FEATURE' - }).expect(200); - - expect(res.body.status).toEqual(true); - }); - - test('API_MANAGEMENT - Should return TRUE when requesting feature `MY_FEATURE`', async () => { - Switcher.assume('MY_FEATURE').true(); - - const res = await request(app) - .post('/api-management/feature') - .set('Authorization', `Bearer ${token}`) - .send({ - feature: 'MY_FEATURE' - }).expect(200); - - expect(res.body.status).toEqual(true); - }); - - test('API_MANAGEMENT - Should return TRUE when requesting feature `MY_FEATURE` with parameters - value', async () => { - Switcher.assume('MY_FEATURE').false(); - - const res = await request(app) - .post('/api-management/feature') - .set('Authorization', `Bearer ${token}`) - .send({ - feature: 'MY_FEATURE', - parameters: { - value: 'my-value' - } - }).expect(200); - - expect(res.body.status).toEqual(false); - }); - - test('API_MANAGEMENT - Should NOT return when body has invalid payload', async () => { - await request(app) - .post('/api-management/feature') - .set('Authorization', `Bearer ${token}`) - .send({ - features: ['MY_FEATURE'] - }).expect(400); - }); - - test('API_MANAGEMENT - Should NOT return when API cannot respond', async () => { - await request(app) - .post('/api-management/feature') - .set('Authorization', `Bearer ${token}`) - .send({ - feature: 'MY_FEATURE_1' - }).expect(400); - }); - - test('API_MANAGEMENT - Should NOT return when feature not specified', async () => { - await request(app) - .post('/api-management/feature') - .set('Authorization', `Bearer ${token}`) - .send().expect(422); - }); - - test('API_MANAGEMENT - Should NOT return when paramaters is not an object', async () => { - await request(app) - .post('/api-management/feature') - .set('Authorization', `Bearer ${token}`) - .send({ - feature: 'MY_FEATURE', - parameters: 'my-value' - }).expect(422); - }); - - test('API_MANAGEMENT - Should NOT return when not logged', async () => { - await request(app) - .post('/api-management/feature') - .send({ - feature: 'MY_FEATURE' - }).expect(401); - }); - -}); \ No newline at end of file diff --git a/tests/slack.test.js b/tests/slack.test.js index 89aede4..33bf2b7 100644 --- a/tests/slack.test.js +++ b/tests/slack.test.js @@ -9,6 +9,7 @@ import { getConfig } from '../src/services/config'; import { mock1_slack_installation } from './fixtures/db_slack'; import { EnvType } from '../src/models/environment'; import Slack from '../src/models/slack'; +import { TicketValidationType } from '../src/models/slack_ticket'; import { setupDatabase, slack, @@ -18,7 +19,6 @@ import { groupConfigDocument, adminAccountToken } from './fixtures/db_api'; -import { TicketValidationType } from '../src/models/slack_ticket'; afterAll(async () => { await Slack.deleteMany().exec(); @@ -36,7 +36,7 @@ const generateToken = (expiresIn) => { }; const buildInstallation = async (team_id, domain) => { - const installation = Object.assign({}, mock1_slack_installation); + const installation = { ...mock1_slack_installation }; installation.domain = domain; installation.team_id = team_id; installation.bot_payload.app_id = 'APP_ID'; @@ -44,81 +44,6 @@ const buildInstallation = async (team_id, domain) => { return installation; }; -describe('Slack Feature Availability', () => { - const logger_status = process.env.SWITCHER_API_LOGGER == 'true'; - - beforeAll(async () => { - await setupDatabase(); - process.env.SWITCHER_API_ENABLE = true; - if (!logger_status) - process.env.SWITCHER_API_LOGGER = true; - }); - - afterAll(() => { - process.env.SWITCHER_API_ENABLE = false; - process.env.SWITCHER_API_LOGGER = logger_status; - process.env.SWITCHER_SLACK_JWT_SECRET = 'SLACK_APP_SECRET'; - }); - - test('SLACK_SUITE - Should check feature - Available (API enabled)', async () => { - Switcher.assume('SLACK_INTEGRATION').true(); - const response = await request(app) - .post('/slack/v1/availability') - .set('Authorization', `Bearer ${adminMasterAccountToken}`) - .send({ - feature: 'SLACK_INTEGRATION' - }).expect(200); - - expect(response.body.result).toBe(true); - }); - - test('SLACK_SUITE - Should check feature - Available (API disabled)', async () => { - process.env.SWITCHER_API_ENABLE = false; - const response = await request(app) - .post('/slack/v1/availability') - .set('Authorization', `Bearer ${adminMasterAccountToken}`) - .send({ - feature: 'SLACK_INTEGRATION' - }).expect(200); - - expect(response.body.result).toBe(true); - process.env.SWITCHER_API_ENABLE = true; - }); - - test('SLACK_SUITE - Should check feature - Not Available', async () => { - Switcher.assume('SLACK_INTEGRATION').false(); - const response = await request(app) - .post('/slack/v1/availability') - .set('Authorization', `Bearer ${adminMasterAccountToken}`) - .send({ - feature: 'SLACK_INTEGRATION' - }).expect(200); - - expect(response.body.result).toBe(false); - }); - - test('SLACK_SUITE - Should check - Not available: Invalid feature', async () => { - await request(app) - .post('/slack/v1/availability') - .set('Authorization', `Bearer ${adminMasterAccountToken}`) - .send({ - feature: 'INVALID_FEATURE_KEY' - }).expect(400); - }); - - test('SLACK_SUITE - Should check - Not available: No secret defined', async () => { - process.env.SWITCHER_SLACK_JWT_SECRET = ''; - const response = await request(app) - .post('/slack/v1/availability') - .set('Authorization', `Bearer ${adminMasterAccountToken}`) - .send({ - feature: 'SLACK_INTEGRATION' - }).expect(200); - - expect(response.body.result).toBe(false); - }); -}); - describe('Slack Installation', () => { beforeAll(setupDatabase); @@ -136,7 +61,7 @@ describe('Slack Installation', () => { }); test('SLACK_SUITE - Should save installation - Enterprise Account', async () => { - const enterpriseSlack = Object.assign({}, mock1_slack_installation); + const enterpriseSlack = { ...mock1_slack_installation }; enterpriseSlack.enterprise_id = 'ENTERPRISE_ACCNT'; const response = await request(app) @@ -177,7 +102,7 @@ describe('Slack Installation', () => { test('SLACK_SUITE - Should NOT save installation - Missing installation payload', async () => { //given - const slack_install = Object.assign({}, mock1_slack_installation); + const slack_install = { ...mock1_slack_installation }; delete slack_install.installation_payload; //test @@ -280,7 +205,7 @@ describe('Slack Installation', () => { test('SLACK_SUITE - Should find bot', async () => { //given - const installation = Object.assign({}, mock1_slack_installation); + const installation = { ...mock1_slack_installation }; installation.team_id = 'T_FIND_BOT'; installation.bot_payload.app_id = 'TEST_FIND_BOT1'; await Services.createSlackInstallation(installation); @@ -310,7 +235,7 @@ describe('Slack Installation', () => { test('SLACK_SUITE - Should find installation', async () => { //given - const installation = Object.assign({}, mock1_slack_installation); + const installation = { ...mock1_slack_installation }; installation.team_id = 'T_FIND_INSTALL'; installation.installation_payload.app_id = 'TEST_FIND_INSTALLATION1'; await Services.createSlackInstallation(installation); @@ -340,7 +265,7 @@ describe('Slack Installation', () => { test('SLACK_SUITE - Should find installation (Admin)', async () => { //given - const installation = Object.assign({}, mock1_slack_installation); + const installation = { ...mock1_slack_installation }; installation.team_id = 'T_FIND_INSTALL_ADMIN'; installation.installation_payload.app_id = 'TEST_FIND_INSTALLATION2'; await Services.createSlackInstallation(installation); @@ -356,7 +281,7 @@ describe('Slack Installation', () => { test('SLACK_SUITE - Should delete not authorized installation', async () => { //given - const installation = Object.assign({}, mock1_slack_installation); + const installation = { ...mock1_slack_installation }; installation.team_id = 'T_DELETE_INSTALL'; installation.installation_payload.app_id = 'TEST_DELETE_INSTALLATION1'; await Services.createSlackInstallation(installation); From 8ab0977c5cf993b8269a97149a4aba2b5b6ea73b Mon Sep 17 00:00:00 2001 From: petruki <31597636+petruki@users.noreply.github.com> Date: Sun, 22 Oct 2023 11:59:07 -0700 Subject: [PATCH 2/2] Fixed lint --- src/external/switcher-api-facade.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/external/switcher-api-facade.js b/src/external/switcher-api-facade.js index b69b287..d314cac 100644 --- a/src/external/switcher-api-facade.js +++ b/src/external/switcher-api-facade.js @@ -1,6 +1,6 @@ import { Switcher, checkValue, checkPayload, checkRegex } from 'switcher-client'; import { EnvType } from '../models/environment'; -import { BadRequestError, FeatureUnavailableError } from '../exceptions'; +import { FeatureUnavailableError } from '../exceptions'; import { getDomainById, getTotalDomainsByOwner } from '../services/domain'; import { getTotalGroupsByDomainId } from '../services/group-config'; import { getTotalConfigsByDomainId } from '../services/config';