Skip to content

Commit

Permalink
Merge 9ef982c into 20b185e
Browse files Browse the repository at this point in the history
  • Loading branch information
omoefe-dukuye committed Feb 19, 2019
2 parents 20b185e + 9ef982c commit e78f2ed
Show file tree
Hide file tree
Showing 25 changed files with 646 additions and 288 deletions.
393 changes: 206 additions & 187 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
"build": "rm -rf dist/ && babel server/ -d dist/server/ && babel index.js -d dist/",
"start": "export NODE_ENV=production&& node dist",
"heroku-postbuild": "npm run migration && npm run seed && npm run build",
"test": "export NODE_ENV=test && npm run migration && nyc mocha --require @babel/register tests/**/*.spec.js --timeout 5000 --exit",
"test": "export NODE_ENV=test&& npm run migration && nyc mocha --require @babel/register tests/**/*.spec.js --timeout 5000 --exit",
"lint": "eslint",
"start:dev": "NODE_ENV=development && nodemon --exec babel-node index.js",
"start:dev": "export NODE_ENV=development&& nodemon --exec babel-node index.js",
"coverage": "nyc report --reporter=text-lcov | coveralls",
"migrate": "./node_modules/.bin/babel-node ./node_modules/.bin/sequelize db:migrate",
"undo:migration": "./node_modules/.bin/babel-node ./node_modules/.bin/sequelize db:migrate:undo:all",
Expand Down Expand Up @@ -60,6 +60,7 @@
"@babel/cli": "^7.2.3",
"@babel/core": "^7.2.2",
"@babel/node": "^7.2.2",
"@babel/polyfill": "^7.2.5",
"@babel/preset-env": "^7.3.1",
"babel-eslint": "^10.0.1",
"chai": "^4.2.0",
Expand Down
7 changes: 6 additions & 1 deletion server/api/controllers/article.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Sequelize from 'sequelize';
import { createLogger, format, transports } from 'winston';
import notifyFollowers from '../helpers/notification/followers';
import {
User, Article, LikeDislike, Tag, Rating
} from '../../models';
Expand Down Expand Up @@ -120,6 +121,10 @@ export const createArticle = async (req, res) => {
newArticle = newArticle.toJSON();
newArticle.readTime = getReadTime(newArticle.body);


const { authorId, id } = newArticle;
notifyFollowers(authorId, id, title);

return res.status(201).send({
status: 'Success',
data: newArticle
Expand Down Expand Up @@ -566,7 +571,7 @@ export const deleteArticle = async (req, res) => {
message: 'Article not found'
});
}
if ((foundArticle.authorId !== userId) && (role !== 'admin')) {
if ((foundArticle.authorId !== userId) && (role !== 'admin') && (role !== 'super-admin')) {
return res.status(401).send({
status: 'fail',
message: 'Sorry not authorized'
Expand Down
4 changes: 4 additions & 0 deletions server/api/controllers/comments.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@ import {
Comment, Article, Sequelize
} from '../../models';

import informBookmarkers from '../helpers/notification/bookmarkers';

const { Op } = Sequelize;

export const postComment = async (req, res) => {
const { params: { articleId }, body: { commentBody }, user: { id: userId } } = req;
try {
const newComment = await Comment.create({ commentBody, articleId, userId });

informBookmarkers(articleId, commentBody, userId);
return res.status(201).send({ status: 'success', data: newComment });
} catch (error) {
return res.status(500).send({
Expand Down
47 changes: 21 additions & 26 deletions server/api/controllers/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -367,30 +367,6 @@ export const resetPassword = async (req, res) => {
}
};

export const upgradeToAdmin = async ({ user: { id }, body: { pass } }, res) => {
if (pass !== process.env.ADMIN_PASS) {
return res.status(403).send({
status: 'fail',
message: 'wrong pass'
});
}
try {
const [, [{ username, role: assignedRole }]] = await User.update(
{ role: 'admin' },
{ returning: true, where: { id: { [Op.eq]: id } } }
);
res.status(200).send({
status: 'success',
data: { id, username, assignedRole }
});
} catch (error) {
res.status(500).send({
status: 'error',
message: 'Internal server error occured.'
});
}
};

export const changeRole = async ({ body: { id, role: proposedRole } }, res) => {
try {
const user = await User.update(
Expand Down Expand Up @@ -455,7 +431,7 @@ export const listAuthors = async (req, res) => {
};

export const getUser = async ({ user: { role }, params: { id } }, res) => {
if (role !== 'admin') {
if (role !== 'admin' && role !== 'super-admin') {
return res.status(403).send({
status: 'fail',
message: 'You\'re not an admin'
Expand Down Expand Up @@ -494,7 +470,7 @@ export const getUser = async ({ user: { role }, params: { id } }, res) => {
};

export const deleteUser = async ({ user: { role }, params: { id } }, res) => {
if (role !== 'admin') {
if (role !== 'admin' && role !== 'super-admin') {
return res.status(403).send({
status: 'fail',
message: 'You\'re not an admin'
Expand All @@ -521,3 +497,22 @@ export const deleteUser = async ({ user: { role }, params: { id } }, res) => {
});
}
};

export const unsubscribeMail = async ({ user: { id } }, res) => {
try {
await User.update(
{ notifications: false },
{ returning: true, where: { id: { [Op.eq]: id } } }
);

res.status(200).send({
status: 'success',
message: 'Successfully unsubscribed from email list'
});
} catch (error) {
res.status(500).send({
status: 'error',
message: 'internal server error occured'
});
}
};
31 changes: 26 additions & 5 deletions server/api/helpers/mailer/mailer.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import sgMail from '@sendgrid/mail';
import env from 'dotenv';

import verifyTemplate from './templates';
import resetPassowordTemplate from './resetPasswordTemplates';
import verifyTemplate from './templates/templates';
import resetPassowordTemplate from './templates/resetPasswordTemplates';
import newArticleTemplate from './templates/newArticleTemplate';
import articleGotNewCommentTemplate from './templates/articleGotNewComment';

env.config();
sgMail.setApiKey(process.env.SENDGRID_KEY);
Expand All @@ -15,7 +17,7 @@ sgMail.setApiKey(process.env.SENDGRID_KEY);
* @param {Object} url - created User's ID
* @returns {null} null
*/
const sendVerificationMail = (username, email, url) => {
export const sendVerificationMail = (username, email, url) => {
const msg = {
to: email,
from: 'support@authors-haven.com',
Expand All @@ -25,7 +27,7 @@ const sendVerificationMail = (username, email, url) => {
return sgMail.send(msg);
};

const resetPasswordVerificationMail = (username, email, token) => {
export const resetPasswordVerificationMail = (username, email, token) => {
const msg = {
to: email,
from: 'support@authors-haven.com',
Expand All @@ -35,4 +37,23 @@ const resetPasswordVerificationMail = (username, email, token) => {
return sgMail.send(msg);
};

export { sendVerificationMail, resetPasswordVerificationMail };

export const newArticleMail = (info, email) => {
const msg = {
to: email,
from: 'support@authors-haven.com',
subject: `New article from ${info.author}`,
html: newArticleTemplate(info),
};
return sgMail.send(msg);
};

export const articleGotNewComment = (info, email) => {
const msg = {
to: email,
from: 'support@authors-haven.com',
subject: 'New comments on your bookmarked article',
html: articleGotNewCommentTemplate(info),
};
return sgMail.send(msg);
};
130 changes: 130 additions & 0 deletions server/api/helpers/mailer/templates/articleGotNewComment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
export default ({
firstname, id, title, commenter, commentBody
}) => `
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Coinbase</title>
</head>
<body leftmargin="0" marginwidth="0" topmargin="0" marginheight="0" offset="0" style="margin: 0pt auto; padding: 0px; background:#F4F7FA;">
<table id="main" width="100%" height="100%" cellpadding="0" cellspacing="0" border="0" bgcolor="#F4F7FA">
<tbody>
<tr>
<td valign="top">
<table class="innermain" cellpadding="0" width="580" cellspacing="0" border="0" bgcolor="#F4F7FA" align="center"
style="margin:0 auto; table-layout: fixed;">
<tbody>
<!-- START of MAIL Content -->
<tr>
<td colspan="4">
<!-- Logo start here -->
<table class="logo" width="100%" cellpadding="0" cellspacing="0" border="0">
<tbody>
<tr>
<td colspan="2" height="30"></td>
</tr>
<tr>
<td valign="top" align="center">
<p style="font-family: -apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif;color:#4E5C6E;line-height:20px;font-size:1.75rem;">Author's
Haven</p>
</td>
</tr>
</tbody>
</table>
<!-- Logo end here -->
<!-- Main CONTENT -->
<table width="100%" cellpadding="0" cellspacing="0" border="0" bgcolor="#ffffff" style="border-radius: 4px; box-shadow: 0 2px 8px rgba(0,0,0,0.05);">
<tbody>
<tr>
<td height="40"></td>
</tr>
<tr style="font-family: -apple-system,BlinkMacSystemFont,&#39;Segoe UI&#39;,&#39;Roboto&#39;,&#39;Oxygen&#39;,&#39;Ubuntu&#39;,&#39;Cantarell&#39;,&#39;Fira Sans&#39;,&#39;Droid Sans&#39;,&#39;Helvetica Neue&#39;,sans-serif; color:#4E5C6E; font-size:14px; line-height:20px; margin-top:20px;">
<td class="content" colspan="2" valign="top" align="center" style="padding-left:90px; padding-right:90px;">
<table width="100%" cellpadding="0" cellspacing="0" border="0" bgcolor="#ffffff">
<tbody>
<tr>
<td align="center" valign="bottom" colspan="2" cellpadding="3">
<img alt="Coinbase" width="80" src="https://www.coinbase.com/assets/app/icon_email-e8c6b940e8f3ec61dcd56b60c27daed1a6f8b169d73d9e79b8999ff54092a111.png" />
</td>
</tr>
<tr>
<td height="30" &nbsp;=""></td>
</tr>
<tr>
<td align="center"> <span style="color:#48545d;font-size:22px;line-height: 24px;">
Article Notification
</span>
</td>
</tr>
<tr>
<td height="24" &nbsp;=""></td>
</tr>
<tr>
<td height="1" bgcolor="#DAE1E9"></td>
</tr>
<tr>
<td height="24" &nbsp;=""></td>
</tr>
<tr>
<td align="center"> <span style="color:#48545d;font-size:14px;line-height:24px;">
Hi ${firstname}, There has been a new comment on your bookmarked article: "<a href=${process.env.DOMAIN}/api/articles/${id}>${title}</a>". <br>
<em>${commenter}: ${commentBody}</em>
</span>
</td>
</tr>
<tr>
<td height="20" &nbsp;=""></td>
</tr>
<tr>
<td valign="top" width="48%" align="center"> <span>
</span>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td height="60"></td>
</tr>
</tbody>
</table>
<!-- Main CONTENT end here -->
<!-- FOOTER start here -->
<table width="100%" cellpadding="0" cellspacing="0" border="0">
<tbody>
<tr>
<td height="10">&nbsp;</td>
</tr>
<tr>
<td valign="top" align="center"> <span style="font-family: -apple-system,BlinkMacSystemFont,&#39;Segoe UI&#39;,&#39;Roboto&#39;,&#39;Oxygen&#39;,&#39;Ubuntu&#39;,&#39;Cantarell&#39;,&#39;Fira Sans&#39;,&#39;Droid Sans&#39;,&#39;Helvetica Neue&#39;,sans-serif; color:#9EB0C9; font-size:10px;">&copy;
<a href="#" target="_blank" style="color:#9EB0C9 !important; text-decoration:none;">Author's
Haven</a>
&nbsp;&nbsp;|&nbsp;&nbsp;
<a href="https://reallygoodemails.com/" target="_blank" style="color:#9EB0C9 !important; text-decoration:none;">Courtesy
of Really Good Emails</a>
</span>
</td>
</tr>
<tr>
<td height="50">&nbsp;</td>
</tr>
</tbody>
</table>
<!-- FOOTER end here -->
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</body>
</html>
`;
Loading

0 comments on commit e78f2ed

Please sign in to comment.