Skip to content

Commit

Permalink
Merge 118bf77 into b6a5be6
Browse files Browse the repository at this point in the history
  • Loading branch information
nkpremices committed Jun 25, 2019
2 parents b6a5be6 + 118bf77 commit 6edf9ca
Show file tree
Hide file tree
Showing 26 changed files with 1,144 additions and 43 deletions.
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,5 @@ DEV_DATABASE=theDevelopementDbName
TEST_DATABASE=theTestDbName
HOST=TheDatabaseHost
DB_PORT =theDatabasePort

TEST_USER_TOKEN=theTestUserTokenForTestingPurposes
3 changes: 3 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@ src/api/migrations

# Seeders
src/api/seeders

# Models
src/api/models
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,12 @@
"functions": 100,
"statements": 80,
"exclude": [
"src/index.js",
"src/configs/environments.js",
"src/configs/redisConfigs.js",
"src/configs/passport.js",
"src/index.js"
"src/api/models",
"src/index.js",
"src/configs/passport.js"
]
},
"author": "Andela Simulations Programme",
Expand Down
51 changes: 51 additions & 0 deletions src/api/controllers/articleTagController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import models from '../models/index';
import status from '../../helpers/constants/status.codes';
import sendError from '../../helpers/error.sender';
import errorMessages from '../../helpers/constants/error.messages';
// import errorMessages from '../../helpers/constants/error.messages';

const { Article } = models;

/**
* containing all controllers of the Articles tags
*
* @export
* @class articles
*/
export default class articleTags {
/**
* A controller to add a tag to an article
*
* @param {Object} req - the request object
* @param {Object} res - the result object
* @returns {Object} res
*/
static async createArticleTag(req, res) {
// Initialising variables
const result = {};
const { slug } = req.params;
const { tag } = req.body;
const { tagList } = req.Existing;

if (tagList.includes(tag)) {
return sendError(status.RESET_CONTENT, res, 'tagList', errorMessages.existingTag);
}
// Updating the tags
tagList.push(tag);

// Updating the tags
await Article.update({
tagList
},
{
where: {
slug
}
});

// sending the result back
result.status = status.OK;
result.message = 'Tag added successfully';
res.status(status.OK).json(result);
}
}
51 changes: 51 additions & 0 deletions src/api/migrations/20190622162643-create-article.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
export default {
up: (queryInterface, Sequelize) => queryInterface.createTable('Articles', {
id: {
allowNull: false,
unique: true,
primaryKey: true,
type: Sequelize.UUID,
defaultValue: Sequelize.UUIDV4
},
title: {
type: Sequelize.STRING,
allowNull: false
},
slug: {
type: Sequelize.STRING,
allowNull: false,
unique: true
},
description: {
type: Sequelize.STRING,
allowNull: false
},
body: {
type: Sequelize.TEXT,
allowNull: false
},
tagList: {
type: Sequelize.ARRAY(Sequelize.TEXT),
allowNull: false
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
},
userId: {
type: Sequelize.INTEGER,
references: {
model: 'Users',
key: 'id'
},
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
allowNull: false
}
}),
down: (queryInterface, Sequelize) => queryInterface.dropTable('Articles')
};
43 changes: 43 additions & 0 deletions src/api/migrations/20190622175828-create-rating.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
export default {
up: (queryInterface, Sequelize) => queryInterface
.createTable('Ratings', {
userId: {
type: Sequelize.INTEGER,
references: {
model: 'Users',
key: 'id'
},
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
allowNull: false,
unique: false
},
articleSlug: {
type: Sequelize.STRING,
references: {
model: 'Articles',
key: 'slug'
},
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
allowNull: false,
unique: false
},
rating: {
type: Sequelize.INTEGER
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
})
.then(() => queryInterface.addConstraint('Ratings', ['userId', 'articleSlug'], {
type: 'primary key',
name: 'userRating'
})),
down: (queryInterface, Sequelize) => queryInterface.dropTable('Ratings')
};
52 changes: 52 additions & 0 deletions src/api/models/article.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const Article = (sequelize, DataTypes) => {
const article = sequelize.define('Article',
{
id: {
allowNull: false,
unique: true,
primaryKey: true,
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4
},
title: {
type: DataTypes.STRING,
allowNull: false
},
description: {
type: DataTypes.STRING,
allowNull: false
},
slug: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
body: {
type: DataTypes.TEXT,
allowNull: false
},
tagList: {
type: DataTypes.ARRAY(DataTypes.TEXT),
allowNull: false
},
userId: {
type: DataTypes.INTEGER,
references: {
model: 'Users',
key: 'id'
},
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
allowNull: false
}
},
{});

Article.associate = (models) => {
Article.belongsTo(models.User, { foreignKey: 'userId' });
Article.hasOne(models.Rating, { foreignKey: 'articleSlug' });
};
return article;
};

export default Article;
1 change: 1 addition & 0 deletions src/api/models/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const sequelize = new Sequelize(env.dbUrl, {

const models = {
User: sequelize.import('./user'),
Article: sequelize.import('./article')
};

export { sequelize };
Expand Down
38 changes: 38 additions & 0 deletions src/api/models/rating.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
export default (sequelize, DataTypes) => {
const Rating = sequelize.define('Ratings',
{
userId: {
type: DataTypes.INTEGER,
references: {
model: 'Users',
key: 'id'
},
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
allowNull: false
},
articleSlug: {
type: DataTypes.STRING,
references: {
model: 'Articles',
key: 'slug'
},
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
allowNull: false
},
rating: {
type: DataTypes.INTEGER
}
},
{
freezeTableName: true
});

Rating.removeAttribute('id');
Rating.associate = (models) => {
Rating.belongsTo(models.User, { foreignKey: 'userId' });
Rating.belongsTo(models.Article, { foreignKey: 'articleSlug' });
};
return Rating;
};
19 changes: 19 additions & 0 deletions src/api/routes/articleRouter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import express from 'express';
import articleTagController from '../controllers/articleTagController';
import authorization from '../../middlewares/authorization';
import validdateInputs from '../../middlewares/validations/body.inputs';
import checkArticle from '../../middlewares/getOneArticle';
import ownershipValidator from '../../middlewares/checkArticleOwnership';
import verifyBody from '../../middlewares/validations/body.verifier';

const router = express();

router.patch('/:slug/tags',
authorization,
verifyBody,
validdateInputs(true, 'addArticleTag', ['tag']),
checkArticle.getArticle,
ownershipValidator.checkOwner,
articleTagController.createArticleTag);

export default router;
4 changes: 4 additions & 0 deletions src/api/routes/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import express from 'express';
import authRouter from './authRouter';
import resetRouter from './password.reset';
import articleRouter from './articleRouter';
import testsRouter from '../../helpers/factory/routes/body.inputs.test';

const router = express();

router.use('/users', authRouter);
router.use('/password-reset', resetRouter);
router.use('/articles', articleRouter);
router.use('/tests', testsRouter);

export default router;
Loading

0 comments on commit 6edf9ca

Please sign in to comment.