2018-07-31 16:58:04 +01:00
|
|
|
import React from 'react';
|
|
|
|
import { renderToString } from 'react-dom/server';
|
2018-08-01 12:42:00 +01:00
|
|
|
import { StaticRouter } from 'react-router-dom';
|
2018-08-03 11:41:17 +01:00
|
|
|
import { has } from 'lodash';
|
|
|
|
import debug from 'debug';
|
2018-07-31 16:58:04 +01:00
|
|
|
|
|
|
|
import NewsApp from '../../news/NewsApp';
|
|
|
|
|
2018-08-03 11:41:17 +01:00
|
|
|
const routerLog = debug('fcc:boot:news:router');
|
|
|
|
const apiLog = debug('fcc:boot:news:api');
|
|
|
|
|
|
|
|
export default function newsBoot(app) {
|
|
|
|
const router = app.loopback.Router();
|
|
|
|
const api = app.loopback.Router();
|
|
|
|
|
|
|
|
router.get('/n', (req, res) => res.redirect('/news'));
|
2018-08-03 14:43:28 +01:00
|
|
|
router.get('/n/:shortId', createShortLinkHandler(app));
|
2018-08-03 11:41:17 +01:00
|
|
|
|
|
|
|
router.get('/news', serveNewsApp);
|
|
|
|
router.get('/news/*', serveNewsApp);
|
|
|
|
|
|
|
|
api.post('/p', createPopularityHandler(app));
|
|
|
|
|
|
|
|
app.use(api);
|
|
|
|
app.use(router);
|
|
|
|
}
|
|
|
|
|
2018-08-01 12:42:00 +01:00
|
|
|
function serveNewsApp(req, res) {
|
|
|
|
const context = {};
|
|
|
|
const markup = renderToString(
|
|
|
|
<StaticRouter basename='/news' context={context} location={req.url}>
|
|
|
|
<NewsApp />
|
|
|
|
</StaticRouter>
|
|
|
|
);
|
2018-08-02 16:48:02 +01:00
|
|
|
if (context.url) {
|
2018-08-03 11:41:17 +01:00
|
|
|
routerLog('redirect found in `renderToString`');
|
2018-08-02 16:48:02 +01:00
|
|
|
// 'client-side' routing hit on a redirect
|
|
|
|
return res.redirect(context.url);
|
|
|
|
}
|
2018-08-03 11:41:17 +01:00
|
|
|
routerLog('news markup sending');
|
2018-08-01 12:42:00 +01:00
|
|
|
return res.render('layout-news', { title: 'News | freeCodeCamp', markup });
|
|
|
|
}
|
|
|
|
|
2018-08-03 14:43:28 +01:00
|
|
|
function createShortLinkHandler(app) {
|
2018-08-03 11:41:17 +01:00
|
|
|
const { Article } = app.models;
|
|
|
|
|
2018-08-03 14:43:28 +01:00
|
|
|
const referralHandler = createRerralHandler(app);
|
|
|
|
|
|
|
|
return function shortLinkHandler(req, res, next) {
|
|
|
|
const { query, user } = req;
|
2018-08-03 10:32:38 +01:00
|
|
|
const { shortId } = req.params;
|
2018-08-03 14:43:28 +01:00
|
|
|
|
|
|
|
referralHandler(query, shortId, !!user);
|
|
|
|
|
|
|
|
routerLog(req.origin);
|
|
|
|
routerLog(query.refsource);
|
2018-08-03 10:32:38 +01:00
|
|
|
if (!shortId) {
|
|
|
|
return res.redirect('/news');
|
|
|
|
}
|
2018-08-03 11:41:17 +01:00
|
|
|
routerLog('shortId', shortId);
|
2018-08-03 10:32:38 +01:00
|
|
|
return Article.findOne(
|
|
|
|
{
|
|
|
|
where: {
|
|
|
|
or: [{ shortId }, { slugPart: shortId }]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
(err, article) => {
|
|
|
|
if (err) {
|
|
|
|
next(err);
|
|
|
|
}
|
|
|
|
if (!article) {
|
|
|
|
return res.redirect('/news');
|
|
|
|
}
|
|
|
|
const {
|
|
|
|
slugPart,
|
|
|
|
shortId,
|
|
|
|
author: { username }
|
|
|
|
} = article;
|
|
|
|
const slug = `/news/${username}/${slugPart}--${shortId}`;
|
|
|
|
return res.redirect(slug);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
};
|
|
|
|
}
|
2018-08-02 16:48:02 +01:00
|
|
|
|
2018-08-03 11:41:17 +01:00
|
|
|
function createPopularityHandler(app) {
|
|
|
|
const { Article, Popularity } = app.models;
|
2018-07-31 16:34:32 +01:00
|
|
|
|
2018-08-03 11:41:17 +01:00
|
|
|
return function handlePopularityStats(req, res, next) {
|
|
|
|
const { body, user } = req;
|
2018-08-03 14:43:28 +01:00
|
|
|
|
2018-08-03 11:41:17 +01:00
|
|
|
if (
|
|
|
|
!has(body, 'event') ||
|
|
|
|
!has(body, 'timestamp') ||
|
|
|
|
!has(body, 'shortId')
|
|
|
|
) {
|
|
|
|
console.warn('Popularity event recieved from client is malformed');
|
|
|
|
console.log(JSON.stringify(body, null, 2));
|
|
|
|
// sending 200 because the client shouldn't care for this
|
|
|
|
return res.sendStatus(200);
|
|
|
|
}
|
|
|
|
res.sendStatus(200);
|
|
|
|
const { shortId } = body;
|
|
|
|
apiLog('shortId', shortId);
|
|
|
|
const populartiyUpdate = {
|
|
|
|
...body,
|
|
|
|
byAuthenticatedUser: !!user
|
|
|
|
};
|
|
|
|
Popularity.findOne({ where: { articleId: shortId } }, (err, popularity) => {
|
|
|
|
if (err) {
|
|
|
|
apiLog(err);
|
|
|
|
return next(err);
|
|
|
|
}
|
|
|
|
if (popularity) {
|
|
|
|
return popularity.updateAttribute(
|
|
|
|
'events',
|
|
|
|
[populartiyUpdate, ...popularity.events],
|
|
|
|
err => {
|
|
|
|
if (err) {
|
|
|
|
apiLog(err);
|
|
|
|
return next(err);
|
|
|
|
}
|
|
|
|
return apiLog('poplarity updated');
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return Popularity.create(
|
|
|
|
{
|
|
|
|
events: [populartiyUpdate],
|
|
|
|
articleId: shortId
|
|
|
|
},
|
|
|
|
err => {
|
|
|
|
if (err) {
|
|
|
|
apiLog(err);
|
|
|
|
return next(err);
|
|
|
|
}
|
|
|
|
return apiLog('poulartiy created');
|
|
|
|
}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
return body.event === 'view'
|
|
|
|
? Article.findOne({ where: { shortId } }, (err, article) => {
|
|
|
|
if (err) {
|
|
|
|
apiLog(err);
|
|
|
|
next(err);
|
|
|
|
}
|
|
|
|
return article.updateAttributes(
|
|
|
|
{ viewCount: article.viewCount + 1 },
|
|
|
|
err => {
|
|
|
|
if (err) {
|
|
|
|
apiLog(err);
|
|
|
|
return next(err);
|
|
|
|
}
|
|
|
|
return apiLog('article views updated');
|
|
|
|
}
|
|
|
|
);
|
|
|
|
})
|
|
|
|
: null;
|
|
|
|
};
|
2018-07-31 16:34:32 +01:00
|
|
|
}
|
2018-08-03 14:43:28 +01:00
|
|
|
|
|
|
|
function createRerralHandler(app) {
|
|
|
|
const { Popularity } = app.models;
|
|
|
|
|
|
|
|
return function referralHandler(query, shortId, byAuthenticatedUser) {
|
|
|
|
if (!query.refsource) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
const eventUpdate = {
|
|
|
|
event: `referral - ${query.refsource}`,
|
|
|
|
timestamp: new Date(Date.now()),
|
|
|
|
byAuthenticatedUser
|
|
|
|
};
|
|
|
|
return Popularity.findOne(
|
|
|
|
{ where: { articleId: shortId } },
|
|
|
|
(err, popularity) => {
|
|
|
|
if (err) {
|
|
|
|
console.error(
|
|
|
|
'Failed finding a `Popularity` in a referral handler',
|
|
|
|
err
|
|
|
|
);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (popularity) {
|
|
|
|
return popularity.updateAttribute(
|
|
|
|
'events',
|
|
|
|
[eventUpdate, ...popularity.events],
|
|
|
|
err => {
|
|
|
|
if (err) {
|
|
|
|
console.error(
|
|
|
|
'Failed in updating the `events` attribute of a `popularity`',
|
|
|
|
err
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return Popularity.create(
|
|
|
|
{
|
|
|
|
events: [eventUpdate],
|
|
|
|
articleId: shortId
|
|
|
|
},
|
|
|
|
err => {
|
|
|
|
if (err) {
|
|
|
|
return console.error('Failed creating a new `Popularity`', err);
|
|
|
|
}
|
|
|
|
return apiLog('poulartiy created');
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
};
|
|
|
|
}
|