diff --git a/api/public/swagger.yaml b/api/public/swagger.yaml index b5a27cd..f0b127f 100644 --- a/api/public/swagger.yaml +++ b/api/public/swagger.yaml @@ -758,6 +758,27 @@ paths: application/json: schema: $ref: '#/components/schemas/ClientPayload' + get: + operationId: GetAllClients + responses: + '200': + description: Ok + content: + application/json: + schema: + items: + $ref: '#/components/schemas/ClientPayload' + type: array + examples: + 'Example 1': + value: [{clientId: someClientID1234, clientSecret: someRandomCryptoString, accessTokenExpiration: 86400}, {clientId: someOtherClientID, clientSecret: someOtherRandomCryptoString, accessTokenExpiration: 86400}] + summary: 'Admin only task. Returns the list of all the clients *' + tags: + - Client + security: + - + bearerAuth: [] + parameters: [] /SASjsApi/code/execute: post: operationId: ExecuteCode diff --git a/api/src/controllers/client.ts b/api/src/controllers/client.ts index b6b6350..e71ef9b 100644 --- a/api/src/controllers/client.ts +++ b/api/src/controllers/client.ts @@ -1,4 +1,4 @@ -import { Security, Route, Tags, Example, Post, Body } from 'tsoa' +import { Security, Route, Tags, Example, Post, Body, Get } from 'tsoa' import Client, { ClientPayload, @@ -29,6 +29,28 @@ export class ClientController { ): Promise { return createClient(body) } + + /** + * @summary Admin only task. Returns the list of all the clients + */ + @Example([ + { + clientId: 'someClientID1234', + clientSecret: 'someRandomCryptoString', + accessTokenExpiration: NUMBER_OF_SECONDS_IN_A_DAY, + refreshTokenExpiration: NUMBER_OF_SECONDS_IN_A_DAY * 30 + }, + { + clientId: 'someOtherClientID', + clientSecret: 'someOtherRandomCryptoString', + accessTokenExpiration: NUMBER_OF_SECONDS_IN_A_DAY, + refreshTokenExpiration: NUMBER_OF_SECONDS_IN_A_DAY * 30 + } + ]) + @Get('/') + public async getAllClients(): Promise { + return getAllClients() + } } const createClient = async (data: ClientPayload): Promise => { @@ -60,3 +82,13 @@ const createClient = async (data: ClientPayload): Promise => { refreshTokenExpiration: savedClient.refreshTokenExpiration } } + +const getAllClients = async (): Promise => { + return Client.find({}).select({ + _id: 0, + clientId: 1, + clientSecret: 1, + accessTokenExpiration: 1, + refreshTokenExpiration: 1 + }) +} diff --git a/api/src/routes/api/client.ts b/api/src/routes/api/client.ts index ae9f4d7..77ed93d 100644 --- a/api/src/routes/api/client.ts +++ b/api/src/routes/api/client.ts @@ -1,6 +1,7 @@ import express from 'express' import { ClientController } from '../../controllers' import { registerClientValidation } from '../../utils' +import { authenticateAccessToken, verifyAdmin } from '../../middlewares' const clientRouter = express.Router() @@ -17,4 +18,19 @@ clientRouter.post('/', async (req, res) => { } }) +clientRouter.get( + '/', + authenticateAccessToken, + verifyAdmin, + async (req, res) => { + const controller = new ClientController() + try { + const response = await controller.getAllClients() + res.send(response) + } catch (err: any) { + res.status(403).send(err.toString()) + } + } +) + export default clientRouter diff --git a/api/src/routes/api/spec/client.spec.ts b/api/src/routes/api/spec/client.spec.ts index 22e8b5d..a901a65 100644 --- a/api/src/routes/api/spec/client.spec.ts +++ b/api/src/routes/api/spec/client.spec.ts @@ -5,6 +5,7 @@ import request from 'supertest' import appPromise from '../../../app' import { UserController, ClientController } from '../../../controllers/' import { generateAccessToken, saveTokensInDB } from '../../../utils' +import { NUMBER_OF_SECONDS_IN_A_DAY } from '../../../model/Client' const client = { clientId: 'someclientID', @@ -26,6 +27,7 @@ describe('client', () => { let app: Express let con: Mongoose let mongoServer: MongoMemoryServer + let adminAccessToken: string const userController = new UserController() const clientController = new ClientController() @@ -34,6 +36,18 @@ describe('client', () => { mongoServer = await MongoMemoryServer.create() con = await mongoose.connect(mongoServer.getUri()) + + const dbUser = await userController.createUser(adminUser) + adminAccessToken = generateAccessToken({ + clientId: client.clientId, + userId: dbUser.id + }) + await saveTokensInDB( + dbUser.id, + client.clientId, + adminAccessToken, + 'refreshToken' + ) }) afterAll(async () => { @@ -43,22 +57,6 @@ describe('client', () => { }) describe('create', () => { - let adminAccessToken: string - - beforeAll(async () => { - const dbUser = await userController.createUser(adminUser) - adminAccessToken = generateAccessToken({ - clientId: client.clientId, - userId: dbUser.id - }) - await saveTokensInDB( - dbUser.id, - client.clientId, - adminAccessToken, - 'refreshToken' - ) - }) - afterEach(async () => { const collections = mongoose.connection.collections const collection = collections['clients'] @@ -157,4 +155,80 @@ describe('client', () => { expect(res.body).toEqual({}) }) }) + + describe('get', () => { + afterEach(async () => { + const collections = mongoose.connection.collections + const collection = collections['clients'] + await collection.deleteMany({}) + }) + + it('should respond with an array of all clients', async () => { + await clientController.createClient(newClient) + await clientController.createClient({ + clientId: 'clientID', + clientSecret: 'clientSecret' + }) + + const res = await request(app) + .get('/SASjsApi/client') + .auth(adminAccessToken, { type: 'bearer' }) + .send() + .expect(200) + + const expected = [ + { + clientId: 'newClientID', + clientSecret: 'newClientSecret', + accessTokenExpiration: NUMBER_OF_SECONDS_IN_A_DAY, + refreshTokenExpiration: NUMBER_OF_SECONDS_IN_A_DAY * 30 + }, + { + clientId: 'clientID', + clientSecret: 'clientSecret', + accessTokenExpiration: NUMBER_OF_SECONDS_IN_A_DAY, + refreshTokenExpiration: NUMBER_OF_SECONDS_IN_A_DAY * 30 + } + ] + + expect(res.body).toEqual(expected) + }) + + it('should respond with Unauthorized if access token is not present', async () => { + const res = await request(app).get('/SASjsApi/client').send().expect(401) + + expect(res.text).toEqual('Unauthorized') + expect(res.body).toEqual({}) + }) + + it('should respond with Forbideen if access token is not of an admin account', async () => { + const user = { + displayName: 'User 2', + username: 'username2', + password: '12345678', + isAdmin: false, + isActive: true + } + const dbUser = await userController.createUser(user) + const accessToken = generateAccessToken({ + clientId: client.clientId, + userId: dbUser.id + }) + await saveTokensInDB( + dbUser.id, + client.clientId, + accessToken, + 'refreshToken' + ) + + const res = await request(app) + .get('/SASjsApi/client') + .auth(accessToken, { type: 'bearer' }) + .send() + .expect(401) + + expect(res.text).toEqual('Admin account required') + expect(res.body).toEqual({}) + }) + }) })