Skip to content

Commit

Permalink
Merge 1f40cbe into 0bbc9b2
Browse files Browse the repository at this point in the history
  • Loading branch information
truestbyheart committed Jul 15, 2019
2 parents 0bbc9b2 + 1f40cbe commit 95bfaa7
Show file tree
Hide file tree
Showing 13 changed files with 391 additions and 14 deletions.
115 changes: 115 additions & 0 deletions src/api/controllers/bookmarkController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import status from '../../helpers/constants/status.codes';
import errorSender from '../../helpers/error.sender';
import errorMessage from '../../helpers/constants/error.messages';
import model from '../models/index';
import generatePagination from '../../helpers/generate.pagination.details';

const {
Bookmark,
User,
Article,
Category
} = model;
/**
* @class
*/
export default class BookmarkController {
/**
* @author Daniel Mwangila
* @description This functions stores the bookmarked articles
* If the user request this operation for the second time it will delete the boorkmark
* This is to create the toggle effect.
* @static
* @param {object} req the request sent to be excuted
* @param {object} res the response after execution
* @return {*} void
* @memberof BookmarkController
*/
static async addBookmark(req, res) {
const { username } = req.user.user;
const { slug } = req.params;

try {
await Bookmark.create({
articleSlug: slug,
username
});
res.status(status.CREATED).json({
status: 201,
message: 'Bookmarked successfully'
});
} catch (error) {
const duplicationErrorCode = '23505';
if (error.original.code === duplicationErrorCode) {
await Bookmark.destroy({
where: {
username,
articleSlug: slug
}
});
res.status(status.OK).json({
status: 200,
message: 'Successfully removed bookmark'
});
} else {
errorSender(status.NOT_FOUND, res, 'Slug', errorMessage.noSlug);
}
}
}

/**
* @author Daniel Mwangila
* @description This funcrtion gets the users bookmarks from the database.
* @static
* @param {object} req the request sent to be excuted
* @param {object} res the response after execution
* @return {*} void
* @memberof BookmarkController
*/
static async getBookmarks(req, res) {
const { username } = req.user.user;
const emptyBookmarkList = 0;
const defaultOffset = 0;
const defaultLimit = 10;
const data = {};
const offset = req.query.offset || defaultOffset;
const limit = req.query.limit || defaultLimit;

const bookmarkList = await Bookmark.findAll({
attributes: ['articleSlug'],
where: {
username
},
include: {
model: Article,
required: true,
attributes: ['id', 'title', 'description'],
include: [{
model: User,
required: true,
attributes: ['firstName', 'lastName', 'profileImage']
}, {
model: Category,
as: 'Category',
attributes: ['name']
}]
},
offset,
limit
});
const count = bookmarkList.length;

const paginationDetail = generatePagination(count, bookmarkList, offset, limit);
data.paginationDetail = paginationDetail;
data.bookmarks = bookmarkList;

if (count > emptyBookmarkList) {
res.status(status.OK).json({
status: 200,
data
});
} else {
errorSender(status.NOT_FOUND, res, 'Bookmark', errorMessage.noBookmark);
}
}
}
2 changes: 1 addition & 1 deletion src/api/migrations/20190622195902-create-article.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export default {
title: { type: Sequelize.STRING, allowNull: false },
description: { type: Sequelize.TEXT, allowNull: false },
body: { type: Sequelize.TEXT, allowNull: false },
slug: { type: Sequelize.STRING, allowNull: false },
slug: { type: Sequelize.STRING, allowNull: false, unique: true },
coverImage: { type: Sequelize.TEXT, allowNull: false },
tagList: {
type: Sequelize.ARRAY(Sequelize.TEXT),
Expand Down
44 changes: 44 additions & 0 deletions src/api/migrations/20190701162027-create-bookmark.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
export default {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Bookmarks', {
articleSlug: {
type: Sequelize.STRING,
references: {
model: 'Articles',
key: 'slug'
},
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
allowNull: false
},
username: {
type: Sequelize.STRING,
references: {
model: 'Users',
key: 'username'
},
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
allowNull: false
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
})
.then(() =>
queryInterface
.addConstraint('Bookmarks', ['articleSlug', 'username'], {
type: 'primary key',
name: 'bookmarkId'
})
);
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Bookmarks');
}
};
24 changes: 18 additions & 6 deletions src/api/models/article.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ const slugRandomNumberTwo = 6;
const SlugDefaultNumber = 0;

export default (sequelize, DataTypes) => {
const Article = sequelize.define('Articles',
const Article = sequelize.define(
'Articles',
{
id: {
allowNull: false,
Expand Down Expand Up @@ -40,15 +41,20 @@ export default (sequelize, DataTypes) => {
paranoid: true,
hooks: {
beforeCreate(article) {
article.slug = slug(`${article.title}-${(
Math.random() * slugRandomNumberOne ** slugRandomNumberTwo || SlugDefaultNumber
).toString(slugRandomNumberOne)}`).toLowerCase();
article.slug = slug(
`${article.title}-${(
Math.random() * slugRandomNumberOne ** slugRandomNumberTwo ||
SlugDefaultNumber
).toString(slugRandomNumberOne)}`
).toLowerCase();
}
}
});
Article.associate = (models) => {
}
);
Article.associate = models => {
Article.belongsTo(models.User, {
foreignKey: 'author',
targetKey: 'id',
onDelete: 'CASCADE',
hooks: true
});
Expand All @@ -67,6 +73,12 @@ export default (sequelize, DataTypes) => {
onDelete: 'CASCADE',
sourceKey: 'slug'
});
Article.hasMany(models.Bookmark, {
foreignKey: 'articleSlug',
sourceKey: 'slug',
onDelete: 'CASCADE',
hooks: true
});
};

return Article;
Expand Down
40 changes: 40 additions & 0 deletions src/api/models/bookmark.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
export default (sequelize, DataTypes) => {
const bookmark = sequelize.define('Bookmark', {
articleSlug: {
type: DataTypes.STRING,
references: {
model: 'Article',
key: 'slug'
},
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
allowNull: false
},
username: {
type: DataTypes.STRING,
references: {
model: 'Users',
key: 'username'
},
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
allowNull: false
}
}, {});

bookmark.removeAttribute('id');

bookmark.associate = (models) => {
bookmark.belongsTo(models.Article,{
foreignKey: 'articleSlug',
targetKey: 'slug',
onDelete: 'CASCADE',
hooks: true
});
bookmark.belongsTo(models.User,{
foreignKey: 'username'
});

};
return bookmark;
};
3 changes: 2 additions & 1 deletion src/api/models/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ const models = {
Share: sequelize.import('./share'),
Highlight: sequelize.import('./highlight'),
Following: sequelize.import('./following'),
Comment: sequelize.import('./comment')
Comment: sequelize.import('./comment'),
Bookmark: sequelize.import('./bookmark')
};

Object.keys(models).forEach((key) => {
Expand Down
10 changes: 8 additions & 2 deletions src/api/models/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ export default (sequelize, DataTypes) => {
const User = sequelize.define('Users',
{
username: {
type: DataTypes.STRING
type: DataTypes.STRING,
unique: true
},
email: {
type: DataTypes.STRING
Expand Down Expand Up @@ -65,11 +66,15 @@ export default (sequelize, DataTypes) => {
User.associate = (models) => {
User.hasMany(models.Article, {
foreignKey: 'author',
sourceKey: 'id',
onDelete: 'CASCADE',
hooks: true
});
User.hasMany(models.Rating, {
foreignKey: 'userId'
foreignKey: 'userId'
});
User.hasMany(models.Bookmark, {
foreignKey: 'username',
});
User.hasMany(models.Highlight, {
foreignKey: 'userId',
Expand All @@ -91,5 +96,6 @@ export default (sequelize, DataTypes) => {

return queryResult;
};

return User;
};
11 changes: 11 additions & 0 deletions src/api/routes/bookmarkRouter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Router } from 'express';
import bookmarkController from '../controllers/bookmarkController';
import authorization from '../../middlewares/checkValidToken';

const route = new Router();

route.post('/:slug', authorization, bookmarkController.addBookmark);
route.get('/', authorization, bookmarkController.getBookmarks);


export default route;
3 changes: 3 additions & 0 deletions src/api/routes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import articleRouter from './articleRouter';
import profileRouter from './profileRouter';
import authorsRouter from './authorsRoutes';
import adminRouter from './adminRouter';
import bookmarkRouter from './bookmarkRouter';


const router = express();
router.use('/password-reset', resetRouter);
Expand All @@ -14,5 +16,6 @@ router.use('/authors', authorsRouter);
router.use('/profiles', profileRouter);

router.use('/admin', adminRouter);
router.use('/bookmarks', bookmarkRouter);

export default router;
2 changes: 1 addition & 1 deletion src/api/seeders/20190621184055-user.js
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ module.exports = {
password: hashedPassword,
createdAt: new Date(),
updatedAt: new Date()
}
},
],
{}),

Expand Down
20 changes: 20 additions & 0 deletions src/api/seeders/20190701190735-test-bookmarks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export default {
up: (queryInterface, Sequelize) => {
return queryInterface.bulkInsert('Bookmarks', [{
articleSlug:'How-to-create-sequalize-seeds',
username:'BurindiAlain2',
createdAt: new Date(),
updatedAt: new Date()
},
{
articleSlug:'How-to-create-sequalize-seedss',
username:'BurindiAlain2',
createdAt: new Date(),
updatedAt: new Date()
}], {});
},

down: (queryInterface, Sequelize) => {
return queryInterface.bulkDelete('Bookmarks', null, {});
}
};
7 changes: 4 additions & 3 deletions src/helpers/constants/error.messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ export default {
invalidLink: 'Invalid link provided',
incorectPassword: 'Incorect password provided',
notAllowed: 'Forbiden access',
emailLinkInvalid:
'The link provided is corrupt, please request a new one or try to click it again',
emailLinkInvalid: 'The link provided is corrupt, please request a new one or try to click it again',
noUser: "User doesn't exist.",
authenticationMessage: 'You have to login to perform this action.',
serverError: 'Something went wrong',
Expand Down Expand Up @@ -48,5 +47,7 @@ export default {
noComment: 'Invalid parent comment Id provided',
noCommentFound: 'No comments found. Try to reduce the provided entries or create a comment.',
parentCommentId: 'You can not reply to a reply',
notCommentOwner: 'You must be the owner of the comment in order to proceed'
notCommentOwner: 'You must be the owner of the comment in order to proceed',
noBookmark: 'You have no bookmarks',
noSlug: 'There is no article with the slug provided'
};
Loading

0 comments on commit 95bfaa7

Please sign in to comment.