Skip to content

Commit

Permalink
Add the approve mentor and create category endpoints (#63)
Browse files Browse the repository at this point in the history
  • Loading branch information
anjula-sack authored Sep 11, 2023
1 parent 9f3ad01 commit 538f1fb
Show file tree
Hide file tree
Showing 21 changed files with 349 additions and 84 deletions.
19 changes: 0 additions & 19 deletions .github/workflows/sonarQube.yml

This file was deleted.

17 changes: 17 additions & 0 deletions mocks.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
const randomString = Math.random().toString(36)

export const mockMentor = {
email: `mentor${randomString}@gmail.com`,
password: '123'
}

export const mockAdmin = {
email: `admin${randomString}@gmail.com`,
password: 'admin123'
}

export const mockUser = {
email: `user${randomString}@gmail.com`,
password: '123'
}

export const mentorApplicationInfo = {
application: [
{
Expand Down
27 changes: 27 additions & 0 deletions src/controllers/admin/category.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { Request, Response } from 'express'
import type Profile from '../../entities/profile.entity'
import { ProfileTypes } from '../../enums'
import { createCategory } from '../../services/admin/category.service'

export const addCategory = async (
req: Request,
res: Response
): Promise<void> => {
try {
const user = req.user as Profile
const { categoryName } = req.body

if (user.type !== ProfileTypes.ADMIN) {
res.status(403).json({ message: 'Only Admins are allowed' })
} else {
const { category, statusCode, message } = await createCategory(
categoryName
)

res.status(statusCode).json({ category, message })
}
} catch (err) {
console.error('Error executing query', err)
res.status(500).json({ error: err })
}
}
36 changes: 36 additions & 0 deletions src/controllers/admin/mentor.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import type { Request, Response } from 'express'
import { updateMentorStatus } from '../../services/admin/mentor.service'
import { ApplicationStatus, ProfileTypes } from '../../enums'
import type Profile from '../../entities/profile.entity'

export const mentorStatusHandler = async (
req: Request,
res: Response
): Promise<void> => {
try {
const user = req.user as Profile
const { status } = req.body
const { mentorId } = req.params

if (user.type !== ProfileTypes.ADMIN) {
res.status(403).json({ message: 'Only Admins are allowed' })
} else {
if (!(status.toUpperCase() in ApplicationStatus)) {
res.status(400).json({ message: 'Please provide a valid status' })
return
}
const { mentor, statusCode, message } = await updateMentorStatus(
mentorId,
status
)
res.status(statusCode).json({ mentor, message })
}
} catch (err) {
if (err instanceof Error) {
console.error('Error executing query', err)
res
.status(500)
.json({ error: 'Internal server error', message: err.message })
}
}
}
3 changes: 2 additions & 1 deletion src/controllers/admin/user.controller.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Request, Response } from 'express'
import { getAllUsers } from '../../services/admin.service'
import { getAllUsers } from '../../services/admin/user.service'
import type Profile from '../../entities/profile.entity'
import { ProfileTypes } from '../../enums'

Expand All @@ -9,6 +9,7 @@ export const getAllUsersHandler = async (
): Promise<void> => {
try {
const user = req.user as Profile

if (user.type !== ProfileTypes.ADMIN) {
res.status(403).json({ message: 'Only Admins are allowed' })
} else {
Expand Down
4 changes: 1 addition & 3 deletions src/controllers/mentor.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,12 @@ export const mentorApplicationHandler = async (
try {
const user = req.user as Profile
const { application, categoryId } = req.body

const { mentor, statusCode, message } = await createMentor(
user,
application,
categoryId
)
if (!mentor) {
res.status(404).json({ message: 'Mentor not created' })
}

res.status(statusCode).json({ mentor, message })
} catch (err) {
Expand Down
2 changes: 1 addition & 1 deletion src/enums/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ export enum EmailStatusTypes {
export enum ApplicationStatus {
PENDING = 'pending',
REJECTED = 'rejected',
ACCEPTED = 'accepted'
APPROVED = 'approved'
}
11 changes: 7 additions & 4 deletions src/routes/admin/admin.route.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import express from 'express'
import { getAllUsersHandler } from '../../controllers/admin/user.controller'
import { requireAuth } from '../../controllers/auth.controller'
import userRouter from './user/user.route'
import mentorRouter from './mentor/mentor.route'
import categoryRouter from './category/category.route'

const adminRouter = express.Router()
const adminRouter = express()

adminRouter.get('/users', requireAuth, getAllUsersHandler)
adminRouter.use('/users', userRouter)
adminRouter.use('/mentors', mentorRouter)
adminRouter.use('/categories', categoryRouter)

export default adminRouter
60 changes: 60 additions & 0 deletions src/routes/admin/category/category.route.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
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'
import { mockUser, mockAdmin } from '../../../../mocks'

const port = Math.floor(Math.random() * (9999 - 3000 + 1)) + 3000

let server: Express
let agent: supertest.SuperAgentTest
let adminAgent: supertest.SuperAgentTest

describe('Admin category routes', () => {
beforeAll(async () => {
server = await startServer(port)
agent = supertest.agent(server)
adminAgent = supertest.agent(server)

await supertest(server)
.post('/api/auth/register')
.send(mockUser)
.expect(201)
await agent.post('/api/auth/login').send(mockUser).expect(200)

const profileRepository = dataSource.getRepository(Profile)

const hashedPassword = await bcrypt.hash(mockAdmin.password, 10)
const newProfile = profileRepository.create({
primary_email: mockAdmin.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(mockAdmin).expect(200)
}, 5000)

it('should add a category', async () => {
await adminAgent
.post('/api/admin/categories')
.send({ categoryName: 'Computer Science' })
.expect(201)
})

it('should only allow admins to add a category', async () => {
await agent
.post('/api/admin/categories')
.send({ categoryName: 'Computer Science' })
.expect(403)
})
})
9 changes: 9 additions & 0 deletions src/routes/admin/category/category.route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import express from 'express'
import { requireAuth } from '../../../controllers/auth.controller'
import { addCategory } from '../../../controllers/admin/category.controller'

const categoryRouter = express.Router()

categoryRouter.post('/', requireAuth, addCategory)

export default categoryRouter
78 changes: 78 additions & 0 deletions src/routes/admin/mentor/mentor.route.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
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'
import { mentorApplicationInfo, mockAdmin, mockMentor } from '../../../../mocks'

const port = Math.floor(Math.random() * (9999 - 3000 + 1)) + 3000

let server: Express
let mentorAgent: supertest.SuperAgentTest
let adminAgent: supertest.SuperAgentTest
let mentorId: string

describe('Admin mentor routes', () => {
beforeAll(async () => {
server = await startServer(port)
mentorAgent = supertest.agent(server)
adminAgent = supertest.agent(server)

await mentorAgent.post('/api/auth/register').send(mockMentor).expect(201)
await mentorAgent.post('/api/auth/login').send(mockMentor).expect(200)

const profileRepository = dataSource.getRepository(Profile)
const hashedPassword = await bcrypt.hash(mockAdmin.password, 10)
const newProfile = profileRepository.create({
primary_email: mockAdmin.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(mockAdmin).expect(200)
const categoryResponse = await adminAgent
.post('/api/admin/categories')
.send({ categoryName: 'Computer Science' })
.expect(201)

const response = await mentorAgent
.post('/api/mentors')
.send({
...mentorApplicationInfo,
categoryId: categoryResponse.body.category.uuid
})
.expect(201)

mentorId = response.body.mentor.uuid
}, 5000)

it('should update the mentor application state', async () => {
await adminAgent
.put(`/api/admin/mentors/${mentorId}/status`)
.send({ status: 'approved' })
.expect(200)
})

it('should return 400 when an invalid status was provided', async () => {
await adminAgent
.put(`/api/admin/mentors/${mentorId}/status`)
.send({ status: 'invalid status' })
.expect(400)
})

it('should only allow admins to update the status', async () => {
await mentorAgent
.put(`/api/admin/mentors/${mentorId}/status`)
.send({ status: 'approved' })
.expect(403)
})
})
9 changes: 9 additions & 0 deletions src/routes/admin/mentor/mentor.route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import express from 'express'
import { requireAuth } from '../../../controllers/auth.controller'
import { mentorStatusHandler } from '../../../controllers/admin/mentor.controller'

const mentorRouter = express.Router()

mentorRouter.put('/:mentorId/status', requireAuth, mentorStatusHandler)

export default mentorRouter
Original file line number Diff line number Diff line change
@@ -1,47 +1,35 @@
import { startServer } from '../../app'
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 Profile from '../../../entities/profile.entity'
import { ProfileTypes } from '../../../enums'
import { dataSource } from '../../../configs/dbConfig'
import bcrypt from 'bcrypt'
import { mockAdmin, mockUser } from '../../../../mocks'

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', () => {
describe('Admin user routes', () => {
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)
.send(mockUser)
.expect(201)

await agent.post('/api/auth/login').send(defaultUser).expect(200)

const adminUser = {
email: `test${randomStringAdmin}@gmail.com`,
password: 'admin123'
}
await agent.post('/api/auth/login').send(mockUser).expect(200)

const profileRepository = dataSource.getRepository(Profile)

const hashedPassword = await bcrypt.hash(adminUser.password, 10)
const hashedPassword = await bcrypt.hash(mockAdmin.password, 10)
const newProfile = profileRepository.create({
primary_email: adminUser.email,
primary_email: mockAdmin.email,
password: hashedPassword,
contact_email: '',
first_name: '',
Expand All @@ -53,7 +41,7 @@ describe('Get all users route', () => {

await profileRepository.save(newProfile)

await adminAgent.post('/api/auth/login').send(adminUser).expect(200)
await adminAgent.post('/api/auth/login').send(mockAdmin).expect(200)
}, 5000)

it('should return a 401 when a valid access token is not provided', async () => {
Expand Down
9 changes: 9 additions & 0 deletions src/routes/admin/user/user.route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import express from 'express'
import { getAllUsersHandler } from '../../../controllers/admin/user.controller'
import { requireAuth } from '../../../controllers/auth.controller'

const userRouter = express.Router()

userRouter.get('/', requireAuth, getAllUsersHandler)

export default userRouter
Loading

0 comments on commit 538f1fb

Please sign in to comment.