Skip to content

Commit

Permalink
Merge a848f1b into e1be332
Browse files Browse the repository at this point in the history
  • Loading branch information
kodek-sleuth committed Aug 16, 2019
2 parents e1be332 + a848f1b commit 4b3f2f1
Show file tree
Hide file tree
Showing 15 changed files with 283 additions and 35 deletions.
31 changes: 30 additions & 1 deletion controllers/comment.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ import {

const {
comments, sequelize, articles, users,
highlightArticleComments
} = db;

class Comment {
static async createComment(req, res) {
const transaction = await sequelize.transaction();
const { body } = req.body;
const { slug } = req.params;
const { username } = req.decoded;
const transaction = await sequelize.transaction();
try {
const article = await articles.findOne({
where: {
Expand Down Expand Up @@ -140,5 +141,33 @@ class Comment {
});
}
}

static async highlightTextAndComment(req, res) {
try {
const { articleSlug } = req.params;
const {
comment, highlight, startIndex, stopIndex
} = req.body;
const { email } = req.decoded;
const article = await articles.findOne({ where: { slug: articleSlug } });
const user = await users.findOne({ where: { email } });
const highlightText = await highlightArticleComments.create({
startIndex,
stopIndex,
highlight,
comment,
articleSlug: article.slug,
authorId: user.id
}, { returning: true });
return res.status(201).json({
message: 'successfully commented on text',
highlightText
});
} catch (error) {
return res.status(500).json({
error: 'failed to comment on highlited text'
});
}
}
}
export default Comment;
2 changes: 1 addition & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ app.use(passport.session());
app.use(router);

app.all('*', (_req, res) => {
res.status(400).json({
res.status(404).json({
error: 'address not found',
});
});
Expand Down
1 change: 1 addition & 0 deletions middlewares/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './checkToken';
export * from './checkDb';
export * from './validations/highlightsValidations';
34 changes: 34 additions & 0 deletions middlewares/validations/highlightsValidations.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import db from '../../models';

const {
articles
} = db;

export const checkHighlightAndComment = async (req, res, next) => {
const {
highlight, startIndex, stopIndex, comment
} = req.body;
const { articleSlug } = req.params;
const article = await articles.findOne({
where: { slug: articleSlug }
});
if (!article) {
return res.status(404).json({ error: 'failed to find article' });
}
switch (true) {
case highlight === null || highlight === undefined
|| highlight === '' || startIndex === null
|| startIndex === undefined || startIndex === ''
|| stopIndex === null || stopIndex === undefined
|| stopIndex === '' || comment === null
|| comment === undefined || comment === '':
return res.status(400).json({ error: 'highlight, startIndex, stopIndex and comment cannot be left empty' });
case typeof startIndex === 'string' || stopIndex === 'string':
return res.status(400).json({ error: 'startIndex and stopIndex can only be number' });
case stopIndex > article.body.length:
return res.status(400).json({ error: 'stopIndex is invalid' });
case startIndex < 0:
return res.status(400).json({ error: 'startIndex is invalid' });
}
next();
};
File renamed without changes.
52 changes: 52 additions & 0 deletions migrations/20190729040846-createTableHighlightComments.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
export const up = (queryInterface, Sequelize) => queryInterface.createTable('highlightArticleComments', {
id: {
type: Sequelize.UUID,
defaultValue: Sequelize.UUIDV4,
allowNull: false,
primaryKey: true
},
startIndex: {
type: Sequelize.INTEGER,
allowNull: false
},
stopIndex: {
type: Sequelize.INTEGER,
allowNull: false
},
highlight: {
type: Sequelize.TEXT,
allowNull: false
},
comment: {
type: Sequelize.TEXT,
allowNull: false
},
articleSlug: {
type: Sequelize.STRING,
allowNull: false,
onDelete: 'CASCADE',
references: {
model: 'articles',
key: 'slug'
}
},
authorId: {
type: Sequelize.UUID,
allowNull: false,
onDelete: 'CASCADE',
references: {
model: 'users',
key: 'id'
}
},
createdAt: {
type: Sequelize.DATE,
default: true
},
updatedAt: {
type: Sequelize.DATE,
default: true
}
});

export const down = queryInterface => queryInterface.dropTable('highlightArticleComments');
1 change: 1 addition & 0 deletions models/articles.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export default (sequelize, DataTypes) => {
});
articles.associate = (models) => {
articles.belongsTo(models.users, { as: 'author', foreignKey: 'authorId' });
articles.hasMany(models.highlightArticleComments, { foreignKey: 'articleSlug', sourceKey: 'slug' });
articles.hasMany(models.bookmark, { foreignKey: 'articleId' });
articles.hasMany(models.ratings, { as: 'ratings', foreignKey: 'articleSlug', sourceKey: 'slug' });
articles.hasMany(models.likes, { as: 'likes', foreignKey: 'articleSlug', sourceKey: 'slug' });
Expand Down
58 changes: 58 additions & 0 deletions models/highlightArticleComments.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
export default (sequelize, DataTypes) => {
const highlightArticleComments = sequelize.define('highlightArticleComments', {
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
allowNull: false,
primaryKey: true
},
startIndex: {
type: DataTypes.INTEGER,
allowNull: false
},
stopIndex: {
type: DataTypes.INTEGER,
allowNull: false
},
highlight: {
type: DataTypes.TEXT,
allowNull: false
},
comment: {
type: DataTypes.TEXT,
allowNull: false
},
articleSlug: {
type: DataTypes.STRING,
allowNull: false,
onDelete: 'CASCADE',
references: {
model: 'articles',
key: 'slug'
}
},
authorId: {
type: DataTypes.UUID,
allowNull: false,
onDelete: 'CASCADE',
references: {
model: 'users',
key: 'id'
}
},
createdAt: {
type: DataTypes.DATE,
default: true
},
updatedAt: {
type: DataTypes.DATE,
default: true
}
},
{});
highlightArticleComments.associate = (models) => {
highlightArticleComments.belongsTo(models.users, { as: 'author', foreignKey: 'authorId' });
highlightArticleComments.belongsTo(models.articles, { foreignKey: 'articleSlug' });
};
return highlightArticleComments;
};
3 changes: 1 addition & 2 deletions models/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,7 @@ export default (sequelize, DataTypes) => {
users.hasMany(models.articles, { as: 'author', foreignKey: 'authorId' });
users.hasMany(models.ratings, { foreignKey: 'userId' });
users.hasMany(models.likes, { as: 'liker', foreignKey: 'userId', sourceKey: 'id' });
users.hasMany(models.articles, { foreignKey: 'authorId', allowNull: false });
users.hasMany(models.comments, { foreignKey: 'authorId', allowNull: false });
users.hasMany(models.highlightArticleComments, { foreignKey: 'authorId', sourceKey: 'id' });
users.hasMany(models.Follow, { as: 'User', foreignKey: 'followed' });
users.hasMany(models.bookmark, { foreignKey: 'userId', allowNull: false });
users.hasMany(models.articleStats, { foreignKey: 'userId' });
Expand Down
1 change: 0 additions & 1 deletion routes/api/articles.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,6 @@ router.put('/articles/:slug', checkToken, checkArticleOwner, uploadImage, valida
* description: Article deleted successfully
*/
router.delete('/articles/:slug', checkToken, checkArticleOwner, article.deleteArticle);

/**
* @swagger
* /api/articles/{slug}/share/{channel}:
Expand Down
3 changes: 2 additions & 1 deletion routes/api/comments.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import express from 'express';
import commentController from '../../controllers/comment';
import { checkToken } from '../../middlewares';
import { checkToken, checkHighlightAndComment } from '../../middlewares';

const router = express.Router();

Expand Down Expand Up @@ -39,5 +39,6 @@ const router = express.Router();
router.post('/articles/:slug/comments', checkToken, commentController.createComment);
router.get('/articles/:articleSlug/comments', commentController.getArticleComments);
router.delete('/comments/:commentId', checkToken, commentController.deleteComment);
router.post('/articles/:articleSlug/highlight/comments', checkToken, checkHighlightAndComment, commentController.highlightTextAndComment);

export default router;
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ export const up = (queryInterface, Sequelize) => queryInterface.bulkInsert(
{}
);

const down = (queryInterface, Sequelize) => queryInterface.bulkDelete('comments', null, {});
const down = (queryInterface, Sequelize) => queryInterface.bulkDelete('comments', null, {});
67 changes: 67 additions & 0 deletions tests/comment.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,4 +177,71 @@ describe('Create, Get and Delete Comment', () => {
done();
});
});
it('Should let user comment on highlited text in an article with valid details', (done) => {
chai
.request(app)
.post(`/api/articles/${slugArticle}/highlight/comments`)
.set('Authorization', `Bearer ${authToken}`)
.send(user.highlightText)
.end((err, res) => {
expect(res.statusCode).to.be.equal(201);
expect(res.body.message).to.be.equal('successfully commented on text');
expect(res.body.highlightText).to.have.property('comment');
expect(res.body.highlightText).to.have.property('startIndex');
expect(res.body.highlightText).to.have.property('stopIndex');
done();
});
});
it('Should not let user comment on highlited text in an article with invalid Indexes', (done) => {
chai
.request(app)
.post(`/api/articles/${slugArticle}/highlight/comments`)
.set('Authorization', `Bearer ${authToken}`)
.send(user.invalidEndIndex)
.end((err, res) => {
expect(res.statusCode).to.be.equal(400);
expect(res.body.error).to.be.equal('stopIndex is invalid');
expect(res.body).to.have.property('error');
done();
});
});
it('Should not let user comment on highlited text in an article with invalid null body', (done) => {
chai
.request(app)
.post(`/api/articles/${slugArticle}/highlight/comments`)
.set('Authorization', `Bearer ${authToken}`)
.send(user.nullIndex)
.end((err, res) => {
expect(res.statusCode).to.be.equal(400);
expect(res.body.error).to.be.equal('highlight, startIndex, stopIndex and comment cannot be left empty');
expect(res.body).to.have.property('error');
done();
});
});
it('Should not let user comment on highlited text in an article with negative Indexes than article', (done) => {
chai
.request(app)
.post(`/api/articles/${slugArticle}/highlight/comments`)
.set('Authorization', `Bearer ${authToken}`)
.send(user.negativeIndex)
.end((err, res) => {
expect(res.statusCode).to.be.equal(400);
expect(res.body.error).to.be.equal('startIndex is invalid');
expect(res.body).to.have.property('error');
done();
});
});
it('Should not let user comment on highlited text in an article with invalidSlug', (done) => {
chai
.request(app)
.post('/api/articles/thelondon/highlight/comments')
.set('Authorization', `Bearer ${authToken}`)
.send(user.highlightText)
.end((err, res) => {
expect(res.statusCode).to.be.equal(404);
expect(res.body.error).to.be.equal('failed to find article');
expect(res.body).to.have.property('error');
done();
});
});
});
33 changes: 32 additions & 1 deletion tests/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,33 @@ const article2 = {
tagList: 'nodejs, programming'
};

const highlightText = {
startIndex: 1,
stopIndex: 24,
highlight: 'language which has many',
comment: 'change tense'
};

const invalidEndIndex = {
startIndex: 1,
stopIndex: 1000,
highlight: 'language which has many',
comment: 'change tense'
};

const nullIndex = {
startIndex: 1,
highlight: 'language which has many',
comment: 'change tense'
};

const negativeIndex = {
startIndex: -12,
stopIndex: 20,
highlight: 'language which has many',
comment: 'change tense'
};

// twitter user
export const twitterUser = (req, res, next) => {
req.user = {
Expand Down Expand Up @@ -234,5 +261,9 @@ export default {
secondLogin,
givenArticle,
givenComment1,
givenComment2
givenComment2,
highlightText,
invalidEndIndex,
nullIndex,
negativeIndex
};
Loading

0 comments on commit 4b3f2f1

Please sign in to comment.