Skip to content

Commit

Permalink
Merge c712b89 into c7005e9
Browse files Browse the repository at this point in the history
  • Loading branch information
pngabo committed Jul 22, 2019
2 parents c7005e9 + c712b89 commit 228c285
Show file tree
Hide file tree
Showing 9 changed files with 620 additions and 360 deletions.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,12 @@
"sequelize-cli": "^5.5.0",
"social-share": "^0.1.0",
"socket.io": "^2.2.0",
"swagger-ui-express": "^4.0.6"
"swagger-ui-express": "^4.0.6",
"chai": "^4.2.0",
"chai-http": "^4.3.0"
},
"devDependencies": {
"@babel/plugin-transform-runtime": "^7.4.4",
"chai": "^4.2.0",
"chai-http": "^4.3.0",
"eslint": "^6.0.1",
"eslint-config-airbnb-base": "^13.2.0",
"eslint-plugin-import": "^2.17.3",
Expand Down
52 changes: 52 additions & 0 deletions src/controllers/ReadStatsController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import models from '../models';

const { ReadingStats } = models;
/**
* @class { ReadingStatsController }
* @description { Handles Reading stats GET Requests }
*/
export default class ReadingStatsController {
/**
* Save reading stats
* @param {object} req
* @param {object} res
* @returns {object} stats object
*/
static async create(req, res) {
try {
const userId = req.user.id;
const { articleId } = req.params;
const [result, created] = await ReadingStats.findOrCreate({ where:
{ userId, articleId }, });
if (!created) {
await ReadingStats.update({ numberOfReading:
result.numberOfReading + 1 },
{ where: { id: result.id }, returning: true });
}
res.status(201).send({ message: 'Reading...',
articleId: result.articleId,
userId: result.userId });
} catch (error) {
return res.status(500).json(error.message);
}
}

/**
* Get reading stats
* @param {Object} req express request
* @param {Object} res express response
* @returns {Array} user reading statistics
*/
static async getAll(req, res) {
try {
const totalReadingStats = await ReadingStats.count({ where:
{ articleId: req.params.articleId } });
return totalReadingStats
? res.status(200).json({ message: 'Reading Stats:',
totalReadings: totalReadingStats })
: res.status(404).json({ message: ' stats not found' });
} catch (error) {
return res.status(500).json(error.message);
}
}
}
24 changes: 24 additions & 0 deletions src/migrations/20190721115501-create-reading-stat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@


module.exports = { up: (queryInterface, Sequelize) => queryInterface.createTable('ReadingStats', { id: { allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER },
articleId: { type: Sequelize.INTEGER,
onDelete: 'CASCADE',
references: { model: 'Articles',
key: 'id', },
allowNull: false },
userId: { type: Sequelize.INTEGER,
allowNull: true,
references: { model: 'User',
key: 'id' },
onUpdate: 'CASCADE',
onDelete: 'CASCADE' },
numberOfReading: { allowNull: true,
type: Sequelize.INTEGER },
createdAt: { allowNull: false,
type: Sequelize.DATE },
updatedAt: { allowNull: false,
type: Sequelize.DATE } }),
down: queryInterface => queryInterface.dropTable('ReadingStats') };
24 changes: 24 additions & 0 deletions src/models/readingStat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module.exports = (sequelize, DataTypes) => {
const ReadingStats = sequelize.define('ReadingStats', { articleId: { type: DataTypes.STRING,
allowNull: false },
userId: { type: DataTypes.INTEGER,
allowNull: false,
references: { model: 'User',
key: 'id' },
onUpdate: 'CASCADE',
onDelete: 'CASCADE' },
numberOfReading: { type: DataTypes.INTEGER } }, {});
ReadingStats.associate = (models) => {
// associations can be defined here
ReadingStats.belongsTo(models.Articles, { foreignKey: 'articleId',
targetKey: 'id',
onDelete: 'CASCADE',
onupdate: 'CASCADE' });
ReadingStats.belongsTo(models.User, { foreignKey: 'userId',
// as: 'user',
targetKey: 'id',
onDelete: 'CASCADE',
onupdate: 'CASCADE' });
};
return ReadingStats;
};
2 changes: 2 additions & 0 deletions src/routes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import likeAndDislike from './likesAndDislikes';
import socialAPIRoute from './socialAPIRoute';
import optinAndOptOut from './optinAndOptOut';
import bookmarkRoute from './bookmarksRoutes';
import readerStatsRoute from './readerStatsRoute';

const { verifyToken } = Auth;

Expand All @@ -31,6 +32,7 @@ router.use('/api/social', socialRoute);
router.use('/api/articles', commentRoute);
router.use('/api/users', followerRoute);
router.use('/api', socialAPIRoute);
router.use('/api', readerStatsRoute);
// route for optin/Optout
router.use('/', optinAndOptOut);

Expand Down
10 changes: 10 additions & 0 deletions src/routes/readerStatsRoute.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import express from 'express';
import Auth from '../middlewares/Auth';
import ReaderStatsController from '../controllers/ReadStatsController';

const { verifyToken } = Auth;
const router = express.Router();
router.get('/readerstats/:articleId', verifyToken, ReaderStatsController.getAll);
router.post('/:articleId/readerstats', verifyToken, ReaderStatsController.create);

export default router;
78 changes: 78 additions & 0 deletions src/test/readStats.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import chai from 'chai';
import chaiHttp from 'chai-http';
import app from '../index';

chai.use(chaiHttp);
chai.should();

let tokenGen;
describe('READING STATS TEST', () => {
it('A new user who filled all required data should be registered', (done) => {
const user = { username: 'Kagabof',
email: 'kagabo1@gmail.com',
password: 'Kagabo1@', };
chai.request(app)
.post('/api/users')
.send(user)
.end((req, res) => {
// eslint-disable-next-line prefer-destructuring
res.should.have.status(201);
res.body.should.have.property('message');
res.body.should.have.property('token');
done();
});
});

it('User should be able to sign in', (done) => {
const user2 = { username: 'Kagabo1',
email: 'kagabo1@gmail.com',
password: 'Kagabo1@', };
chai.request(app)
.post('/api/users/login')
.send(user2)
.end((req, res) => {
res.should.have.status(200);
res.body.data.should.be.an('object');
res.body.data.should.have.property('email');
res.body.data.should.have.property('token');
tokenGen = res.body.data.token;
done();
});
});
it('Autenticated user should be able to create reading stats', (done) => {
const articleId = 3;
chai
.request(app)
.post(`/api/${articleId}/readerstats`)
.set('token', tokenGen)
.end((err, res) => {
res.should.have.status(201);
res.body.should.be.an('object');
done();
});
});
it('Autenticated user should be able get reading stats', (done) => {
const articleId = 3;
chai
.request(app)
.get(`/api/readerstats/${articleId}`)
.set('token', tokenGen)
.end((err, res) => {
res.should.have.status(200);
res.body.should.be.an('object');
done();
});
});
it('Fail to get reading stats when not found', (done) => {
const articleId = 4;
chai
.request(app)
.get(`/api/readerstats/${articleId}`)
.set('token', tokenGen)
.end((err, res) => {
res.should.have.status(404);
res.body.should.be.an('object');
done();
});
});
});
4 changes: 2 additions & 2 deletions src/test/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ describe('users', () => {
});

it('Invalid email', (done) => {
const user3 = { email: 'kagabo1@gmail.com',
const user3 = { email: 'kagabo11@gmail.com',
password: 'Kagabo1@' };
chai.request(app)
.post('/api/users/login')
Expand Down Expand Up @@ -354,7 +354,7 @@ describe('User Profile view amend', () => {
chai.request(app)
.patch(`/api/users/${userGen}`)
.set('token', tokenGen)
.send({ id: 15,
.send({ id: 16,
username: 'shaluchandwani',
firstName: 'Shalu',
lastName: 'chandwani',
Expand Down
Loading

0 comments on commit 228c285

Please sign in to comment.