2016-04-07 06:06:19 +00:00
|
|
|
import moment from 'moment';
|
2015-06-03 23:19:23 +00:00
|
|
|
|
2016-04-07 06:06:19 +00:00
|
|
|
import { unDasherize } from '../utils';
|
|
|
|
import { observeMethod } from '../utils/rx';
|
2015-06-25 22:03:46 +00:00
|
|
|
|
2015-10-07 06:23:44 +00:00
|
|
|
const foundationDate = 1413298800000;
|
|
|
|
const time48Hours = 172800000;
|
|
|
|
|
2015-06-25 22:03:46 +00:00
|
|
|
function hotRank(timeValue, rank) {
|
|
|
|
/*
|
|
|
|
* Hotness ranking algorithm: http://amix.dk/blog/post/19588
|
|
|
|
* tMS = postedOnDate - foundationTime;
|
|
|
|
* Ranking...
|
|
|
|
* f(ts, 1, rank) = log(10)z + (ts)/45000;
|
|
|
|
*/
|
|
|
|
var z = Math.log(rank) / Math.log(10);
|
|
|
|
var hotness = z + (timeValue / time48Hours);
|
|
|
|
return hotness;
|
|
|
|
}
|
|
|
|
|
|
|
|
function sortByRank(a, b) {
|
|
|
|
return hotRank(b.timePosted - foundationDate, b.rank) -
|
|
|
|
hotRank(a.timePosted - foundationDate, a.rank);
|
|
|
|
}
|
|
|
|
|
2015-06-03 23:19:23 +00:00
|
|
|
module.exports = function(app) {
|
2016-04-07 06:06:19 +00:00
|
|
|
const router = app.loopback.Router();
|
|
|
|
const Story = app.models.Story;
|
|
|
|
const findStory = observeMethod(Story, 'find');
|
|
|
|
const findOneStory = observeMethod(Story, 'findOne');
|
|
|
|
const query = {
|
|
|
|
order: 'timePosted DESC',
|
|
|
|
limit: 1000
|
|
|
|
};
|
|
|
|
const storiesData$ = findStory(query)
|
|
|
|
.map(stories => {
|
|
|
|
const sliceVal = stories.length >= 100 ? 100 : stories.length;
|
|
|
|
return stories.sort(sortByRank).slice(0, sliceVal);
|
|
|
|
})
|
|
|
|
.shareReplay();
|
|
|
|
|
|
|
|
const redirectToNews = (req, res) => res.redirect('/news');
|
|
|
|
const deprecated = (req, res) => res.sendStatus(410);
|
2016-04-07 17:12:29 +00:00
|
|
|
router.get('/news', showNews);
|
2016-04-07 06:06:19 +00:00
|
|
|
router.post('/news/userstories', deprecated);
|
2015-08-01 02:51:21 +00:00
|
|
|
router.get('/news/hot', hotJSON);
|
2015-11-08 10:39:17 +00:00
|
|
|
router.get('/news/feed', RSSFeed);
|
2015-08-01 03:10:30 +00:00
|
|
|
router.get('/stories/hotStories', hotJSON);
|
2016-04-07 06:06:19 +00:00
|
|
|
router.get('/stories/submit', redirectToNews);
|
|
|
|
router.get('/stories/submit/new-story', redirectToNews);
|
|
|
|
router.post('/stories/preliminary', deprecated);
|
|
|
|
router.post('/stories/', deprecated);
|
|
|
|
router.post('/stories/search', deprecated);
|
2015-06-26 06:39:38 +00:00
|
|
|
router.get('/news/:storyName', returnIndividualStory);
|
2016-04-07 06:06:19 +00:00
|
|
|
router.post('/stories/upvote/', deprecated);
|
|
|
|
router.get('/stories/:storyName', replaceStoryWithNews);
|
2015-06-03 23:19:23 +00:00
|
|
|
|
2015-06-03 23:31:42 +00:00
|
|
|
app.use(router);
|
|
|
|
|
2016-04-07 17:12:29 +00:00
|
|
|
function showNews(req, res) {
|
|
|
|
res.render('news/deprecated', { title: 'Camper News' });
|
|
|
|
}
|
|
|
|
|
2016-04-07 06:06:19 +00:00
|
|
|
function replaceStoryWithNews(req, res) {
|
2015-06-26 06:39:38 +00:00
|
|
|
var url = req.originalUrl.replace(/^\/stories/, '/news');
|
|
|
|
return res.redirect(url);
|
|
|
|
}
|
|
|
|
|
2015-06-09 18:54:45 +00:00
|
|
|
function hotJSON(req, res, next) {
|
2016-04-07 06:06:19 +00:00
|
|
|
storiesData$.subscribe(
|
|
|
|
stories => res.json(stories),
|
2015-06-25 22:03:46 +00:00
|
|
|
next
|
|
|
|
);
|
2015-06-03 23:19:23 +00:00
|
|
|
}
|
|
|
|
|
2015-11-08 10:39:17 +00:00
|
|
|
function RSSFeed(req, res, next) {
|
2016-04-07 06:06:19 +00:00
|
|
|
storiesData$.subscribe(
|
|
|
|
data => {
|
2015-11-15 07:39:30 +00:00
|
|
|
res.set('Content-Type', 'text/xml');
|
2016-04-07 17:12:29 +00:00
|
|
|
res.render('news/feed', {
|
2015-11-08 10:39:17 +00:00
|
|
|
title: 'FreeCodeCamp Camper News RSS Feed',
|
|
|
|
description: 'RSS Feed for FreeCodeCamp Top 100 Hot Camper News',
|
|
|
|
url: 'http://www.freecodecamp.com/news',
|
|
|
|
FeedPosts: data
|
|
|
|
});
|
|
|
|
},
|
|
|
|
next
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2015-06-03 23:19:23 +00:00
|
|
|
function returnIndividualStory(req, res, next) {
|
|
|
|
var dashedName = req.params.storyName;
|
2015-06-25 22:03:46 +00:00
|
|
|
var storyName = unDasherize(dashedName);
|
2015-06-03 23:19:23 +00:00
|
|
|
|
2015-06-25 22:03:46 +00:00
|
|
|
findOneStory({ where: { storyLink: storyName } }).subscribe(
|
|
|
|
function(story) {
|
|
|
|
if (!story) {
|
|
|
|
req.flash('errors', {
|
|
|
|
msg: "404: We couldn't find a story with that name. " +
|
|
|
|
'Please double check the name.'
|
|
|
|
});
|
2015-06-26 07:16:18 +00:00
|
|
|
return res.redirect('/news');
|
|
|
|
}
|
2015-06-03 23:19:23 +00:00
|
|
|
|
2015-06-26 07:16:18 +00:00
|
|
|
var dashedNameFull = story.storyLink.toLowerCase()
|
|
|
|
.replace(/\s+/g, ' ')
|
|
|
|
.replace(/\s/g, '-');
|
2015-03-03 13:03:33 +00:00
|
|
|
|
2015-06-26 07:16:18 +00:00
|
|
|
if (dashedNameFull !== dashedName) {
|
|
|
|
return res.redirect('../stories/' + dashedNameFull);
|
2015-06-25 22:03:46 +00:00
|
|
|
}
|
2015-06-03 23:19:23 +00:00
|
|
|
|
2016-04-07 17:12:29 +00:00
|
|
|
return res.render('news/index', {
|
|
|
|
title: story.headline || 'news',
|
2015-06-25 22:03:46 +00:00
|
|
|
link: story.link,
|
|
|
|
originalStoryLink: dashedName,
|
|
|
|
author: story.author,
|
|
|
|
rank: story.upVotes.length,
|
|
|
|
id: story.id,
|
|
|
|
timeAgo: moment(story.timePosted).fromNow(),
|
|
|
|
image: story.image,
|
2016-04-07 17:12:29 +00:00
|
|
|
storyMetaDescription: story.metaDescription
|
2015-06-03 23:19:23 +00:00
|
|
|
});
|
2015-06-25 22:03:46 +00:00
|
|
|
},
|
|
|
|
next
|
|
|
|
);
|
2015-06-03 23:19:23 +00:00
|
|
|
}
|
|
|
|
};
|