Skip to content

Commit 0bf727b

Browse files
committed
Refactors user and auth routes
- Adds update password functionality - Separates auth and user routes - Adds an update password validator - Adds unit and integration tests
1 parent 95d493b commit 0bf727b

File tree

9 files changed

+169
-11
lines changed

9 files changed

+169
-11
lines changed

app.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@ const joiErrors = require('./server/middlewares/joiErrors');
88

99
// Require our routes and passport into the application
1010
const todosRouter = require('./server/routes').todosRouter();
11-
const userRouter = require('./server/routes').userRouter();
11+
const authRouter = require('./server/routes').authRouter();
12+
const usersRouter = require('./server/routes').usersRouter();
1213
const { passportAuth } = require('./server/config/passport');
1314

1415
passportAuth(passport);
1516

17+
const apiPrefix = '/api';
18+
1619
// Set up the express app
1720
const app = express();
1821

@@ -29,8 +32,10 @@ app.use(logger('dev'));
2932
app.use(bodyParser.json());
3033
app.use(bodyParser.urlencoded({ extended: false }));
3134

32-
app.use('/api', passport.authenticate('jwt', { session: false }), todosRouter);
33-
app.use(userRouter);
35+
app.use(apiPrefix, passport.authenticate('jwt', { session: false }));
36+
app.use(apiPrefix, usersRouter);
37+
app.use(apiPrefix, todosRouter);
38+
app.use(authRouter);
3439

3540
app.use(joiErrors);
3641

server/controllers/users.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,35 @@ async function login(req, res) {
5555
});
5656
}
5757

58+
const updatePassword = async (req, res) => {
59+
const { body, params } = req;
60+
const user = await User.findByPk(params.userId);
61+
62+
if (!user) {
63+
return res.status(404).send({
64+
success: false,
65+
message: 'User not found',
66+
});
67+
}
68+
69+
if (user.id !== req.user.id) {
70+
return res.status(403).send({
71+
success: false,
72+
message: 'Forbidden, you can only update your own password',
73+
});
74+
}
75+
76+
await user.update({
77+
password: body.password,
78+
});
79+
return res.status(200).send({
80+
success: true,
81+
message: 'Password updated successfully',
82+
});
83+
};
84+
5885
module.exports = {
5986
signup,
6087
login,
88+
updatePassword,
6189
};

server/routes/userRouter.js renamed to server/routes/authRouter.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ const usersController = require('../controllers').users;
44
const validator = require('../validators/validators');
55
const asyncHandler = require('../middlewares/asyncHandler');
66

7-
function userRoutes() {
8-
const userRouter = express.Router();
7+
function authRoutes() {
8+
const authRouter = express.Router();
99

10-
userRouter.route('/auth/signup')
10+
authRouter.route('/auth/signup')
1111
.post(celebrate({ body: validator.validateUser }), asyncHandler(usersController.signup));
12-
userRouter.route('/auth/login')
12+
authRouter.route('/auth/login')
1313
.post(celebrate({ body: validator.validateLogin }), asyncHandler(usersController.login));
1414

15-
return userRouter;
15+
return authRouter;
1616
}
1717

18-
module.exports = userRoutes;
18+
module.exports = authRoutes;

server/routes/index.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
const todosRouter = require('./todosRouter');
2-
const userRouter = require('./userRouter');
2+
const authRouter = require('./authRouter');
3+
const usersRouter = require('./usersRouter');
34

45

56
module.exports = {
67
todosRouter,
7-
userRouter,
8+
authRouter,
9+
usersRouter,
810
};

server/routes/usersRouter.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
const express = require('express');
2+
const { celebrate } = require('celebrate');
3+
const usersController = require('../controllers').users;
4+
const validator = require('../validators/validators');
5+
const asyncHandler = require('../middlewares/asyncHandler');
6+
7+
function userRoutes() {
8+
const userRouter = express.Router();
9+
10+
userRouter.route('/users/:userId')
11+
.patch(celebrate({
12+
body: validator.validatePassword,
13+
}), asyncHandler(usersController.updatePassword));
14+
15+
return userRouter;
16+
}
17+
18+
module.exports = userRoutes;
File renamed without changes.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
const chai = require('chai');
2+
3+
const { expect } = chai;
4+
const chaiHttp = require('chai-http');
5+
const app = require('../../../app');
6+
const { deleteTestUser } = require('../utils');
7+
8+
chai.use(chaiHttp);
9+
10+
describe('A user', () => {
11+
before(async () => {
12+
await chai
13+
.request(app)
14+
.post('/auth/signup')
15+
.send({ username: 'ironman@starkindustries.com', password: 'breaker' });
16+
17+
const res1 = await chai
18+
.request(app)
19+
.post('/auth/login')
20+
.send({ username: 'ironman@starkindustries.com', password: 'breaker' });
21+
22+
token = res1.body.token;
23+
userId = res1.body.user.id;
24+
});
25+
26+
after(async () => {
27+
await deleteTestUser('ironman@starkindustries.com');
28+
});
29+
30+
describe('Update password', () => {
31+
it('Should return 200 Success, on successfully updating the password of a user.', async () => {
32+
const res = await chai
33+
.request(app)
34+
.patch(`/api/users/${userId}`)
35+
.set('Authorization', `Bearer ${token}`)
36+
.send({ password: '1234567890' });
37+
38+
expect(res).to.have.status(200);
39+
});
40+
});
41+
42+
});

server/tests/unit/user.spec.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,20 @@ const chai = require('chai');
33
const { expect } = chai;
44
const sinonChai = require('sinon-chai');
55
const { mockReq, mockRes } = require('sinon-express-mock');
6+
const { User } = require('../../models');
67
const usersController = require('../../controllers/users');
78
const { deleteTestUser } = require('../utils');
89

910
chai.use(sinonChai);
1011

1112
describe('user.controller', () => {
13+
before(async () => {
14+
user = await User.create({ username: 'testuserchange@test.com', password: '1234567' });
15+
});
16+
1217
after(async () => {
1318
await deleteTestUser('testuser3@test.com');
19+
await deleteTestUser('testuserchange@test.com');
1420
});
1521

1622
describe('signup', () => {
@@ -39,6 +45,7 @@ describe('user.controller', () => {
3945
expect(res.status).to.have.been.calledWith(400);
4046
});
4147
});
48+
4249
describe('login', () => {
4350
it('should return authentication failed when a username is not found', async () => {
4451
const request = {
@@ -53,4 +60,55 @@ describe('user.controller', () => {
5360
expect(res.status).to.have.been.calledWith(401);
5461
});
5562
});
63+
64+
describe('update password', () => {
65+
it('should return a 404 when a user is not found', async () => {
66+
const request = {
67+
body: {
68+
password: '12345678',
69+
},
70+
params: {
71+
userId: 10000,
72+
},
73+
};
74+
const req = mockReq(request);
75+
const res = mockRes();
76+
await usersController.updatePassword(req, res);
77+
expect(res.status).to.have.been.calledWith(404);
78+
});
79+
it('should return a 403 forbidden when a user tries to update the password of another user', async () => {
80+
const request = {
81+
body: {
82+
password: '12345678',
83+
},
84+
params: {
85+
userId: user.id,
86+
},
87+
user: {
88+
id: 44
89+
}
90+
};
91+
const req = mockReq(request);
92+
const res = mockRes();
93+
await usersController.updatePassword(req, res);
94+
expect(res.status).to.have.been.calledWith(403);
95+
});
96+
it('should return a 200 on successful update of the password of a user', async () => {
97+
const request = {
98+
body: {
99+
password: '12345678',
100+
},
101+
params: {
102+
userId: user.id,
103+
},
104+
user: {
105+
id: user.id
106+
}
107+
};
108+
const req = mockReq(request);
109+
const res = mockRes();
110+
await usersController.updatePassword(req, res);
111+
expect(res.status).to.have.been.calledWith(200);
112+
});
113+
});
56114
});

server/validators/validators.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,14 @@ const validateLogin = Joi.object().keys({
1919
password: Joi.string().required(),
2020
});
2121

22+
const validatePassword = Joi.object().keys({
23+
password: Joi.string().alphanum().min(7).required(),
24+
});
25+
2226
module.exports = {
2327
validateTodo,
2428
validateTodoItem,
2529
validateUser,
2630
validateLogin,
31+
validatePassword,
2732
};

0 commit comments

Comments
 (0)