Skip to content

Commit

Permalink
feat(cancel-order): add customer cancel order functionality (#94)
Browse files Browse the repository at this point in the history
- write tests
- implement endpoint for customer cancelation of orders

[Finishes #163354082]
  • Loading branch information
akhilome committed Jan 28, 2019
1 parent d791245 commit ff85753
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 28 deletions.
19 changes: 19 additions & 0 deletions server/controllers/orderController.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,25 @@ class OrderController {
return res.status(500).json({ error });
}
}

static async cancelOrder(req, res) {
const {
params: { orderId },
} = req;
if (Number.isNaN(Number(orderId))) return res.status(400).json({ status: 'error', message: 'order id must be a number' });
try {
const orderDetails = await pool.query('SELECT * FROM orders WHERE id=$1', [orderId]);
if (!orderDetails.rowCount) return res.status(404).json({ status: 'error', message: 'no such order exists' });
if (orderDetails.rows[0].author !== req.userId) return res.status(403).json({ status: 'error', message: 'you are not allowed to do that' });
await pool.query('DELETE FROM orders WHERE id=$1', [orderId]);
return res.status(204).json({
status: 'success',
message: 'order cancelled',
});
} catch (error) {
return res.status(500).json({ error });
}
}
}

export default OrderController;
9 changes: 8 additions & 1 deletion server/routes/ordersRouter.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,14 @@ const router = new Router();

router.get('/users/:id/orders', AuthHandler.authorize, OrderController.getAllUserOrders);
router.post('/orders', AuthHandler.authorize, Sanitize.newOrder, OrderController.newOrder);
router.get('/orders', AuthHandler.authorize, AuthHandler.authorizeAdmin, OrderController.getAllOrders);
router.delete('/orders/:orderId', AuthHandler.authorize, OrderController.cancelOrder);

router.get(
'/orders',
AuthHandler.authorize,
AuthHandler.authorizeAdmin,
OrderController.getAllOrders,
);

router.get(
'/orders/:id',
Expand Down
124 changes: 97 additions & 27 deletions tests/routes/orders.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ import { users, generateValidToken } from '../seed/seed';
chai.use(chaiHttp);

describe('POST /orders', () => {
const { validUser } = users;
const { validUser, admin } = users;

it('should successfuly place order for food', (done) => {
chai.request(app)
chai
.request(app)
.post('/api/v1/orders')
.set('x-auth', generateValidToken(validUser))
.send({ foodIds: [1, 2] })
Expand All @@ -31,9 +32,10 @@ describe('POST /orders', () => {
});

it('should successfuly place order for food if any food id is string', (done) => {
chai.request(app)
chai
.request(app)
.post('/api/v1/orders')
.set('x-auth', generateValidToken(validUser))
.set('x-auth', generateValidToken(admin))
.send({ foodIds: ['1', 2] })
.end((err, res) => {
if (err) done(err);
Expand All @@ -49,8 +51,9 @@ describe('POST /orders', () => {
});
});

it('should not place order if any provided food id doesn\'t exist', (done) => {
chai.request(app)
it("should not place order if any provided food id doesn't exist", (done) => {
chai
.request(app)
.post('/api/v1/orders')
.set('x-auth', generateValidToken(validUser))
.send({ foodIds: [1, 2, 6] })
Expand All @@ -65,7 +68,8 @@ describe('POST /orders', () => {
});

it('should respond with an error on provision of invalid data type', (done) => {
chai.request(app)
chai
.request(app)
.post('/api/v1/orders')
.set('x-auth', generateValidToken(validUser))
.send({ foodIds: [1, 2, 'lol'] })
Expand All @@ -82,7 +86,8 @@ describe('POST /orders', () => {

describe('GET /users/<userId>/orders', () => {
it('should successfully get all orders for specified user', (done) => {
chai.request(app)
chai
.request(app)
.get(`/api/v1/users/${users.validUser.id}/orders`)
.set('x-auth', generateValidToken(users.validUser))
.end((err, res) => {
Expand All @@ -95,8 +100,9 @@ describe('GET /users/<userId>/orders', () => {
});
});

it('should return a 401 if user isn\'t authenticated', (done) => {
chai.request(app)
it("should return a 401 if user isn't authenticated", (done) => {
chai
.request(app)
.get(`/api/v1/users/${users.validUser.id}/orders`)
.set('x-auth', '')
.end((err, res) => {
Expand All @@ -110,14 +116,17 @@ describe('GET /users/<userId>/orders', () => {
});

it('should only return orders placed by specified user', (done) => {
chai.request(app)
chai
.request(app)
.get(`/api/v1/users/${users.validUser.id}/orders`)
.set('x-auth', generateValidToken(users.validUser))
.end(async (err, res) => {
if (err) done(err);

try {
const orderCount = (await pool.query('SELECT * FROM orders WHERE author=$1', [users.validUser.id])).rowCount;
const orderCount = (await pool.query('SELECT * FROM orders WHERE author=$1', [
users.validUser.id,
])).rowCount;
res.body.orders.length.should.eql(orderCount);
done();
} catch (error) {
Expand All @@ -127,7 +136,8 @@ describe('GET /users/<userId>/orders', () => {
});

it('should return a 403 if user tries to get orders not placed by them', (done) => {
chai.request(app)
chai
.request(app)
.get(`/api/v1/users/${users.validUserTwo.id}/orders`)
.set('x-auth', generateValidToken(users.validUser))
.end((err, res) => {
Expand All @@ -140,7 +150,8 @@ describe('GET /users/<userId>/orders', () => {
});

it('should return a 400 if specified user id is not a number', (done) => {
chai.request(app)
chai
.request(app)
.get('/api/v1/users/dontdothis/orders')
.set('x-auth', generateValidToken(users.validUser))
.end((err, res) => {
Expand All @@ -157,7 +168,8 @@ describe('GET /users/<userId>/orders', () => {
describe('GET /orders', () => {
const { admin, validUser } = users;
it('should get all user orders if requester is admin', (done) => {
chai.request(app)
chai
.request(app)
.get('/api/v1/orders')
.set('x-auth', generateValidToken(admin))
.end((err, res) => {
Expand All @@ -167,14 +179,22 @@ describe('GET /orders', () => {
res.body.should.have.keys(['status', 'message', 'orders']);
res.body.orders.should.be.an('array');
res.body.orders[0].should.be.an('object');
res.body.orders[0].should.be.have.keys(['id', 'author', 'items', 'price', 'date', 'status']);
res.body.orders[0].should.be.have.keys([
'id',
'author',
'items',
'price',
'date',
'status',
]);
res.body.orders[0].items.should.be.an('array');
done();
});
});

it('should not get orders if user is not admin', (done) => {
chai.request(app)
chai
.request(app)
.get('/api/v1/orders')
.set('x-auth', generateValidToken(validUser))
.end((err, res) => {
Expand All @@ -189,7 +209,8 @@ describe('GET /orders', () => {

describe('GET /orders/:id', () => {
it('should not get order if user is not an admin', (done) => {
chai.request(app)
chai
.request(app)
.get(`/api/v1/orders/${1}`)
.set('x-auth', generateValidToken(users.validUser))
.end((err, res) => {
Expand All @@ -201,7 +222,8 @@ describe('GET /orders/:id', () => {
});

it('should not get order if invalid order id is provided', (done) => {
chai.request(app)
chai
.request(app)
.get('/api/v1/orders/somethingwrong')
.set('x-auth', generateValidToken(users.admin))
.end((err, res) => {
Expand All @@ -212,8 +234,9 @@ describe('GET /orders/:id', () => {
});
});

it('should return a 404 if order id doesn\'t exist', (done) => {
chai.request(app)
it("should return a 404 if order id doesn't exist", (done) => {
chai
.request(app)
.get('/api/v1/orders/5')
.set('x-auth', generateValidToken(users.admin))
.end((err, res) => {
Expand All @@ -225,7 +248,8 @@ describe('GET /orders/:id', () => {
});

it('should successfully fetch the order from the database', (done) => {
chai.request(app)
chai
.request(app)
.get('/api/v1/orders/1')
.set('x-auth', generateValidToken(users.admin))
.end((err, res) => {
Expand All @@ -241,9 +265,51 @@ describe('GET /orders/:id', () => {
});
});

describe('DELETE /orders/:orderId', () => {
it('should not cancel a non-existent order', async () => {
const res = await chai
.request(app)
.del('/api/v1/orders/334')
.set('x-auth', generateValidToken(users.validUser));

res.status.should.eql(404);
res.body.message.should.eql('no such order exists');
});

it('should not allow invalid params', async () => {
const res = await chai
.request(app)
.del('/api/v1/orders/33ds4')
.set('x-auth', generateValidToken(users.validUser));

res.status.should.eql(400);
res.body.message.should.eql('order id must be a number');
});

it("should not cancel another user's order", async () => {
const res = await chai
.request(app)
.del('/api/v1/orders/2')
.set('x-auth', generateValidToken(users.validUser));

res.status.should.eql(403);
res.body.message.should.eql('you are not allowed to do that');
});

it('should successfully cancel an order', async () => {
const res = await chai
.request(app)
.del('/api/v1/orders/2')
.set('x-auth', generateValidToken(users.admin));

res.status.should.eql(204);
});
});

describe('PUT /orders/:id', () => {
it('should not allow non admin users update order status', (done) => {
chai.request(app)
chai
.request(app)
.put('/api/v1/orders/1')
.set('x-auth', generateValidToken(users.validUser))
.send({ status: 'complete' })
Expand All @@ -256,7 +322,8 @@ describe('PUT /orders/:id', () => {
});

it('should return a 400 if invalid order id is provided', (done) => {
chai.request(app)
chai
.request(app)
.put('/api/v1/orders/invalidstuff')
.set('x-auth', generateValidToken(users.admin))
.send({ status: 'complete' })
Expand All @@ -270,7 +337,8 @@ describe('PUT /orders/:id', () => {
});

it('should not allow any text to be set as status', (done) => {
chai.request(app)
chai
.request(app)
.put('/api/v1/orders/1')
.set('x-auth', generateValidToken(users.admin))
.send({ status: 'this is wrong' })
Expand All @@ -285,7 +353,8 @@ describe('PUT /orders/:id', () => {
});

it('should successfully update the status of an order', (done) => {
chai.request(app)
chai
.request(app)
.put('/api/v1/orders/1')
.set('x-auth', generateValidToken(users.admin))
.send({ status: 'complete' })
Expand All @@ -301,7 +370,8 @@ describe('PUT /orders/:id', () => {
});

it('should not update the status of a non-existent order', (done) => {
chai.request(app)
chai
.request(app)
.put('/api/v1/orders/5')
.set('x-auth', generateValidToken(users.admin))
.send({ status: 'complete' })
Expand Down

0 comments on commit ff85753

Please sign in to comment.