Skip to content

Commit

Permalink
Merge 04b8d06 into 0723eb2
Browse files Browse the repository at this point in the history
  • Loading branch information
deschantkn committed Aug 12, 2019
2 parents 0723eb2 + 04b8d06 commit 65ffa3f
Show file tree
Hide file tree
Showing 12 changed files with 161 additions and 25 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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
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
38 changes: 32 additions & 6 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,6 +62,7 @@ class search {
'description',
'readtime',
'body',
'gallery',
'tagList',
'updatedAt',
'createdAt'
Expand All @@ -64,15 +71,33 @@ class search {

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

// @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 +121,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;
};
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);
});
15 changes: 4 additions & 11 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -954,12 +954,10 @@ async@^1.5.0:
resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=

async@^2.6.3:
version "2.6.3"
resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff"
integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==
dependencies:
lodash "^4.17.14"
async@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/async/-/async-3.1.0.tgz#42b3b12ae1b74927b5217d8c0016baaf62463772"
integrity sha512-4vx/aaY6j/j3Lw3fbCHNWP0pPaTCew3F6F3hYyl/tHs/ndmV1q7NW9T5yuJ2XAGwdQrP+6Wu20x06U4APo/iQQ==

asynckit@^0.4.0:
version "0.4.0"
Expand Down Expand Up @@ -3393,11 +3391,6 @@ lodash@^4.17.11:
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==

lodash@^4.17.14:
version "4.17.14"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.14.tgz#9ce487ae66c96254fe20b599f21b6816028078ba"
integrity sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==

log-driver@^1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/log-driver/-/log-driver-1.2.7.tgz#63b95021f0702fedfa2c9bb0a24e7797d71871d8"
Expand Down

0 comments on commit 65ffa3f

Please sign in to comment.