diff --git a/api-server/server/boot/news.js b/api-server/server/boot/news.js
index b7dc2e88b9..6ca80df1bd 100644
--- a/api-server/server/boot/news.js
+++ b/api-server/server/boot/news.js
@@ -1,34 +1,28 @@
-import { has, pick, isEmpty } from 'lodash';
import debug from 'debug';
-import { reportError } from '../middlewares/error-reporter';
const log = debug('fcc:boot:news');
export default function newsBoot(app) {
- const api = app.loopback.Router();
+ const router = app.loopback.Router();
- api.get('/n/:shortId', createShortLinkHandler(app));
-
- api.post('/p', createPopularityHandler(app));
-
- app.use('/internal', api);
+ router.get('/n', (req, res) => res.redirect('/news'));
+ router.get('/n/:shortId', createShortLinkHandler(app));
}
function createShortLinkHandler(app) {
const { Article } = app.models;
- const referralHandler = createReferralHandler(app);
-
return function shortLinkHandler(req, res, next) {
- const { query, user } = req;
+ const { query } = req;
const { shortId } = req.params;
- // We manually report the error here as it should not affect this request
- referralHandler(query, shortId, !!user).catch(err => reportError(err));
+ log(req.origin);
+ log(query.refsource);
if (!shortId) {
- return res.sendStatus(400);
+ return res.redirect('/news');
}
+ log('shortId', shortId);
return Article.findOne(
{
where: {
@@ -40,220 +34,14 @@ function createShortLinkHandler(app) {
next(err);
}
if (!article) {
- return res.status(404).send('Could not find article by shortId');
+ return res.redirect('/news');
}
const {
- slugPart,
- shortId,
- author: { username }
+ slugPart
} = article;
- const slug = `/news/${username}/${slugPart}--${shortId}`;
- const articleData = {
- ...pick(article, [
- 'author',
- 'renderableContent',
- 'firstPublishedDate',
- 'viewCount',
- 'title',
- 'featureImage',
- 'slugPart',
- 'shortId',
- 'meta'
- ]),
- slug
- };
- return res.json(articleData);
+ const slug = `/news/${slugPart}`;
+ return res.redirect(slug);
}
);
};
}
-
-function createPopularityHandler(app) {
- const { Article, Popularity } = app.models;
-
- function findArticleByShortId(shortId) {
- return new Promise((resolve, reject) =>
- Article.findOne({ where: { shortId } }, (err, article) => {
- if (err) {
- log('Error returned from Article.findOne(shortId)');
- return reject(err);
- }
- log('article found');
- return resolve(article);
- })
- );
- }
-
- function findPopularityByShortId(shortId) {
- return new Promise((resolve, reject) =>
- Popularity.findOne(
- { where: { articleId: shortId } },
- (err, popularity) => {
- if (err) {
- log('Error returned from Popularity.findOne(shortId)');
- return reject(err);
- }
- log('popularity found');
- return resolve(popularity);
- }
- )
- );
- }
-
- function createPopularity(popularityUpdate, shortId) {
- return new Promise((resolve, reject) =>
- Popularity.create(
- {
- events: [popularityUpdate],
- articleId: shortId
- },
- err => {
- if (err) {
- return reject(err);
- }
- log('poulartiy created');
- return resolve();
- }
- )
- );
- }
-
- function updatePopularity(popularity, popularityUpdate) {
- return new Promise((resolve, reject) =>
- popularity.updateAttribute(
- 'events',
- [popularityUpdate, ...popularity.events],
- err => {
- if (err) {
- log('Error returned from popularity.updateAttribute()');
- return reject(err);
- }
- log('poplarity updated');
- return resolve();
- }
- )
- );
- }
-
- function incrementArticleViews(article) {
- return new Promise((resolve, reject) =>
- article.updateAttributes({ $inc: { viewCount: 1 } }, err => {
- if (err) {
- log(err);
- return reject(err);
- }
- log('article views updated');
- return resolve();
- })
- );
- }
-
- return async function handlePopularityStats(req, res, next) {
- const { body, user } = req;
-
- 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);
- }
- const { shortId } = body;
- log('shortId', shortId);
-
- const articlePromise = findArticleByShortId(shortId);
- const popularityPromise = findPopularityByShortId(shortId);
-
- const [article, popularity] = await Promise.all([
- articlePromise,
- popularityPromise
- ]).catch(err => {
- log('find catch');
- return next(err);
- });
- if (!article || isEmpty(article)) {
- log('No article found to handle the populartity update');
- // sending 200 because the client shouldn't care for this
- return res.sendStatus(200);
- }
-
- const populartiyUpdate = {
- ...body,
- byAuthenticatedUser: !!user
- };
-
- const populartiyUpdateOrCreatePromise = isEmpty(popularity)
- ? createPopularity(populartiyUpdate, shortId)
- : updatePopularity(popularity, populartiyUpdate);
- const maybeUpdateArticlePromise =
- body.event === 'view' ? incrementArticleViews(article) : null;
- return Promise.all([
- populartiyUpdateOrCreatePromise,
- maybeUpdateArticlePromise
- ])
- .then(() => res.sendStatus(200))
- .catch(err => {
- log('updates catch');
- return next(err);
- });
- };
-}
-
-function createReferralHandler(app) {
- const { Popularity } = app.models;
-
- return function referralHandler(query, shortId, byAuthenticatedUser) {
- if (!query.refsource) {
- return Promise.resolve();
- }
- const eventUpdate = {
- event: `referral - ${query.refsource}`,
- timestamp: new Date(Date.now()),
- byAuthenticatedUser
- };
- return new Promise((resolve, reject) =>
- Popularity.findOne(
- { where: { articleId: shortId } },
- (err, popularity) => {
- if (err) {
- console.error(
- 'Failed finding a `Popularity` in a referral handler',
- err
- );
- return reject(err);
- }
-
- if (popularity) {
- return popularity.updateAttribute(
- 'events',
- [eventUpdate, ...popularity.events],
- err => {
- if (err) {
- return reject(err);
- }
- log('populartiy updated');
- return resolve();
- }
- );
- }
- return Popularity.create(
- {
- events: [eventUpdate],
- articleId: shortId
- },
- err => {
- if (err) {
- return reject(err);
- }
- log('poulartiy created');
- return resolve();
- }
- );
- }
- )
- );
- };
-}
diff --git a/api-server/server/middlewares/add-return-to.js b/api-server/server/middlewares/add-return-to.js
index 73f3b6a694..00935140f9 100644
--- a/api-server/server/middlewares/add-return-to.js
+++ b/api-server/server/middlewares/add-return-to.js
@@ -12,10 +12,8 @@ const pathsOfNoReturn = [
];
const pathsWhiteList = [
- 'news',
'challenges',
'map',
- 'news',
'commit'
];
diff --git a/client/gatsby-config.js b/client/gatsby-config.js
index a0c262e5c1..9e353ca49e 100644
--- a/client/gatsby-config.js
+++ b/client/gatsby-config.js
@@ -46,12 +46,6 @@ module.exports = {
curriculumPath: localeChallengesRootDir
}
},
- {
- resolve: 'fcc-source-news',
- options: {
- maximumStaticRenderCount: 100
- }
- },
{
resolve: 'gatsby-source-filesystem',
options: {
diff --git a/client/gatsby-node.js b/client/gatsby-node.js
index a898d5f5fe..13fe801eee 100644
--- a/client/gatsby-node.js
+++ b/client/gatsby-node.js
@@ -8,10 +8,8 @@ const {
createChallengePages,
createBlockIntroPages,
createSuperBlockIntroPages,
- createGuideArticlePages,
- createNewsArticle
+ createGuideArticlePages
} = require('./utils/gatsby');
-const { createArticleSlug } = require('./utils/news');
const createByIdentityMap = {
guideMarkdown: createGuideArticlePages,
@@ -37,15 +35,7 @@ exports.onCreateNode = function onCreateNode({ node, actions, getNode }) {
createNodeField({ node, name: 'slug', value: slug });
}
}
- if (node.internal.type === 'NewsArticleNode') {
- const {
- author: { username },
- slugPart,
- shortId
- } = node;
- const slug = createArticleSlug({ username, shortId, slugPart });
- createNodeField({ node, name: 'slug', value: slug });
- }
+
};
exports.createPages = function createPages({ graphql, actions }) {
@@ -97,19 +87,6 @@ exports.createPages = function createPages({ graphql, actions }) {
}
}
}
- allNewsArticleNode(
- sort: { fields: firstPublishedDate, order: DESC }
- ) {
- edges {
- node {
- id
- shortId
- fields {
- slug
- }
- }
- }
- }
}
`).then(result => {
if (result.errors) {
@@ -150,11 +127,6 @@ exports.createPages = function createPages({ graphql, actions }) {
return null;
});
- // Create news article pages
- result.data.allNewsArticleNode.edges.forEach(
- createNewsArticle(createPage)
- );
-
return null;
})
);
diff --git a/client/plugins/fcc-source-news/create-news-node.js b/client/plugins/fcc-source-news/create-news-node.js
deleted file mode 100644
index c360e8017c..0000000000
--- a/client/plugins/fcc-source-news/create-news-node.js
+++ /dev/null
@@ -1,26 +0,0 @@
-const crypto = require('crypto');
-
-function createNewsNode(article) {
- const contentDigest = crypto
- .createHash('md5')
- .update(JSON.stringify(article))
- .digest('hex');
-
- const internal = {
- contentDigest,
- type: 'NewsArticleNode'
- };
-
- return JSON.parse(
- JSON.stringify({
- ...article,
- id: article._id + ' >>>>>>> ' + internal.type,
- children: [],
- parent: null,
- internal,
- sourceInstanceName: 'article'
- })
- );
-}
-
-exports.createNewsNode = createNewsNode;
diff --git a/client/plugins/fcc-source-news/gatsby-node.js b/client/plugins/fcc-source-news/gatsby-node.js
deleted file mode 100644
index 961414727c..0000000000
--- a/client/plugins/fcc-source-news/gatsby-node.js
+++ /dev/null
@@ -1,55 +0,0 @@
-const path = require('path');
-require('dotenv').config({ path: path.resolve(__dirname, '../../../.env') });
-const { MongoClient } = require('mongodb');
-
-const { createNewsNode } = require('./create-news-node');
-const { db } = require('../../../config/secrets');
-
-exports.sourceNodes = function sourceChallengesSourceNodes(
- { actions, reporter },
- pluginOptions
-) {
- function handleError(err, client, reject) {
- if (err) {
- if (client) {
- client.close();
- }
- reject(err);
- reporter.panic(err);
- }
- }
- const { maximumStaticRenderCount = 100 } = pluginOptions;
- const { createNode } = actions;
-
- return new Promise((resolve, reject) =>
- MongoClient.connect(
- db,
- { useNewUrlParser: true },
- async function(err, client) {
- handleError(err, client, reject);
-
- reporter.info('fcc-source-news connected successfully to mongo');
- const db = client.db('freecodecamp');
- const articleCollection = db.collection('article');
-
- articleCollection
- .aggregate([
- { $match: { featured: true } },
- { $sort: { firstPublishedDate: -1 } },
- { $limit: maximumStaticRenderCount }
- ])
- .toArray((err, articles) => {
- handleError(err, client, reject);
-
- articles
- .map(article => createNewsNode(article))
- .map(node => createNode(node));
-
- client.close();
- reporter.info('fcc-source-news mongo connection closed');
- return resolve();
- });
- }
- )
- );
-};
diff --git a/client/plugins/fcc-source-news/package-lock.json b/client/plugins/fcc-source-news/package-lock.json
deleted file mode 100644
index 1e506ea7c0..0000000000
--- a/client/plugins/fcc-source-news/package-lock.json
+++ /dev/null
@@ -1,80 +0,0 @@
-{
- "name": "fcc-source-news",
- "requires": true,
- "lockfileVersion": 1,
- "dependencies": {
- "bson": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.0.tgz",
- "integrity": "sha512-9Aeai9TacfNtWXOYarkFJRW2CWo+dRon+fuLZYJmvLV3+MiUp0bEI6IAZfXEIg7/Pl/7IWlLaDnhzTsD81etQA=="
- },
- "memory-pager": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.1.0.tgz",
- "integrity": "sha512-Mf9OHV/Y7h6YWDxTzX/b4ZZ4oh9NSXblQL8dtPCOomOtZciEHxePR78+uHFLLlsk01A6jVHhHsQZZ/WcIPpnzg==",
- "optional": true
- },
- "mongodb": {
- "version": "3.1.9",
- "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.1.9.tgz",
- "integrity": "sha512-f+Og32wK/ovzVlC1S6Ft7yjVTvNsAOs6pBpDrPd2/3wPO9ijNsQrTNntuECjOSxGZpPVl0aRqgHzF1e9e+KvnQ==",
- "requires": {
- "mongodb-core": "3.1.8",
- "safe-buffer": "^5.1.2"
- }
- },
- "mongodb-core": {
- "version": "3.1.8",
- "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-3.1.8.tgz",
- "integrity": "sha512-reWCqIRNehyuLaqaz5JMOmh3Xd8JIjNX34o8mnewXLK2Fyt/Ky6BZbU+X0OPzy8qbX+JZrOtnuay7ASCieTYZw==",
- "requires": {
- "bson": "^1.1.0",
- "require_optional": "^1.0.1",
- "safe-buffer": "^5.1.2",
- "saslprep": "^1.0.0"
- }
- },
- "require_optional": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz",
- "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==",
- "requires": {
- "resolve-from": "^2.0.0",
- "semver": "^5.1.0"
- }
- },
- "resolve-from": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz",
- "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c="
- },
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
- },
- "saslprep": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.2.tgz",
- "integrity": "sha512-4cDsYuAjXssUSjxHKRe4DTZC0agDwsCqcMqtJAQPzC74nJ7LfAJflAtC1Zed5hMzEQKj82d3tuzqdGNRsLJ4Gw==",
- "optional": true,
- "requires": {
- "sparse-bitfield": "^3.0.3"
- }
- },
- "semver": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
- "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg=="
- },
- "sparse-bitfield": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
- "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=",
- "optional": true,
- "requires": {
- "memory-pager": "^1.0.2"
- }
- }
- }
-}
diff --git a/client/plugins/fcc-source-news/package.json b/client/plugins/fcc-source-news/package.json
deleted file mode 100644
index 78ebc005d2..0000000000
--- a/client/plugins/fcc-source-news/package.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "name": "fcc-source-news",
- "dependencies": {
- "mongodb": "^3.1.9"
- }
-}
diff --git a/client/src/__mocks__/news-article.js b/client/src/__mocks__/news-article.js
deleted file mode 100644
index 4ca619f060..0000000000
--- a/client/src/__mocks__/news-article.js
+++ /dev/null
@@ -1,16 +0,0 @@
-export const slugWithId = '/news/quincy/an-article-title--abcDEF123';
-export const slugWithIdAndQuery =
- '/news/quincy/an-article-title--abcDEF123?some=query';
-export const slugWithIdAndHash =
- '/news/quincy/an-article-title--abcDEF123#top-of-page';
-export const slugWithIdAndTrailingSlash =
- '/news/quincy/an-article-title--abcDEF123/';
-
-export const mockId = 'abcDEF123';
-export const slugWithoutId = '/news/quincy/an-article-title';
-
-export const mockArguments = {
- username: 'quincy',
- slugPart: 'an-article-title',
- shortId: 'abcDEF123'
-};
diff --git a/client/src/__tests__/integration/news-slug.test.js b/client/src/__tests__/integration/news-slug.test.js
deleted file mode 100644
index f79357dbdc..0000000000
--- a/client/src/__tests__/integration/news-slug.test.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/* global describe it expect */
-import faker from 'faker';
-import { kebabCase } from 'lodash';
-import shortid from 'shortid';
-
-import { createArticleSlug } from '../../../utils/news';
-import { getShortIdFromSlug } from '../../utils';
-
-shortid.characters(
- '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$+'
-);
-const shortId = () => shortid.generate();
-
-describe('news-slug integration', () => {
- it('returns the correct id from a generated slug', () => {
- expect.assertions(100);
-
- const generatedArguments = Array(100)
- .fill(null)
- .map(() => ({
- username: faker.internet.userName(),
- slugPart: kebabCase(faker.lorem.sentence()).toLowerCase(),
- shortId: shortId()
- }));
-
- return generatedArguments.forEach(arg => {
- const { shortId } = arg;
- const generatedSlug = createArticleSlug(arg);
- const extractedId = getShortIdFromSlug(generatedSlug);
- return expect(extractedId).toEqual(shortId);
- });
- });
-});
diff --git a/client/src/client-only-routes/ShowDynamicNewsOrFourOhFour.js b/client/src/client-only-routes/ShowDynamicNewsOrFourOhFour.js
deleted file mode 100644
index bb62d5b783..0000000000
--- a/client/src/client-only-routes/ShowDynamicNewsOrFourOhFour.js
+++ /dev/null
@@ -1,89 +0,0 @@
-import React, { Component } from 'react';
-import { connect } from 'react-redux';
-import { bindActionCreators } from 'redux';
-import { isNull, pick, isEmpty } from 'lodash';
-
-import Layout from '../components/layouts/Default';
-import Loader from '../components/helpers/Loader';
-
-import { getShortIdFromSlug } from '../utils';
-import { createArticleSlug } from '../../utils/news';
-import {
- resolveShortId,
- resolveShortIdFetchStateSelector,
- dynamicArticleByIdMapSelector
-} from '../templates/News/redux';
-import { createFlashMessage } from '../components/Flash/redux';
-import ShowArticle from '../templates/News/ShowArticle';
-
-const mapStateToProps = () => (state, { articleSlug = '' }) => {
- const shortId = getShortIdFromSlug(articleSlug);
- const articleMap = dynamicArticleByIdMapSelector(state);
- const article = articleMap[shortId] || null;
- const fetchState = resolveShortIdFetchStateSelector(state);
- return { article, fetchState, shortId };
-};
-const mapDispatchToProps = dispatch =>
- bindActionCreators({ createFlashMessage, resolveShortId }, dispatch);
-
-class DynamicNewsArticle extends Component {
- componentDidMount() {
- const { shortId, article, resolveShortId } = this.props;
- if (isNull(article)) {
- return resolveShortId(shortId);
- }
- return null;
- }
-
- getArticleAsGatsbyProps(article) {
- const {
- author: { username },
- slugPart,
- shortId,
- meta: { readTime }
- } = article;
-
- return {
- data: {
- newsArticleNode: {
- ...pick(article, [
- 'title',
- 'renderableContent',
- 'youtube',
- 'author',
- 'firstPublishedDate',
- 'shortId',
- 'featureImage'
- ]),
- fields: { slug: createArticleSlug({ username, slugPart, shortId }) },
- meta: { readTime }
- }
- }
- };
- }
-
- render() {
- const {
- fetchState: { pending },
- article
- } = this.props;
- if (pending) {
- return (
-
-
-
-
-
- );
- }
- return isEmpty(article) ? null : (
-
- );
- }
-}
-DynamicNewsArticle.displayName = 'DynamicNewsArticle';
-
-export default connect(
- mapStateToProps,
- mapDispatchToProps
-)(DynamicNewsArticle);
diff --git a/client/src/components/Header/index.js b/client/src/components/Header/index.js
index c6e1b8b46d..f45d9787b1 100644
--- a/client/src/components/Header/index.js
+++ b/client/src/components/Header/index.js
@@ -22,7 +22,7 @@ function Header({ disableSettings }) {
diff --git a/client/src/components/RedirectNews.js b/client/src/components/RedirectNews.js
deleted file mode 100644
index a4c2a7178d..0000000000
--- a/client/src/components/RedirectNews.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import createRedirect from './createRedirect';
-
-export default createRedirect('/news');
diff --git a/client/src/pages/404.js b/client/src/pages/404.js
index 4743023e15..e6c64971f1 100644
--- a/client/src/pages/404.js
+++ b/client/src/pages/404.js
@@ -2,18 +2,14 @@ import React from 'react';
import { Router } from '@reach/router';
import NotFoundPage from '../components/FourOhFour';
-import RedirectNews from '../components/RedirectNews';
/* eslint-disable max-len */
import ShowProfileOrFourOhFour from '../client-only-routes/ShowProfileOrFourOhFour';
-import ShowDynamicNewsOrFourOhFour from '../client-only-routes/ShowDynamicNewsOrFourOhFour';
/* eslint-enable max-len */
function FourOhFourPage() {
return (
-
-
);
diff --git a/client/src/pages/n.js b/client/src/pages/n.js
deleted file mode 100644
index 091967ec4a..0000000000
--- a/client/src/pages/n.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import React from 'react';
-import { Router } from '@reach/router';
-
-import NewsReferalLinkHandler from '../templates/News/NewsReferalLinkHandler';
-import RedirectNews from '../components/RedirectNews';
-
-export default function NewsReferalLinkRouter() {
- return (
-
-
-
-
-
- );
-}
diff --git a/client/src/pages/news.js b/client/src/pages/news.js
deleted file mode 100644
index bb4d064310..0000000000
--- a/client/src/pages/news.js
+++ /dev/null
@@ -1,96 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { Grid } from '@freecodecamp/react-bootstrap';
-import { graphql } from 'gatsby';
-
-import Layout from '../components/layouts/Default';
-
-import FullWidthRow from '../components/helpers/FullWidthRow';
-import Featured from '../templates/News/Featured';
-
-const propTypes = {
- data: PropTypes.shape({
- allNewsArticleNode: PropTypes.shape({
- edges: PropTypes.arrayOf(
- PropTypes.shape({
- title: PropTypes.string,
- shortId: PropTypes.string,
- slugPart: PropTypes.string,
- featureImage: PropTypes.shape({
- src: PropTypes.string,
- alt: PropTypes.string,
- caption: PropTypes.string
- }),
- meta: PropTypes.shape({
- readTime: PropTypes.number
- }),
- author: PropTypes.shape({
- name: PropTypes.string,
- avatar: PropTypes.string,
- twitter: PropTypes.string,
- username: PropTypes.string,
- bio: PropTypes.string
- }),
- viewCount: PropTypes.number,
- firstPublishedDate: PropTypes.string
- })
- )
- })
- })
-};
-
-export default function NewsIndexPage(props) {
- const {
- allNewsArticleNode: { edges }
- } = props.data;
- const articles = edges.map(({ node }) => node);
- return (
-
-
-
- News - freeCodeCamp.org
-
-
-
-
-
-
- );
-}
-
-export const query = graphql`
- {
- allNewsArticleNode(sort: { fields: firstPublishedDate, order: DESC }) {
- edges {
- node {
- title
- shortId
- slugPart
- featureImage {
- src
- alt
- caption
- }
- meta {
- readTime
- }
- author {
- name
- avatar
- twitter
- bio
- username
- }
- viewCount
- firstPublishedDate
- fields {
- slug
- }
- }
- }
- }
- }
-`;
-
-NewsIndexPage.displayName = 'NewsIndexPage';
-NewsIndexPage.propTypes = propTypes;
diff --git a/client/src/redux/rootReducer.js b/client/src/redux/rootReducer.js
index df875b795a..8541b82759 100644
--- a/client/src/redux/rootReducer.js
+++ b/client/src/redux/rootReducer.js
@@ -15,7 +15,6 @@ import {
reducer as challenge,
ns as challengeNameSpace
} from '../templates/Challenges/redux';
-import { reducer as news, ns as newsNameSpace } from '../templates/News/redux';
export default combineReducers({
[appNameSpace]: app,
@@ -23,6 +22,5 @@ export default combineReducers({
[curriculumMapNameSpace]: curriculumMap,
[flashNameSpace]: flash,
form: formReducer,
- [newsNameSpace]: news,
[settingsNameSpace]: settings
});
diff --git a/client/src/redux/rootSaga.js b/client/src/redux/rootSaga.js
index 4d053e9b30..d6d07b335c 100644
--- a/client/src/redux/rootSaga.js
+++ b/client/src/redux/rootSaga.js
@@ -3,7 +3,6 @@ import { all } from 'redux-saga/effects';
import errorSagas from './error-saga';
import { sagas as appSagas } from './';
import { sagas as challengeSagas } from '../templates/Challenges/redux';
-import { sagas as newsSagas } from '../templates/News/redux';
import { sagas as settingsSagas } from './settings';
export default function* rootSaga() {
@@ -11,7 +10,6 @@ export default function* rootSaga() {
...errorSagas,
...appSagas,
...challengeSagas,
- ...newsSagas,
...settingsSagas
]);
}
diff --git a/client/src/templates/News/Featured/Featured.js b/client/src/templates/News/Featured/Featured.js
deleted file mode 100644
index c905c02125..0000000000
--- a/client/src/templates/News/Featured/Featured.js
+++ /dev/null
@@ -1,62 +0,0 @@
-import React, { Component } from 'react';
-import PropTypes from 'prop-types';
-import { navigate } from 'gatsby';
-import { Image } from '@freecodecamp/react-bootstrap';
-
-import Spacer from '../../../components/helpers/Spacer';
-import BannerWide from '../components/BannerWide';
-import ArticleMeta from '../components/ArticleMeta';
-
-import './featured.css';
-
-const propTypes = {
- featuredList: PropTypes.arrayOf(PropTypes.object)
-};
-
-class Featured extends Component {
- createHandleArticleClick(slug) {
- return e => {
- e.preventDefault();
- return navigate(slug);
- };
- }
-
- renderFeatured(articles) {
- return articles.map(article => {
- const { featureImage, shortId, title, fields: {slug} } = article;
- return (
-
-
- {title}
- {featureImage && featureImage.src ? (
-
- ) : (
-
- )}
-
-
-
-
- );
- });
- }
-
- render() {
- const { featuredList } = this.props;
- return (
- {this.renderFeatured(featuredList)}
- );
- }
-}
-
-Featured.displayName = 'Featured';
-Featured.propTypes = propTypes;
-
-export default Featured;
diff --git a/client/src/templates/News/Featured/featured.css b/client/src/templates/News/Featured/featured.css
deleted file mode 100644
index 9b00e36b29..0000000000
--- a/client/src/templates/News/Featured/featured.css
+++ /dev/null
@@ -1,33 +0,0 @@
-.featured-list {
- list-style: none;
- padding-left: 0;
- margin-top: 40px;
-}
-
-.featured-list-item {
- padding-bottom: 20px;
-}
-
-.featured-list-item .title {
- color: #333;
- padding-bottom: 20px;
-}
-
-.featured-list-item a {
- padding-top: 5px;
-}
-
-.featured-list-image {
- margin: 0 auto;
-}
-
-.featured-list-item a:hover,
-.featured-list-item a:focus {
- text-decoration: none;
- text-decoration-line: none;
- text-decoration-color: transparaent;
-}
-.featured-list-item a:hover > .meta-wrapper,
-.featured-list-item a:focus > .meta-wrapper {
- color: #006400;
-}
diff --git a/client/src/templates/News/Featured/index.js b/client/src/templates/News/Featured/index.js
deleted file mode 100644
index b9c878bbea..0000000000
--- a/client/src/templates/News/Featured/index.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from './Featured';
diff --git a/client/src/templates/News/NewsApp.js b/client/src/templates/News/NewsApp.js
deleted file mode 100644
index 2d8e1345d7..0000000000
--- a/client/src/templates/News/NewsApp.js
+++ /dev/null
@@ -1,62 +0,0 @@
-import React from 'react';
-import { Grid } from 'react-bootstrap';
-import Helmet from 'react-helmet';
-
-import { SlimWidthRow } from '../common/app/helperComponents';
-import Nav from './components/Nav';
-import { routes } from './routes';
-
-const propTypes = {};
-/* eslint-disable max-len */
-const styles = `
-.app-layout p,
-.app-layout li,
-.app-layout a,
-.app-layout span {
- font-size: 21.5px;
-}
-.app-layout hr {
- background-image: linear-gradient(to right, rgba(0, 100, 0, 0), rgba(0, 100, 0, 0.75), rgba(0, 100, 0, 0));
-}
-
-.app-layout p {
- paddin-top: 8px;
-}
-
- .app-layout h1, .app-layout h2, .app-layout h3, .app-layout h4, .app-layout h5, .app-layout h6
- {
- padding-top: 35px;
- padding-bottom: 0px;
- }
-
-.app-layout h1 {
- font-size: 42px;
-}
-
-.app-layout h2 {
- font-size: 34px;
-}
-
-.app-layout h3 {
- font-size: 32px;
-}
-`;
-/* eslint-enable max-len */
-function NewsApp() {
- return (
-
-
-
-
-
-
- {routes}
-
-
- );
-}
-
-NewsApp.displayName = 'NewsApp';
-NewsApp.propTypes = propTypes;
-
-export default NewsApp;
diff --git a/client/src/templates/News/NewsReferalLinkHandler/index.js b/client/src/templates/News/NewsReferalLinkHandler/index.js
deleted file mode 100644
index 166b6b614a..0000000000
--- a/client/src/templates/News/NewsReferalLinkHandler/index.js
+++ /dev/null
@@ -1,61 +0,0 @@
-import React, { Component } from 'react';
-import PropTypes from 'prop-types';
-import { navigate } from 'gatsby';
-import { bindActionCreators } from 'redux';
-import { connect } from 'react-redux';
-
-import Layout from '../../../components/layouts/Default';
-import { resolveShortId, dynamicArticleSelector } from '../redux';
-import { Loader } from '../../../components/helpers';
-
-const propTypes = {
- redirect: PropTypes.string,
- resolveShortId: PropTypes.func.isRequired,
- shortId: PropTypes.string.isRequired
-};
-
-const mapStateToProps = () => (state, props) => {
- const article = dynamicArticleSelector(state, props);
- return {
- redirect: article.redirect
- };
-};
-
-const mapDispatchToProps = dispatch =>
- bindActionCreators({ resolveShortId }, dispatch);
-
-class NewsReferalLinkHandler extends Component {
- componentDidMount() {
- const { shortId, redirect, resolveShortId } = this.props;
- if (!redirect) {
- return resolveShortId(shortId);
- }
- return navigate(redirect);
- }
-
- componentDidUpdate() {
- const { redirect } = this.props;
- if (redirect) {
- return navigate(redirect);
- }
- return null;
- }
-
- render() {
- return (
-
-
-
-
-
- );
- }
-}
-
-NewsReferalLinkHandler.displayName = 'NewsReferalLinkHandler';
-NewsReferalLinkHandler.propTypes = propTypes;
-
-export default connect(
- mapStateToProps,
- mapDispatchToProps
-)(NewsReferalLinkHandler);
diff --git a/client/src/templates/News/ShowArticle/components/Author.js b/client/src/templates/News/ShowArticle/components/Author.js
deleted file mode 100644
index 2f29db4673..0000000000
--- a/client/src/templates/News/ShowArticle/components/Author.js
+++ /dev/null
@@ -1,60 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import Helmet from 'react-helmet';
-
-import ArticleMeta from '../../components/ArticleMeta';
-
-const propTypes = {
- article: PropTypes.shape({
- author: PropTypes.objectOf(PropTypes.string)
- })
-};
-
-const styles = `
- .author-block {
- display: flex;
- align-items: center;
- justify-content: center;
- margin-top: 15px;
- }
-
- .author-block img {
- border-radius: 20%;
- }
-
- .author-bio {
- display: flex;
- flex-direction: column;
- margin-left: 30px;
- }
-
- .author-bio span {
- font-size: 16px;
- }
-
- .author-block {
- text-decoration: none;
- }
-`;
-
-function Author({ article }) {
- const {
- author: { avatar }
- } = article;
- return (
-
-
-
-
-

-
-
- );
-}
-
-Author.displayName = 'Author';
-Author.propTypes = propTypes;
-
-export default Author;
diff --git a/client/src/templates/News/ShowArticle/index.js b/client/src/templates/News/ShowArticle/index.js
deleted file mode 100644
index b31d7871d8..0000000000
--- a/client/src/templates/News/ShowArticle/index.js
+++ /dev/null
@@ -1,187 +0,0 @@
-import React, { Component, Fragment } from 'react';
-import PropTypes from 'prop-types';
-import Helmet from 'react-helmet';
-import { graphql } from 'gatsby';
-import Youtube from 'react-youtube';
-import { Image, Grid } from '@freecodecamp/react-bootstrap';
-
-import Layout from '../../../components/layouts/Default';
-import Author from './components/Author';
-import FullWidthRow from '../../../components/helpers/FullWidthRow';
-import Spacer from '../../../components/helpers/Spacer';
-import { postPopularityEvent } from '../../../utils/ajax';
-import { newsArticleNodePropTypes } from './proptypes';
-
-import './show-article.css';
-
-const propTypes = {
- data: PropTypes.shape({
- newsArticleNode: newsArticleNodePropTypes
- })
-};
-
-const youtubeOpts = {
- playerVars: {
- // https://developers.google.com/youtube/player_parameters
- autoplay: 0
- }
-};
-
-class ShowArticle extends Component {
- constructor(props) {
- super(props);
-
- this.state = {
- fetchState: {
- pending: false,
- complete: false,
- errored: false,
- error: null
- },
- currentArticle: {},
- requiredArticle: ''
- };
- }
-
- componentDidMount() {
- window.scrollTo(0, 0);
-
- const { shortId } = this.props.data.newsArticleNode;
- return postPopularityEvent({
- event: 'view',
- timestamp: Date.now(),
- shortId
- });
- }
-
- youtubeReady(event) {
- event.target.pauseVideo();
- }
-
- render() {
- const {
- data: {
- newsArticleNode: {
- title,
- renderableContent,
- youtubeId,
- featureImage,
- fields: { slug }
- },
- newsArticleNode
- }
- } = this.props;
-
- // RegEx finds the first paragraph and groups the content
- const description = renderableContent.join('').match(/(.*?)<\/p>/)[1];
- const pageTitle = `${title} | freeCodeCamp.org`;
- return (
-
-
- {pageTitle}
-
-
-
-
-
-
-
-
-
-
-
-
-
- {title}
-
- {featureImage ? (
-
-
-
-
- {featureImage.caption ? (
-
- ) : null}
-
-
-
- ) : null}
-
-
-
-
- {youtubeId ? (
-
-
-
-
-
-
- ) : null}
-
-
-
-
- );
- }
-}
-
-ShowArticle.displayName = 'ShowArticle';
-ShowArticle.propTypes = propTypes;
-
-export default ShowArticle;
-
-export const query = graphql`
- fragment newsArticleContent on NewsArticleNode {
- title
- renderableContent
- featureImage {
- src
- alt
- caption
- }
- fields {
- slug
- }
- author {
- name
- avatar
- twitter
- bio
- username
- }
- meta {
- readTime
- }
- firstPublishedDate
- shortId
- }
-
- query NewsArticleById($id: String!) {
- newsArticleNode(id: { eq: $id }) {
- ...newsArticleContent
- }
- }
-`;
diff --git a/client/src/templates/News/ShowArticle/proptypes.js b/client/src/templates/News/ShowArticle/proptypes.js
deleted file mode 100644
index 1d968664ff..0000000000
--- a/client/src/templates/News/ShowArticle/proptypes.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import PropTypes from 'prop-types';
-
-export const newsArticleNodePropTypes = PropTypes.shape({
- title: PropTypes.string,
- renderableContent: PropTypes.arrayOf(PropTypes.string),
- featureImage: PropTypes.shape({
- src: PropTypes.string,
- alt: PropTypes.string,
- caption: PropTypes.string
- }),
- fields: PropTypes.shape({
- slug: PropTypes.string
- }),
- author: PropTypes.shape({
- name: PropTypes.string,
- avatar: PropTypes.string,
- twitter: PropTypes.string,
- bio: PropTypes.string,
- username: PropTypes.string
- }),
- meta: PropTypes.shape({
- readTime: PropTypes.number
- }),
- firstPublishedDate: PropTypes.string,
- shortId: PropTypes.string
-});
diff --git a/client/src/templates/News/ShowArticle/show-article.css b/client/src/templates/News/ShowArticle/show-article.css
deleted file mode 100644
index 75761a65cb..0000000000
--- a/client/src/templates/News/ShowArticle/show-article.css
+++ /dev/null
@@ -1,34 +0,0 @@
-.show-article figure {
- display: flex;
- flex-direction: column;
- align-items: center;
-}
-
-.show-article figcaption > * {
- font-size: 16px;
-}
-
-.show-article figcaption {
- padding-top: 5px;
-}
-
-.show-article a {
- text-decoration: underline;
-}
-
-.feature-image-wrapper {
- padding-top: 32px;
-}
-.youtube-wrapper {
- position: relative;
- padding-bottom: 56.25%; /* 16:9 */
- padding-top: 25px;
- height: 0;
- overflow: hidden;
-}
-.youtube-wrapper iframe {
- position: absolute;
- left: 0;
- width: 100%;
- height: 95%;
-}
diff --git a/client/src/templates/News/components/ArticleMeta.js b/client/src/templates/News/components/ArticleMeta.js
deleted file mode 100644
index d016c41ecf..0000000000
--- a/client/src/templates/News/components/ArticleMeta.js
+++ /dev/null
@@ -1,90 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import Helmet from 'react-helmet';
-import differenceInMinutes from 'date-fns/difference_in_minutes';
-import differenceInHours from 'date-fns/difference_in_hours';
-import differenceInDays from 'date-fns/difference_in_calendar_days';
-import format from 'date-fns/format';
-import FontAwesomeIcon from '@fortawesome/react-fontawesome';
-import { faCalendarAlt, faClock } from '@fortawesome/free-regular-svg-icons';
-import { faFreeCodeCamp } from '@fortawesome/free-brands-svg-icons';
-
-const propTypes = {
- article: PropTypes.object
-};
-
-const styles = `
-
-.meta-wrapper {
- padding-top: 10px;
-}
-
-.meta-wrapper span,
-.meta-wrapper a {
- font-size: 16px;
-}
-
-.meta-item {
- margin-right: 20px;
-}
-
-`;
-
-function pluralise(singular, count) {
- return `${singular}${count === 1 ? '' : 's'}`;
-}
-
-function getTimeString(pubDate) {
- const now = new Date(Date.now());
- const minuteDiff = differenceInMinutes(now, pubDate);
-
- if (minuteDiff < 60) {
- return `${minuteDiff} ${pluralise('minute', minuteDiff)} ago`;
- }
- const hourDiff = differenceInHours(now, pubDate);
- if (hourDiff < 24) {
- return `${hourDiff} ${pluralise('hour', hourDiff)} ago`;
- }
- const dayDiff = differenceInDays(now, pubDate);
- if (dayDiff < 8) {
- return `${dayDiff} ${pluralise('day', dayDiff)} ago`;
- }
-
- if (dayDiff < 365) {
- return format(pubDate, 'MMM D');
- }
-
- return format(pubDate, 'MMM D YYYY');
-}
-
-function ArticleMeta({
- article: { viewCount, author, meta, firstPublishedDate }
-}) {
- return (
-
-
-
-
-
- By {author.name}
-
- {' '}
- {getTimeString(firstPublishedDate)}
-
-
- {`${meta.readTime} minute read`}
-
- {viewCount >= 100 && (
-
- {`${viewCount} views`}
-
- )}
-
-
- );
-}
-
-ArticleMeta.displayName = 'ArticleMeta';
-ArticleMeta.propTypes = propTypes;
-
-export default ArticleMeta;
diff --git a/client/src/templates/News/components/BannerWide.js b/client/src/templates/News/components/BannerWide.js
deleted file mode 100644
index 6dd9e1b168..0000000000
--- a/client/src/templates/News/components/BannerWide.js
+++ /dev/null
@@ -1,52 +0,0 @@
-import React from 'react';
-
-const propTypes = {};
-
-function BannerWide() {
- return (
-
- );
-}
-
-BannerWide.displayName = 'BannerWide';
-BannerWide.propTypes = propTypes;
-
-export default BannerWide;
diff --git a/client/src/templates/News/redux/index.js b/client/src/templates/News/redux/index.js
deleted file mode 100644
index 1de714d14c..0000000000
--- a/client/src/templates/News/redux/index.js
+++ /dev/null
@@ -1,67 +0,0 @@
-import { createAction, handleActions } from 'redux-actions';
-
-import { createTypes } from '../../../../utils/stateManagement';
-import { createAsyncTypes } from '../../../utils/createTypes';
-import { defaultFetchState } from '../../../redux';
-import { createShortIdSaga } from './shortId-saga';
-
-export const ns = 'news';
-const initialState = {
- resolveShortIdFetchState: { ...defaultFetchState },
- dynamicArticleByIdMap: {}
-};
-
-export const types = createTypes([...createAsyncTypes('resolveShortId')], ns);
-
-export const sagas = [...createShortIdSaga(types)];
-
-export const resolveShortId = createAction(types.resolveShortId);
-export const resolveShortIdComplete = createAction(
- types.resolveShortIdComplete,
- article => {
- const { slug } = article;
- article.redirect = slug;
- return article;
- }
-);
-export const resolveShortIdError = createAction(types.resolveShortIdError);
-
-export const resolveShortIdFetchStateSelector = state =>
- state[ns].resolveShortIdFetchState;
-export const dynamicArticleByIdMapSelector = state =>
- state[ns].dynamicArticleByIdMap;
-export const dynamicArticleSelector = (state, { shortId }) => {
- const map = dynamicArticleByIdMapSelector(state);
- return map[shortId] || {};
-};
-
-export const reducer = handleActions(
- {
- [types.resolveShortId]: state => ({
- ...state,
- resolveShortIdFetchState: { ...defaultFetchState }
- }),
- [types.resolveShortIdComplete]: (state, { payload }) => ({
- ...state,
- resolveShortIdFetchState: {
- ...defaultFetchState,
- pending: false,
- complete: true
- },
- dynamicArticleByIdMap: {
- ...state.dynamicArticleByIdMap,
- [payload.shortId]: payload
- }
- }),
- [types.resolveShortIdError]: (state, { payload: error }) => ({
- ...state,
- resolveShortIdFetchState: {
- ...defaultFetchState,
- pending: false,
- errored: true,
- error
- }
- })
- },
- initialState
-);
diff --git a/client/src/templates/News/redux/shortId-saga.js b/client/src/templates/News/redux/shortId-saga.js
deleted file mode 100644
index fe293f3068..0000000000
--- a/client/src/templates/News/redux/shortId-saga.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import { call, put, takeEvery } from 'redux-saga/effects';
-
-import { getArticleById } from '../../../utils/ajax';
-import { resolveShortIdComplete, resolveShortIdError } from './';
-import { handleAPIError, wrapHandledError } from '../../../utils/handled-error';
-
-function* fetchArticleByIdSaga({ payload }) {
- try {
- const { data } = yield call(getArticleById, payload);
- yield put(resolveShortIdComplete(data));
- } catch (e) {
- const { response: { status } = {} } = e;
- if (typeof status !== 'undefined') {
- const handledError = wrapHandledError(
- e,
- handleAPIError(e, { redirectTo: '/news' })
- );
- yield put(resolveShortIdError(handledError));
- return;
- }
- yield put(resolveShortIdError(e));
- }
-}
-
-export function createShortIdSaga(types) {
- return [takeEvery(types.resolveShortId, fetchArticleByIdSaga)];
-}
diff --git a/client/src/utils/index.js b/client/src/utils/index.js
index 84b6546c43..d9d2a7fa53 100644
--- a/client/src/utils/index.js
+++ b/client/src/utils/index.js
@@ -1,22 +1,6 @@
-import { findIndex } from 'lodash';
-
// These regex are not for validation, it is purely to see
// if we are looking at something like what we want to validate
// before we try to validate
export const maybeEmailRE = /.*@.*\.\w\w/;
export const maybeUrlRE = /https?:\/\/.*\..*/;
export const hasProtocolRE = /^http/;
-
-export const getShortIdFromSlug = (slug = '') => {
- const slugToArray = [...slug];
- const endOfUseableSlug = findIndex(
- slugToArray,
- char => char === '?' || char === '#'
- );
- let operableSlug = slug.slice(0);
- if (endOfUseableSlug !== -1) {
- operableSlug = slug.slice(0, endOfUseableSlug);
- }
- const [, maybeShortId = ''] = operableSlug.split('--');
- return maybeShortId.replace(/\/*$/, '');
-};
diff --git a/client/src/utils/utils.test.js b/client/src/utils/utils.test.js
index a63e70a792..0769858d1f 100644
--- a/client/src/utils/utils.test.js
+++ b/client/src/utils/utils.test.js
@@ -1,45 +1,9 @@
/* global describe it expect */
-import {
- slugWithId,
- slugWithIdAndHash,
- slugWithIdAndQuery,
- slugWithIdAndTrailingSlash,
- slugWithoutId,
- mockId
-} from '../__mocks__/news-article';
-
-import { getShortIdFromSlug } from './';
describe('client/src utilities', () => {
- describe('getShortIdFromSlug', () => {
- const emptyString = '';
- it('returns a string', () => {
- expect(typeof getShortIdFromSlug()).toEqual('string');
- });
-
- it('extracts the shortId when one is present', () => {
- const result = getShortIdFromSlug(slugWithId);
- expect(result).toEqual(mockId);
- });
-
- it('still returns a string when no id is found', () => {
- const result = getShortIdFromSlug(slugWithoutId);
- expect(result).toEqual(emptyString);
- });
-
- it('can handle query', () => {
- const result = getShortIdFromSlug(slugWithIdAndQuery);
- expect(result).toEqual(mockId);
- });
-
- it('can handle hash', () => {
- const result = getShortIdFromSlug(slugWithIdAndHash);
- expect(result).toEqual(mockId);
- });
-
- it('can handle trails slashes', () => {
- const result = getShortIdFromSlug(slugWithIdAndTrailingSlash);
- expect(result).toEqual(mockId);
+ describe('No tests for utils', () => {
+ it('No tests for utils', () => {
+ expect(true);
});
});
});
diff --git a/client/utils/gatsby/index.js b/client/utils/gatsby/index.js
index 60854efda6..410a359403 100644
--- a/client/utils/gatsby/index.js
+++ b/client/utils/gatsby/index.js
@@ -1,9 +1,7 @@
const challengePageCreators = require('./challengePageCreator');
const guidePageCreators = require('./guidePageCreator');
-const newsPageCreators = require('./newsPageCreator');
module.exports = {
...challengePageCreators,
- ...guidePageCreators,
- ...newsPageCreators
+ ...guidePageCreators
};
diff --git a/client/utils/gatsby/newsPageCreator.js b/client/utils/gatsby/newsPageCreator.js
deleted file mode 100644
index 1b8e15ac08..0000000000
--- a/client/utils/gatsby/newsPageCreator.js
+++ /dev/null
@@ -1,22 +0,0 @@
-const path = require('path');
-
-const newsArticle = path.resolve(
- __dirname, '../../src/templates/News/ShowArticle/index.js'
-);
-
-exports.createNewsArticle = createPage => ({
- node: {
- fields: { slug },
- shortId,
- id
- }
-}) =>
- createPage({
- path: slug,
- component: newsArticle,
- context: {
- slug,
- shortId,
- id
- }
- });
diff --git a/client/utils/news.js b/client/utils/news.js
deleted file mode 100644
index 1187f78e0f..0000000000
--- a/client/utils/news.js
+++ /dev/null
@@ -1,18 +0,0 @@
-exports.createArticleSlug = ({
- username = '',
- slugPart = '',
- shortId = ''
-} = {}) => {
- if (!username || !slugPart || !shortId) {
- throw new Error(`
- createArtcileSlug: One or more properties were missing, all are required
-
- {
- username: ${username},
- slugPart: ${slugPart},
- shortId: ${shortId}
- }
-`);
- }
- return `/news/${username}/${slugPart.concat('--', shortId)}`;
-};
diff --git a/client/utils/news.test.js b/client/utils/news.test.js
deleted file mode 100644
index 1d131fc91c..0000000000
--- a/client/utils/news.test.js
+++ /dev/null
@@ -1,32 +0,0 @@
-/* global describe it expect */
-import { mockArguments, slugWithId} from '../src/__mocks__/news-article';
-import { createArticleSlug } from './news';
-
-describe('news utils', () => {
- describe('createArticleSlug', () => {
-
- it('returns a string', () => {
- expect(typeof createArticleSlug(mockArguments)).toEqual('string');
- });
-
- it('throws when values are missing', () => {
- expect.assertions(3);
- /* eslint-disable no-undefined */
- expect(() =>
- createArticleSlug({ ...mockArguments, shortId: undefined })
- ).toThrow();
- expect(() =>
- createArticleSlug({ ...mockArguments, slugPart: undefined })
- ).toThrow();
- expect(() =>
- createArticleSlug({ ...mockArguments, username: undefined })
- ).toThrow();
- });
-
- it('creates a slug in the expected format', () => {
- const result = createArticleSlug(mockArguments);
-
- expect(result).toEqual(slugWithId);
- });
- });
-});
diff --git a/package.json b/package.json
index 9a3dd2ace5..d1913e90f8 100644
--- a/package.json
+++ b/package.json
@@ -11,7 +11,6 @@
"lint": "echo 'Warning: TODO - Define Linting with fixing.'",
"seed": "npm-run-all -p seed:*",
"seed:challenges": "cross-env DEBUG=fcc:* node ./tools/scripts/seed/seedChallenges",
- "seed:news": "cross-env DEBUG=fcc:* node ./tools/scripts/seed/seedNewsArticles",
"seed:auth-user": "cross-env DEBUG=fcc:* node ./tools/scripts/seed/seedAuthUser",
"start-develop": "node ./tools/scripts/start-develop.js",
"pretest": "npm-run-all -s test:lint",
diff --git a/tools/scripts/seed/seedNewsArticles.js b/tools/scripts/seed/seedNewsArticles.js
deleted file mode 100644
index 8d8760ae38..0000000000
--- a/tools/scripts/seed/seedNewsArticles.js
+++ /dev/null
@@ -1,126 +0,0 @@
-const path = require('path');
-require('dotenv').config({ path: path.resolve(__dirname, '../../../.env') });
-const MongoClient = require('mongodb').MongoClient;
-const faker = require('faker');
-const shortid = require('shortid');
-const slugg = require('slugg');
-const { homeLocation } = require('../../../config/env.json');
-const debug = require('debug');
-
-const log = debug('fcc:tools:seedNewsArticles');
-
-shortid.characters(
- '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$+'
-);
-
-const shortId = () => shortid.generate();
-
-const { MONGOHQ_URL, NODE_ENV: env } = process.env;
-
-function handleError(err, client) {
- if (err) {
- console.error('Oh noes!!');
- console.error(err);
- try {
- client.close();
- } catch (e) {
- // no-op
- } finally {
- /* eslint-disable-next-line no-process-exit */
- process.exit(1);
- }
- }
-}
-
-if (env !== 'production') {
- MongoClient.connect(
- MONGOHQ_URL,
- { useNewUrlParser: true },
- async function(err, client) {
- handleError(err, client);
-
- log('Connected successfully to mongo');
- const db = client.db('freecodecamp');
- const articleCollection = db.collection('article');
-
- const articles = stubArticles(200);
-
- await articleCollection
- .deleteMany({})
- .catch(err => handleError(err, client));
- return articleCollection
- .insertMany(articles)
- .then(({ insertedCount }) => {
- log('inserted %d new articles', insertedCount);
- client.close();
- })
- .catch(err => handleError(err, client));
- }
- );
-}
-
-function stubArticles(numberOfArticles = 1) {
- return new Array(numberOfArticles).fill('').map(() => generateArticle());
-}
-
-const sixMonths = 15780000000;
-
-function generateArticle() {
- const now = Date.now();
- const id = shortId();
- const title = faker.lorem.sentence();
- const paragraphs = faker.random.number(10) || 1;
- const arrayToLoopOver = new Array(paragraphs).fill('');
- const fakeDate = faker.date.between(new Date(now - sixMonths), new Date(now));
- const fakeDateMs = new Date(fakeDate).getTime();
- return {
- shortId: id,
- slugPart: slugg(title),
- title,
- author: {
- name: faker.name.findName(),
- avatar: faker.internet.avatar(),
- twitter: 'https://twitter.com/camperbot',
- bio: faker.lorem.sentence(),
- username: faker.internet.userName()
- },
- featureImage: {
- src: 'https://picsum.photos/2000/1300?random',
- alt: faker.lorem.sentence(),
- caption: paragraphs >= 5 ? faker.lorem.sentence() : ''
- },
- meta: {
- readTime: paragraphs,
- refLink: `${homeLocation}/n/${id}`
- },
- draft: 'this needs to be fixed',
- renderableContent: arrayToLoopOver.map(
- () => `${faker.lorem.paragraph()}
`
- ),
- published: true,
- featured: Math.random() < 0.6,
- underReview: false,
- viewCount: faker.random.number(90000),
- firstPublishedDate: fakeDate,
- createdDate: fakeDate,
- lastEditedDate: fakeDate,
- history: [
- {
- event: 'created',
- timestamp: fakeDateMs
- },
- {
- event: 'edited',
- timestamp: fakeDateMs
- },
- {
- event: 'publish',
- timestamp: fakeDateMs
- },
- {
- event: 'featured',
- timestamp: fakeDateMs
- }
- ]
- };
-}