Skip to content

Commit

Permalink
Merge branch 'develop' into chore/164798013-auth-documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
Rotimi Babalola committed Apr 5, 2019
2 parents ce84588 + 8335a44 commit 1e3afd6
Show file tree
Hide file tree
Showing 30 changed files with 974 additions and 253 deletions.
6 changes: 5 additions & 1 deletion example.env
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@ DB_DATABASE_DEV=
DB_DATABASE_TEST=
HOST=
SECRET=<string>

SENDGRID_API_KEY=
PUSHER_API_ID=
PUSHER_KEY=
PUSHER_SECRET=
PUSHER_CLUSTER=
406 changes: 203 additions & 203 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
"migrate:undo": "sequelize db:migrate:undo:all",
"seed": "sequelize db:seed:all",
"db:reset": "npm run migrate:undo && npm run migrate && npm run seed",
"start:dev": "npm run migrate && nodemon server/app.js --exec babel-node",
"test": "export NODE_ENV=test && nyc --reporter=html --reporter=text mocha tests/**/*.test.js --timeout 20000 --require @babel/register --exit",
"start:dev": "nodemon server/app.js --exec babel-node",
"eslint:check": "node_modules/eslint/bin/eslint.js \"server/**/*.js\"",
"prettier:check": "prettier --check \"./server/**/*.js\" && prettier --check \"./tests/**/*.js\"",
"prettier:fix": "prettier --write \"./server/**/*.js\" && prettier --write \"./tests/**/*.js\"",
Expand Down
2 changes: 1 addition & 1 deletion server/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ app.use(express.json());

app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));
const port = process.env.PORT || 6000;

app.use('/api/v1/auth', routes);
app.get('/', (req, res) => {
res.send('Welcome to Authors Haven');
});
Expand Down
54 changes: 53 additions & 1 deletion server/controllers/auth.controller.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import db from '../models';
import authHelper from '../helpers/auth';
import searchDatabase from '../helpers/searchDatabase';
import emailSender from '../helpers/emailSender';

const { findUser } = searchDatabase;
const { User } = db;
const error = ['invalid username and/or password'];
const serverError = {
Expand Down Expand Up @@ -64,6 +67,14 @@ const loginController = async (req, res) => {
}
};

/**
* @description - this method create in a user
*
* @param {object} req - The request payload sent to the router
* @param {object} res - The response payload sent back from the controller
*
* @returns {object} - object
*/
const signupController = async (req, res) => {
try {
const { firstname, lastname, email, password } = req.body;
Expand All @@ -79,6 +90,13 @@ const signupController = async (req, res) => {
const { id, is_admin: isAdmin, bio, image_url: image } = user;
const token = authHelper.encode({ id, email, isAdmin });

const verificationToken = authHelper.encode({ email });
const verificationLink = `${req.protocol}://${req.get(
'host'
)}/api/v1/auth/verification/${verificationToken}`;

await emailSender.signupEmail(email, verificationLink);

return res.send({
status: 200,
user: { email, token, bio, image },
Expand All @@ -89,6 +107,40 @@ const signupController = async (req, res) => {
}
};

const authController = { loginController, signupController };
/**
* @description - this method logs in a user
*
* @param {object} req - The request payload sent to the router
* @param {object} res - The response payload sent back from the controller
*
* @returns {object} - object
*/
const verifyEmail = async (req, res) => {
try {
const { token } = req.params;
const decodedToken = authHelper.decode(token);
const { email } = decodedToken.userObj;

const user = await findUser(email);
if (user.is_activated) {
return res.send({
status: 403,
errors: {
body: ['Your account has already been verified'],
},
});
}
const updateValue = { is_activated: true };
await user.update(updateValue);
return res.send({
status: 200,
message: 'Account verification was successful',
});
} catch (err) {
return res.send(serverError);
}
};

const authController = { loginController, signupController, verifyEmail };

export default authController;
3 changes: 2 additions & 1 deletion server/controllers/comment.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const { databaseError, findArticle } = search;

const comments = {
post: async (req, res) => {
const userId = req.user.userObj.id;
/**
* @description post comment on article
* @param {*} req
Expand All @@ -24,7 +25,7 @@ const comments = {
});
}
const comment = await Comment.create({
user_id: req.body.user_id,
user_id: userId,
article_id: req.body.article_id,
body: req.body.body,
});
Expand Down
2 changes: 2 additions & 0 deletions server/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import profileController from './profile.controllers';
import articleController from './article.controllers';
import authController from './auth.controller';
import ratingController from './rating.controller';
import ResetPasswordController from './resetpassword';
import commentController from './comment.controller';

export default {
Expand All @@ -11,5 +12,6 @@ export default {
authController,
likeController,
ratingController,
ResetPasswordController,
commentController,
};
4 changes: 2 additions & 2 deletions server/controllers/rating.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import model from '../models';

const { Rating } = model;
const { databaseError, findArticle } = search;

const rating = {
post: async (req, res) => {
const userId = req.user.userObj.id;
/**
* @description post article Rating
* @param {*} req
Expand All @@ -24,7 +24,7 @@ const rating = {
});
}
const ratingDetails = await Rating.create({
user_id: req.body.user_id,
user_id: userId,
article_id: req.body.article_id,
rating_value: req.body.rating_value,
});
Expand Down
44 changes: 44 additions & 0 deletions server/controllers/resetpassword.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import notification from '../helpers/notifications';
import Authenticate from '../helpers/auth';
import model from '../models';

const { User } = model;

const { hashPassword } = Authenticate;

const ResetPasswordController = {
async updatePassword(req, res) {
try {
const { email } = req.user;
const hashedPassword = hashPassword(req.body.password);
const newPassword = await User.update(
{ password: hashedPassword },
{
where: { email },
returning: true,
}
);

if (newPassword.length) {
res.status(200).json({
status: 200,
message: 'password reset successful',
});
notification.passwordReset(email);
}
} catch (error) {
return res.status(500).json({
message: error.message,
});
}
},

acceptRequest(req, res) {
res
.status(200)
.redirect(
`${req.protocol}://${req.get('host')}/api/v1/auth/reset/message`
);
},
};
export default ResetPasswordController;
6 changes: 6 additions & 0 deletions server/helpers/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ const Authenticate = {
return token;
},

encodeEmail(email) {
const secret = process.env.SECRET;
const token = jwt.sign({ email }, secret, { expiresIn: '72h' });
return token;
},

/**
* @description - this method decodes a token
*
Expand Down
11 changes: 11 additions & 0 deletions server/helpers/emailSender.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import sendEmail from '../config/email';

const signupEmail = (email, link) => {
const titile = 'Welcome to Authors Haven';
const body = `<p>click <a href=${link}>here</a> to confirm your email</p>`;
sendEmail(email, titile, body);
};

const emailSender = { signupEmail };

export default emailSender;
22 changes: 22 additions & 0 deletions server/helpers/notifications.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import sendEmail from '../config/email';
import template from './template';

const Notification = {
forgetPassword(email, link) {
const subject = 'Password Reset';
const message = template(
`<p>You requested for a password reset</p> <p>follow this link to reset your password <a href=${link}>Reset my password</a></p><br><b>Please note that this link expires in 12hours and you can only use it once</b><p>If you didn't request for a password reset, ignore this email and nothing will happen</p>`
);

sendEmail(email, subject, message);
},

passwordReset(email) {
const subject = 'Password was changed';
const message = template('<p>Your password was changed successfuly</p>');

sendEmail(email, subject, message);
},
};

export default Notification;
26 changes: 26 additions & 0 deletions server/helpers/tagsHelpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import models from '../models';

const { Keyword } = models;
const serverError = 'Server error, please try again later';

const tagging = {
/**
*
* @param {*} articleId
* @param {*} tags
* @returns {*} userId, articleId and keywords in an array.
*/
async saveArticleTags(articleId, tags) {
try {
const Articletags = await Keyword.create({
article_id: articleId,
keyword: tags,
});
return Articletags;
} catch (err) {
return serverError;
}
},
};

export default tagging;
43 changes: 43 additions & 0 deletions server/helpers/template.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
const template = (
title,
body
) => `<div style="font-family:-apple-system, '.SFNSText-Regular', 'Helvetica Neue', Roboto, 'Segoe UI', sans-serif; color: #666666; background:white; text-decoration: none; margin-bottom: 50px">
<table width="100%" cellpadding="0" cellspacing="0" border="0" summary="">
<tr align="center">
<td valign="top" style="width: 100%;">
<tabl cellspacing="0" cellpadding="0" border="0" summary="">
<tr align="center">
<td valign="middle" style="width: 100%;">
<a href="#">
<img style="width: 125px; cursor: pointer" src="https://res.cloudinary.com/dnch08bzc/image/upload/v1554130472/logo_transparent.png" alt="Authors Haven">
</a>
</td>
</tr>
</table>
</td>
</tr>
<tr align="center">
<td valign="top" style="width: 80%;">
<table style="padding: 0px; border: 0; max-width: 520px; text-align: center;" width="100%" cellpadding="0" cellspacing="0" border="0" summary="">
<tr align="center" style="margin: 0px 10px;">
<td style="width: 100%; line-height: 24px; font-size: 11pt;">
<p>${title}</p>
<p>${body}</p>
</td>
</tr>
</table>
<table style="border-collapse:collapse; max-width: 520px; text-align: center; margin-top: 30px" cellpadding="0" cellspacing="0" border="0" summary="">
<tr align="center">
<td style="width: 100%;">
<p style="line-height: 20px; font-size: 0.75rem; color: #b3b3b3;">Sent by
<a href="#" style="color: #4a08ef;text-decoration: none;">Author's Haven</a>
</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
</div>`;

export default template;
Loading

0 comments on commit 1e3afd6

Please sign in to comment.