diff --git a/src/app.ts b/src/app.ts index b83a5951..ff5a5a44 100644 --- a/src/app.ts +++ b/src/app.ts @@ -5,6 +5,7 @@ import cors from 'cors' import { dataSource } from './configs/dbConfig' import authRouter from './routes/auth/auth.route' import profileRouter from './routes/profile/profile.route' +import adminRouter from './routes/admin/admin.route' import passport from 'passport' import './configs/passport' import cookieParser from 'cookie-parser' @@ -22,6 +23,7 @@ app.get('/', (req, res) => { app.use('/api/auth', authRouter) app.use('/api/me', profileRouter) +app.use('/api/admin', adminRouter) export const startServer = async (port: number): Promise => { try { diff --git a/src/controllers/admin/user.controller.ts b/src/controllers/admin/user.controller.ts new file mode 100644 index 00000000..aeb23c57 --- /dev/null +++ b/src/controllers/admin/user.controller.ts @@ -0,0 +1,26 @@ +import type { Request, Response } from 'express' +import { getAllUsers } from '../../services/admin.service' +import type Profile from '../../entities/profile.entity' +import { ProfileTypes } from '../../enums' + +export const getAllUsersHandler = async ( + req: Request, + res: Response +): Promise => { + try { + const user = req.user as Profile + if (user.type !== ProfileTypes.ADMIN) { + res.status(403).json({ message: 'Only Admins are allowed' }) + } else { + const users = await getAllUsers() + if (users?.length === 0) { + res.status(404).json({ message: 'No users available' }) + } else { + res.status(200).json({ profiles: users }) + } + } + } catch (err) { + console.error('Error executing query', err) + res.status(500).json({ error: err }) + } +} diff --git a/src/routes/admin/admin.route.test.ts b/src/routes/admin/admin.route.test.ts new file mode 100644 index 00000000..d88ef533 --- /dev/null +++ b/src/routes/admin/admin.route.test.ts @@ -0,0 +1,86 @@ +import { startServer } from '../../app' +import type { Express } from 'express' +import supertest from 'supertest' +import Profile from '../../entities/profile.entity' +import { ProfileTypes } from '../../enums' +import { dataSource } from '../../configs/dbConfig' +import bcrypt from 'bcrypt' + +const port = Math.floor(Math.random() * (9999 - 3000 + 1)) + 3000 + +const randomString = Math.random().toString(36) +const randomStringAdmin = Math.random().toString(36) +let server: Express +let agent: supertest.SuperAgentTest +let adminAgent: supertest.SuperAgentTest + +describe('Get all users route', () => { + beforeAll(async () => { + server = await startServer(port) + agent = supertest.agent(server) + adminAgent = supertest.agent(server) + + const defaultUser = { + email: `test${randomString}@gmail.com`, + password: '123' + } + + await supertest(server) + .post('/api/auth/register') + .send(defaultUser) + .expect(201) + + await agent.post('/api/auth/login').send(defaultUser).expect(200) + + const adminUser = { + email: `test${randomStringAdmin}@gmail.com`, + password: 'admin123' + } + + const profileRepository = dataSource.getRepository(Profile) + + const hashedPassword = await bcrypt.hash(adminUser.password, 10) + const newProfile = profileRepository.create({ + primary_email: adminUser.email, + password: hashedPassword, + contact_email: '', + first_name: '', + last_name: '', + image_url: '', + linkedin_url: '', + type: ProfileTypes.ADMIN + }) + + await profileRepository.save(newProfile) + + await adminAgent.post('/api/auth/login').send(adminUser).expect(200) + }, 5000) + + it('should return a 401 when a valid access token is not provided', async () => { + await supertest(server).get('/api/admin/users').expect(401) + }) + + it('should return a 403 if user is not admin', async () => { + await agent.get('/api/admin/users').expect(403) + }) + + it('should return a 200 with all users if user is admin', async () => { + const response = await adminAgent.get('/api/admin/users').expect(200) + + const userProfiles = response.body.profiles + + userProfiles.forEach((userProfile: Partial) => { + expect(userProfile).toHaveProperty('created_at') + expect(userProfile).toHaveProperty('updated_at') + expect(userProfile).toHaveProperty('primary_email') + expect(userProfile).toHaveProperty('contact_email') + expect(userProfile).toHaveProperty('first_name') + expect(userProfile).toHaveProperty('last_name') + expect(userProfile).toHaveProperty('image_url') + expect(userProfile).toHaveProperty('linkedin_url') + expect(userProfile).toHaveProperty('type') + expect(userProfile).toHaveProperty('uuid') + expect(userProfile).not.toHaveProperty('password') + }) + }) +}) diff --git a/src/routes/admin/admin.route.ts b/src/routes/admin/admin.route.ts new file mode 100644 index 00000000..4bf7c01a --- /dev/null +++ b/src/routes/admin/admin.route.ts @@ -0,0 +1,9 @@ +import express from 'express' +import { getAllUsersHandler } from '../../controllers/admin/user.controller' +import { requireAuth } from '../../controllers/auth.controller' + +const adminRouter = express.Router() + +adminRouter.get('/users', requireAuth, getAllUsersHandler) + +export default adminRouter diff --git a/src/services/admin.service.ts b/src/services/admin.service.ts new file mode 100644 index 00000000..e4a9fa3d --- /dev/null +++ b/src/services/admin.service.ts @@ -0,0 +1,8 @@ +import { dataSource } from '../configs/dbConfig' +import Profile from '../entities/profile.entity' + +export const getAllUsers = async (): Promise => { + const profileRepository = dataSource.getRepository(Profile) + const allUsers = await profileRepository.find() + return allUsers +}