Skip to content

Commit

Permalink
ft(highlight_&_comment):The user should be able the highlight the art…
Browse files Browse the repository at this point in the history
…icle and comment about it.
  • Loading branch information
Diama1 committed Jul 5, 2019
1 parent ea8a15c commit bc02b61
Show file tree
Hide file tree
Showing 6 changed files with 207 additions and 0 deletions.
56 changes: 56 additions & 0 deletions src/api/controllers/highlightController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import db from '../../sequelize/models';

const { Highlights } = db;
/**
* @author Diane Mahoro
* @class Highlight
* @description this class performs the whole of highlightings
*/
class Highlight {
/**
* @param {Object} req - Request object
* @param {Object} res - Response object
* @returns {Object} - Response object
*/
static async createHighlights(req, res) {
const { id } = req.user;
const {
highlightText, comment, occurencyNumber
} = req.body;
const { article } = req; // This contains the article
const response = await Highlights.findOne({
where: {
articleId: article.id,
userId: id,
highlightText,
occurencyNumber
}
});
if (!response) {
const { body } = article;
const regX = new RegExp(highlightText, 'g');
const count = (body.match(regX) || []).length;
if (count === 0 || occurencyNumber > count) {
return res.status(404).json({
Message: 'Highlight text not found'
});
}
const newHighlight = await Highlights.create({
articleId: article.id,
userId: id,
highlightText,
comment,
occurencyNumber,
});
return res.status(201).json({
Message: `Thank you for highlighting this text ${newHighlight.highlightText}`
});
}

return res.status(403).json({
Message: 'you have already highlighted this text.'
});
}
}

export default Highlight;
6 changes: 6 additions & 0 deletions src/api/routes/articlesRouter.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import checkLikesandDislikes from '../../middleware/checkLikesDislikes';
import paginate from '../../middleware/paginate';
import shareArticle from '../../middleware/shareArticle';
import stats from '../controllers/stats';
import highlight from '../controllers/highlightController';


const articlesRouter = Router();
Expand All @@ -40,6 +41,7 @@ const {
const { verifyToken, checkIsModerator } = Auth;
const { createRatings, UpdateRatings } = RatingController;
const { bookmark } = bookmarkController;
const { createHighlights } = highlight;

const { searchForArticle } = search;
const {
Expand Down Expand Up @@ -112,4 +114,8 @@ articlesRouter.get('/:slug/shares', slugExist, shares);
// block reported articles
articlesRouter.post('/:slug/block', verifyToken, checkIsModerator, validateBody('checkDescription'), slugExist, isAlreadBlocked, blockArticle);
articlesRouter.post('/:slug/unblock', verifyToken, checkIsModerator, slugExist, isNotBlocked, unBlockArticle);
// highlight the text in the article

articlesRouter.post('/:slug/highlight', verifyToken, validateBody('validateHighlight'), slugExist, createHighlights);

export default articlesRouter;
14 changes: 14 additions & 0 deletions src/helpers/validationSchemas.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,5 +126,19 @@ export default {
.max(5)
.required()
.label('Rating must be from 1 to 5 ')
}),
validateHighlight: Joi.object().keys({
highlightText: Joi.string()
.trim()
.required()
.label('The highlightText is required and should be a string'),
comment: Joi.string()
.trim()
.min(3)
.label('The comment should have at least 3 letters!'),
occurencyNumber: Joi.number()
.label('Occurrency should be a number')


})
};
36 changes: 36 additions & 0 deletions src/sequelize/migrations/20190627142139-create-highlights.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@


module.exports = {
up: (queryInterface, Sequelize) => queryInterface.createTable('Highlights', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
articleId: {
type: Sequelize.INTEGER
},
userId: {
type: Sequelize.INTEGER
},
highlightText: {
type: Sequelize.TEXT
},
comment: {
type: Sequelize.TEXT
},
occurencyNumber: {
type: Sequelize.INTEGER
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
}),
down: queryInterface => queryInterface.dropTable('Highlights')
};
13 changes: 13 additions & 0 deletions src/sequelize/models/highlights.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export default (sequelize, DataTypes) => {
const Highlights = sequelize.define('Highlights', {
articleId: DataTypes.INTEGER,
userId: DataTypes.INTEGER,
highlightText: DataTypes.TEXT,
comment: DataTypes.TEXT,
occurencyNumber: DataTypes.INTEGER
}, {});
Highlights.associate = () => {
// associations can be defined here
};
return Highlights;
};
82 changes: 82 additions & 0 deletions test/highlight.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import chai from 'chai';
import chaiHttp from 'chai-http';
import dotenv from 'dotenv';
import server from '../src/index';
import db from '../src/sequelize/models';
import tokenHelper from '../src/helpers/Token.helper';


const { User, Article } = db;
// eslint-disable-next-line no-unused-vars
const should = chai.should();

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

dotenv.config();

let newArticle;
const highlight = {
highlightText: 'Rwanda',
comment: 'Thank you',
occurencyNumber: 1
};

describe('Highlight the Article', () => {
let token;
before(async () => {
const user = {
firstName: 'Emy',
lastName: 'Rukundo',
username: 'mifeillee',
email: 'nimilleer@gmail.com',
password: 'Rukundo1!',
confirmPassword: 'Rukundo1!'
};
const newUser = await User.create(user);

token = await tokenHelper.generateToken({ id: newUser.id });

const article = {
title: 'Andela Kigali Launch',
description: 'Andela Rwanda, a technology company specializing in training software engineers on Thursday last week launched its Kigali office. Its new offices are housed within the University of Rwanda - College of Science and Technology, in Muhabura Block.',
body: 'Andela Rwanda, a technology company specializing in training software engineers on Thursday last week launched its Kigali office. Its new offices are housed within the University of Rwanda - College of Science and Technology, in Muhabura Block. The firm made their debut in Rwanda in July last year, with pan-African hub, the first of its kind. This was followed by the announcement in October of Clement Uwajeneza as the Country Director. The firm has a Memorandum of Understanding with the government to recruit, train and connect to market about 500 young software engineers in the country',
tagList: ['Tech', 'Kigali'],
authorId: newUser.id,
slug: 'slyg',
readtime: '1 min'
};
newArticle = await Article.create(article);
});
it('should highlight with comment or without', (done) => {
chai.request(server)
.post(`/api/articles/${newArticle.slug}/highlight`)
.set('token', token)
.send(highlight)
.end((err, res) => {
res.should.have.status(201);
expect(res.body.Message).to.be.a('string');
done();
});
});
it('should raise an error when the user highlights the same text ', (done) => {
chai.request(server)
.post(`/api/articles/${newArticle.slug}/highlight`)
.set('token', token)
.send(highlight)
.end((err, res) => {
res.should.have.status(403);
expect(res.body.Message).to.be.a('string');
done();
});
});
it('should raise an error when the user is not logged in', (done) => {
chai.request(server)
.post(`/api/articles/${newArticle.slug}/highlight`)
.set('token', ' ')
.end((err, res) => {
res.should.have.status(401);
done();
});
});
});

0 comments on commit bc02b61

Please sign in to comment.