Skip to content

Commit

Permalink
Merge 5737cd3 into 0723eb2
Browse files Browse the repository at this point in the history
  • Loading branch information
deschantkn committed Aug 14, 2019
2 parents 0723eb2 + 5737cd3 commit ab91608
Show file tree
Hide file tree
Showing 15 changed files with 181 additions and 33 deletions.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"dev": "nodemon --exec babel-node src/index.js",
"build": "babel src --out-dir dist",
"start": "node dist/index.js",
"test": "nyc --reporter=html --reporter=text mocha ./test/*.js --exit --require @babel/register --require regenerator-runtime",
"test": "nyc --reporter=html --reporter=text mocha ./test/*.js --exit --no-timeout --require @babel/register --require regenerator-runtime",
"devtest": "NODE_ENV=test & yarn destroy & yarn run seed & yarn run test",
"test:reset": "npm run migrate:reset && nyc --reporter=html --reporter=text mocha ./test/*.js --timeout 80000 --exit --require @babel/register --require regenerator-runtime",
"coverage": "nyc report --reporter=text-lcov | coveralls",
Expand All @@ -22,7 +22,7 @@
"license": "MIT",
"dependencies": {
"@hapi/joi": "^15.0.3",
"async": "^2.6.3",
"async": "^3.1.0",
"bcrypt": "^3.0.6",
"body-parser": "^1.19.0",
"cloudinary": "^1.14.0",
Expand Down Expand Up @@ -90,4 +90,4 @@
"src/helpers/SocketIO.js"
]
}
}
}
21 changes: 15 additions & 6 deletions src/api/controllers/profiles.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export default class ProfilesController {
try {
const updatedUser = await User.update(
updatedProfile,
{ where: { id: params.id } },
{ where: { id: params.id }, returning: true },
);

if (!updatedUser[0]) {
Expand All @@ -65,7 +65,7 @@ export default class ProfilesController {

uploadImageWorker(files, params.id, 'user', null);

return res.status(200).json({ user: { updatedUser } });
return res.status(200).json({ user: updatedUser[1][0] });
} catch (error) {
return res.status(500).json({ error: `${error}` });
}
Expand Down Expand Up @@ -93,7 +93,7 @@ export default class ProfilesController {
* @return {object} returns an object containing the user's profiles
*/
static async getAllProfile(req, res) {
const fetchedProfile = await User.findAll({ attributes: ['username', 'firstName', 'lastName', 'bio', 'image'] });
const fetchedProfile = await User.findAll({ attributes: ['username', 'firstName', 'lastName', 'bio', 'avatar', 'cover'] });
if (!fetchedProfile[0]) return res.status(200).send({ message: 'No Users Profiles found!', data: fetchedProfile });
return res.status(200).send({
profiles: fetchedProfile
Expand Down Expand Up @@ -172,15 +172,15 @@ export default class ProfilesController {
*/
static async followers(req, res) {
// eslint-disable-next-line no-unused-vars
const f = await follows.findAll();
// const f = await follows.findAll();
follows
.findAll({
where: { userId: req.user.id },
include: [
{
model: User,
as: 'follower',
attributes: ['id', 'firstName', 'lastName', 'email', 'username']
attributes: ['id', 'firstName', 'lastName', 'email', 'username', 'avatar', 'bio']
}
]
})
Expand All @@ -206,7 +206,7 @@ export default class ProfilesController {
{
model: User,
as: 'followedUser',
attributes: ['id', 'firstName', 'lastName', 'email', 'username']
attributes: ['id', 'firstName', 'lastName', 'email', 'username', 'avatar', 'bio']
}
]
})
Expand All @@ -217,4 +217,13 @@ export default class ProfilesController {
return res.status(200).json({ following: data });
});
}

/**
* @param {Object} req - Request
* @param {Object} res - Response
* @returns {Object} user
*/
static async getCurrentUser(req, res) {
return res.status(200).json({ user: req.user });
}
}
24 changes: 24 additions & 0 deletions src/api/controllers/uploadController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { v2 as cloudinary } from 'cloudinary';

/**
* @Author - Deschant Kounou
*/
class uploadController {
/**
* Upload a single image
* @param {Object} req - Request
* @param {Object} res - Response
* @returns {Object} uploaded image url
*/
static async uploadImage(req, res) {
const { file } = req;
try {
const image = await cloudinary.uploader.upload(file.path);
return res.status(200).json({ status: 200, url: image.secure_url });
} catch (error) {
return res.status(500).json({ error });
}
}
}

export default uploadController;
2 changes: 2 additions & 0 deletions src/api/routes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import ratingsRouter from './ratingsRouter';
import bookmarkRouter from './bookmark';
import termsAndConditionsRouter from './termsConditionsRouter';
import chatRouter from './chatRouter';
import uploadRouter from './uploadRouter';

const api = express();

Expand All @@ -19,5 +20,6 @@ api.use('/ratings', ratingsRouter);
api.use('/bookmarks', bookmarkRouter);
api.use('/termsandconditions', termsAndConditionsRouter);
api.use('/chats', chatRouter);
api.use('/upload', uploadRouter);

export default api;
13 changes: 13 additions & 0 deletions src/api/routes/uploadRouter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Router } from 'express';

import UploadController from '../controllers/uploadController';
import Auth from '../../middleware/auth';
import upload from '../../handlers/multer';

const uploadRouter = Router();
const { uploadImage } = UploadController;
const { verifyToken } = Auth;

uploadRouter.post('/image', verifyToken, upload.single('image'), uploadImage);

export default uploadRouter;
3 changes: 2 additions & 1 deletion src/api/routes/userRouter.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ import upload from '../../handlers/multer';
import OptController from '../controllers/optController';

const userRouter = Router();
const { updateProfile, deleteProfile } = ProfilesController;
const { updateProfile, deleteProfile, getCurrentUser } = ProfilesController;
const {
optOutEmail, optOutApp, OptInApp, OptInEmail
} = OptController;
const { verifyToken, checkOwnership, checkIsAdmin } = Auth;

userRouter.get('/', verifyToken, getCurrentUser);
userRouter.post('/optinemail', verifyToken, OptInEmail);
userRouter.post('/optinapp', verifyToken, OptInApp);
userRouter.delete('/optinemail', verifyToken, optOutEmail);
Expand Down
1 change: 1 addition & 0 deletions src/helpers/articlesHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class ArticlesHelper {
authorId: id,
readtime,
views: 0,
blocked: false
});

// Uplooad article image
Expand Down
4 changes: 2 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ app.use((req, res) => {
});

sequelize.sync().then(() => {
cron.schedule('*/59 * * * *', () => {
cron.schedule('*/1 * * * *', () => {
purgeWorker();
});
cron.schedule('*/5 * * * *', () => {
cron.schedule('*/1 * * * *', () => {
sendMailWorker();
});
app.listen(port, () => {
Expand Down
41 changes: 34 additions & 7 deletions src/middleware/search.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
/* eslint-disable no-prototype-builtins */
import sequelize from 'sequelize';
import { forEach } from 'async';
import models from '../sequelize/models';

const { Op } = sequelize;
const { User, Article } = models;
const { User, Article, LikeDislike } = models;
/**
* @description search by different parameters
*/
Expand Down Expand Up @@ -47,7 +48,12 @@ class search {
{
as: 'author',
model: User,
attributes: ['username', 'bio', 'image']
attributes: ['username', 'bio', 'cover', 'avatar']
},
{
as: 'metrics',
model: LikeDislike,
attributes: ['likes', 'dislikes']
}
],
attributes: [
Expand All @@ -56,23 +62,43 @@ class search {
'description',
'readtime',
'body',
'gallery',
'tagList',
'updatedAt',
'createdAt'
]
});

if (!response[0]) {
return res.status(404).send({
error: `Author : ${author} - doesn't have any article, so far!`
return res.status(200).send({
message: `Author : ${author} - doesn't have any article, so far!`,
data: []
});
}

// @returning the response
return res.status(200).send({
forEach(response, async (article, callback) => {
const query = await Article.findAll({ where: { slug: article.slug } });

const { dataValues: foundArticle } = query[0];

const likeCount = await LikeDislike.count({
where: { articleId: foundArticle.id, likes: 1 }
});

const dislikeCount = await LikeDislike.count({
where: {
articleId: foundArticle.id,
dislikes: 1
}
});

article.dataValues.likes = likeCount;
article.dataValues.dislikes = dislikeCount;
callback();
}, () => res.status(200).send({
message: `Here's All article written by Author who is like ${author}`,
data: response
});
}));
}

if (title && !author && !tag && !keywords) {
Expand All @@ -96,6 +122,7 @@ class search {
'body',
'readtime',
'tagList',
'gallery',
'updatedAt',
'createdAt'
]
Expand Down
6 changes: 6 additions & 0 deletions src/sequelize/models/article.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ module.exports = (sequelize, DataTypes) => {
onDelete: 'CASCADE',
onUpdate: 'CASCADE'
});
Article.hasMany(models.LikeDislike, {
as: 'metrics',
foreignKey: 'articleId',
onDelete: 'CASCADE',
onUpdate: 'CASCADE'
});
};
return Article;
};
9 changes: 9 additions & 0 deletions src/sequelize/models/likedislike.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,14 @@ export default (sequelize, DataTypes) => {
},
{}
);

LikeDislike.associate = (models) => {
LikeDislike.belongsTo(models.Article, {
foreignKey: 'articleId',
targetKey: 'id',
onUpdate: 'CASCADE',
onDelete: 'CASCADE'
});
};
return LikeDislike;
};
16 changes: 13 additions & 3 deletions src/workers/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
const workerFarm = require('worker-farm');

const workers = {};
import purgeDeadTokens from './purgeDeadTokens';
import queueEmail from './queueEmail';
import sendMail from './sendMail';
import uploadImage from './uploadImage';

/*
const workerFarm = require('worker-farm');
workers.purgeWorker = workerFarm(require.resolve('./purgeDeadTokens'));
workers.queueEmailWorker = workerFarm(require.resolve('./queueEmail'));
workers.sendMailWorker = workerFarm(require.resolve('./sendMail'));
workers.uploadImageWorker = workerFarm(require.resolve('./uploadImage'));
*/

const workers = {};
workers.purgeWorker = purgeDeadTokens;
workers.queueEmailWorker = queueEmail;
workers.sendMailWorker = sendMail;
workers.uploadImageWorker = uploadImage;

export default workers;
7 changes: 7 additions & 0 deletions test/mock/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,12 @@ export default {
email: 'shia@gmail.com',
username: 'shiaroberts',
password: 'Shi@R0berts',
},
user3: {
firstName: 'Saitama',
lastName: 'Sensei',
email: 'onepunch@testmail.com',
username: 'onepunch',
password: 'genos@SclassHer0',
}
};
46 changes: 46 additions & 0 deletions test/upload.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import chaiHttp from 'chai-http';
import chai from 'chai';
import dotenv from 'dotenv';
import fs from 'fs';

import app from '../src/index';
import tokenHelper from '../src/helpers/Token.helper';
import models from '../src/sequelize/models';
import mockUsers from './mock/users';

dotenv.config();
chai.use(chaiHttp);

let testUser, userToken;

describe('Image Upload', () => {
before(async () => {
testUser = await models.User.create(mockUsers.user3);
userToken = await tokenHelper.generateToken({ id: testUser.dataValues.id });
});

it('should upload and image', (done) => {
chai
.request(app)
.post('/api/upload/image')
.set('token', userToken)
.attach('image', fs.readFileSync(`${__dirname}/mock/sample.png`), 'sample.png')
.end((err, res) => {
res.should.have.status(200);
res.body.should.be.a('object');
done();
});
}).timeout(10000);

it('should not upload and image with invalid path', (done) => {
chai
.request(app)
.post('/api/upload/image')
.set('token', userToken)
.attach('imsage', fs.readFileSync(`${__dirname}/mock/sample.png`), 'sample.png')
.end((err, res) => {
res.should.have.status(500);
done();
});
}).timeout(10000);
});
Loading

0 comments on commit ab91608

Please sign in to comment.