Skip to content

Commit

Permalink
Merge pull request #56 from andela/ft-users-provide-feedback-167733848
Browse files Browse the repository at this point in the history
167733848:  Users provide feedback
  • Loading branch information
Oluwafayokemi committed Sep 16, 2019
2 parents 2b0b3eb + 77b499f commit ea4b31d
Show file tree
Hide file tree
Showing 7 changed files with 231 additions and 1 deletion.
34 changes: 34 additions & 0 deletions src/controllers/accommodationFeedback.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/* eslint-disable require-jsdoc */
import models from '../models';

const { AccommodationFeedback } = models;

export default class FeedbackController {
/**
* @param {Object} req the user's feedback
* @param {Object} res success or error object
* @returns {Object} details of the posted feedback
* @description Post a new feedback about an accommodation
*/
static async postFeedback(req, res) {
try {
const userId = req.user.id;
const { feedbackBody } = req.body;
const { accommodationId } = req.params;
const newFeedback = await AccommodationFeedback.create({
feedbackBody, accommodationId, userId
});


res.status(201).json({
status: 'success',
data: {
newFeedback: newFeedback.feedbackBody,
'User ID': newFeedback.userId
}
});
} catch (error) {
res.status(500).json({ status: 'error', error: error.message });
}
}
}
2 changes: 2 additions & 0 deletions src/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import likeController from './like';
import notificationController from './notification';
import commentController from './comment';
import accommodationController from './accommodation';
import accommodationFeedbackController from './accommodationFeedback';
import roomController from './room';
import tripController from './trips';
import ratingController from './rating';
Expand All @@ -15,6 +16,7 @@ export const RequestController = requestController;
export const CommentController = commentController;
export const AccommodationController = accommodationController;
export const LikeController = likeController;
export const AccommodationFeedbackController = accommodationFeedbackController;
export const NotificationController = notificationController;
export const RoomController = roomController;
export const TripController = tripController;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
module.exports = {
up: (queryInterface, Sequelize) => queryInterface.createTable('AccommodationFeedbacks', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
feedbackBody: {
type: Sequelize.STRING
},
accommodationId: {
type: Sequelize.INTEGER,
allowNull: false,
onDelete: 'CASCADE',
references: {
model: 'Accommodation',
key: 'id',
as: 'accommodationId',
},
},
userId: {
type: Sequelize.INTEGER,
onDelete: 'CASCADE',
allowNull: false,
references: {
model: 'Users',
key: 'id',
as: 'userId',
},
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
}),

down: (queryInterface) => queryInterface.dropTable('AccommodationFeedbacks')
};
26 changes: 26 additions & 0 deletions src/middlewares/validateAccommodationFeedback.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/* eslint-disable no-mixed-operators */
import helpers from '../helpers/Helpers';


const { extractErrors } = helpers;

export default (req, res, next) => {
/**
* @param {Object} req the user feedback
* @param {Object} res summary of the above feedback
* @param {function} next pass control to next middleware
* @description Validate the user's feedback inputs
*/
req
.checkParams('accommodationId', 'The accommodation ID must be a number')
.notEmpty()
.isInt();
const errors = req.validationErrors();
if (errors) {
return res.status(400).json({
status: 'error',
error: extractErrors(errors),
});
}
return next();
};
28 changes: 28 additions & 0 deletions src/models/accomodationfeedback.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

export default (sequelize, DataTypes) => {
const AccommodationFeedback = sequelize.define('AccommodationFeedback', {
feedbackBody: {
type: DataTypes.STRING,
allowNull: false,
},
deletedAt: {
type: DataTypes.DATE,
allowNull: true
}
}, {
paranoid: true
});

AccommodationFeedback.associate = (models) => {
AccommodationFeedback.belongsTo(models.Accommodation, {
foreignKey: 'accommodationId',
onDelete: 'CASCADE',
});
AccommodationFeedback.belongsTo(models.User, {
foreignKey: 'userId',
onDelete: 'CASCADE',
});
};

return AccommodationFeedback;
};
13 changes: 12 additions & 1 deletion src/routes/accommodation.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Router } from 'express';
import { AccommodationController } from '../controllers';
import { AccommodationController, AccommodationFeedbackController } from '../controllers';
import { checkToken, checkVerified } from '../middlewares';
import getImageFromRequest from '../middlewares/getImageFromRequest';
import ValidateAccommodation from '../middlewares/validateAccommodation';
import validateAccommodationFeedback from '../middlewares/validateAccommodationFeedback';
import CloudinaryConfig from '../middlewares/cloudinaryConfig';
import { authorize } from '../middlewares/authorize';
import ImageHandler from '../middlewares/imageHandler';
Expand All @@ -17,6 +18,16 @@ const { cloudinaryConfig } = CloudinaryConfig;

const { imageHandler } = ImageHandler;


// api/v1 is already prepended to the request
router.post(
'/accommodation/:accommodationId/feedback',
checkToken,
checkVerified,
validateAccommodationFeedback,
AccommodationFeedbackController.postFeedback
);

router.post(
'/accommodation',
checkToken,
Expand Down
86 changes: 86 additions & 0 deletions src/tests/accommodationFeedbac.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import chai from 'chai';
import chaiHttp from 'chai-http';
import server from '../index';
import models from '../models';
import helper from '../helpers/jwtHelper';

const { generateToken } = helper;

let userId;
let accommodationId;
let token;

const {
Accommodation,
User
} = models;

const { expect } = chai;
chai.should();
chai.use(chaiHttp);

before((done) => {
// Create a user
User.create({
firstName: 'TestUser',
lastName: 'Neo',
email: 'testEmail@domain.com',
password: 'password',
isVerified: true
}).then((user) => {
userId = user.id;
token = generateToken({
id: userId,
email: user.email,
isVerified: user.isVerified
});

Accommodation.create({
userId,
name: 'Kampala',
location: 'Southern Uganda',
type: 'chateau',
totalNumberOfRooms: 5,
owner: userId,
}).then((accommodation) => {
accommodationId = accommodation.id;
done();
});
});
});
describe('POST /accommodation/:accommodationId/feedback, Creating a new feedback', () => {
it('Should successfully create a feedback and return details of the new feedback', (done) => {
chai.request(server)
.post(`/api/v1/accommodation/${accommodationId}/feedback`)
.set('Authorization', `Bearer ${token}`)
.send({
feedbackBody: 'This is the feedback body',
userId,
accommodationId
})
.end((err, res) => {
// eslint-disable-next-line no-unused-expressions
expect(err).to.be.null;
expect(res).to.has.status(201);
expect(res.body.status).to.equal('success');
expect(res.body).to.haveOwnProperty('data');
done();
});
});
it('Should return 400 if not token is provided', (done) => {
chai.request(server)
.post('/api/v1/accommodation/1/feedback')
.send({
feedbackBody: 'This is the feedback body',
userId,
accommodationId
})
.end((err, res) => {
// eslint-disable-next-line no-unused-expressions
expect(res).to.has.status(400);
expect(res.body).to.haveOwnProperty('status');
expect(res.body).to.haveOwnProperty('error');
done();
});
});
});

0 comments on commit ea4b31d

Please sign in to comment.