diff --git a/app/build/plugins/videoEmbeds/bandcamp.js b/app/build/plugins/videoEmbeds/bandcamp.js
index c53cc56fe9c..24f64b6bcda 100644
--- a/app/build/plugins/videoEmbeds/bandcamp.js
+++ b/app/build/plugins/videoEmbeds/bandcamp.js
@@ -1,70 +1,47 @@
-var request = require("request");
-var cheerio = require("cheerio");
-var url = require("url");
+const fetch = require("node-fetch");
+const cheerio = require("cheerio");
+const { parse } = require("url");
-// we prepend a zero-width char because of a weird fucking
-// bug on mobile safari where if the embed is the first child,
-// the video player will not show. This causes issues with
-// inline elements displaying (adds extra space) solution needed
-// that doesn't disrupt page layout...
-function template(url, width, height) {
- return (
- '
'
- );
-}
+const ERROR_MESSAGE = "Could not retrieve song properties";
-var FAIL = "Could not retrieve song properties";
-
-module.exports = function (href, callback) {
- // Before loading anything, check that the path starts with
- // /album or /track
- var path, paths;
+module.exports = async function (href, callback) {
try {
- path = url.parse(href).pathname;
- } catch (e) {
- return callback(new Error(FAIL));
- }
-
- // Trim trailing slash if applicable
- if (path.slice(-1) === "/") path = path.slice(0, -1);
-
- paths = path.split("/");
-
- if (paths.length < 1) {
- return callback(new Error(FAIL));
- }
+ const { hostname, pathname } = parse(href);
+ const path = pathname.toLowerCase();
- var category = paths[1];
- if (category !== "track" && category !== "album") {
- return callback(new Error(FAIL));
- }
+ if (!hostname.endsWith("bandcamp.com")) {
+ return callback(new Error(ERROR_MESSAGE));
+ }
- request(href, function (error, response, body) {
- if (error) return callback(error);
+ if (!path || !path.match(/\/(album|track)/)) {
+ return callback(new Error(ERROR_MESSAGE));
+ }
- var $, height, width, html;
+ const res = await fetch(href);
+ const body = await res.text();
+ const $ = cheerio.load(body);
- try {
- $ = cheerio.load(body);
- width = Number($('meta[property="og:video:width"]').attr("content"));
- height = Number($('meta[property="og:video:height"]').attr("content"));
- html = $('meta[property="og:video"]').attr("content");
- } catch (error) {
- return callback(new Error(FAIL));
- }
+ const width = Number($('meta[property="og:video:width"]').attr("content"));
+ const height = Number(
+ $('meta[property="og:video:height"]').attr("content")
+ );
+ const html = $('meta[property="og:video"]').attr("content");
if (!html || isNaN(height) || isNaN(width)) {
- return callback(new Error(FAIL));
+ return callback(new Error(ERROR_MESSAGE));
}
- return callback(null, template(html, width, height));
- });
+ // we prepend a zero-width char because of a weird
+ // bug on mobile safari where if the embed is the first child,
+ // the video player will not show. This causes issues with
+ // inline elements displaying (adds extra space) solution needed
+ // that doesn't disrupt page layout...
+ const embedHTML = `
`;
+
+ callback(null, embedHTML);
+ } catch (error) {
+ callback(new Error(ERROR_MESSAGE));
+ }
};
diff --git a/app/build/plugins/videoEmbeds/tests.js b/app/build/plugins/videoEmbeds/tests.js
deleted file mode 100644
index 5aba7a8aada..00000000000
--- a/app/build/plugins/videoEmbeds/tests.js
+++ /dev/null
@@ -1,61 +0,0 @@
-describe("video-embed plugin", function () {
- var videoEmbed = require("./index");
- var cheerio = require("cheerio");
-
- function is(html, expected) {
- it("handles " + html.slice(0, 15), function (done) {
- var $ = cheerio.load(html, { decodeEntities: false });
-
- var callback = function (output) {
- expect($.html()).toEqual(expected);
- done();
- };
-
- videoEmbed.render($, callback);
- });
- }
-
- function link(url) {
- return '' + url + " ";
- }
-
- var wideVideo = "https://www.youtube.com/watch?v=YaT_5KoGh1Q";
- var exp =
- 'VIDEO
';
-
- // is("" + link(wideVideo) + "
", exp);
- // is(link(wideVideo), exp);
- // is(
- // "" + link(wideVideo) + "
",
- // 'VIDEO
'
- // );
- // is(
- // "Hello: " + link(wideVideo) + " bye...
",
- // 'Hello: bye...
VIDEO
'
- // );
-
- var vid2 = "https://www.youtube.com/watch?v=MJ62hh0a9U4";
- var vid2Alt = "http://youtube.com/watch?v=MJ62hh0a9U4";
-
- var exp2 =
- 'VIDEO
';
-
- // is('' + vid2 + " ", exp2);
- // is('' + vid2Alt + " ", exp2);
-
- var vimeoVid = "https://vimeo.com/87952436";
- var exp3 =
- '
';
-
- // is(link(vimeoVid), exp3);
-
- var bad1 = "http://foo.com";
- var bad2 = "https://www.youtube.com/watch?v=*(&*^%";
- var bad3 = "http://youtube.com/watch";
- var bad4 = "https://vimeo.com/^*%&^*(";
-
- // is(link(bad1), link(bad1));
- // is(link(bad2), link(bad2));
- // is(link(bad3), link(bad3));
- // is(link(bad4), link(bad4));
-});
diff --git a/app/build/plugins/videoEmbeds/tests/bandcamp.js b/app/build/plugins/videoEmbeds/tests/bandcamp.js
new file mode 100644
index 00000000000..3abdb043816
--- /dev/null
+++ b/app/build/plugins/videoEmbeds/tests/bandcamp.js
@@ -0,0 +1,52 @@
+describe("bandcamp embeds", function () {
+ const bandcamp = require("../bandcamp");
+
+ it("handles an empty href", function (done) {
+ const href = "";
+ bandcamp(href, (err, template) => {
+ expect(err.message).toEqual("Could not retrieve song properties");
+ expect(template).toEqual(undefined);
+ done();
+ });
+ });
+
+ it("handles an invalid href", function (done) {
+ const href = "https://bandcamp.com";
+ bandcamp(href, (err, template) => {
+ expect(err.message).toEqual("Could not retrieve song properties");
+ expect(template).toEqual(undefined);
+ done();
+ });
+ });
+
+ it("handles an invalid path", function (done) {
+ const href = "https://bandcamp.com/invalid";
+ bandcamp(href, (err, template) => {
+ expect(err.message).toEqual("Could not retrieve song properties");
+ expect(template).toEqual(undefined);
+ done();
+ });
+ });
+
+ it("handles a valid link to an album on a bandcamp subdomain", function (done) {
+ const href = "https://oliviachaney.bandcamp.com/album/circus-of-desire";
+ bandcamp(href, (err, template) => {
+ expect(err).toEqual(null);
+ expect(template).toEqual(
+ `
`
+ );
+ done();
+ });
+ });
+
+ it("handles a valid link to a track on a bandcamp subdomain", function (done) {
+ const href = "https://cloquet.bandcamp.com/track/new-drugs";
+ bandcamp(href, (err, template) => {
+ expect(err).toEqual(null);
+ expect(template).toEqual(
+ `
`
+ );
+ done();
+ });
+ });
+});
diff --git a/app/build/plugins/videoEmbeds/tests/index.js b/app/build/plugins/videoEmbeds/tests/index.js
new file mode 100644
index 00000000000..e273956cc4d
--- /dev/null
+++ b/app/build/plugins/videoEmbeds/tests/index.js
@@ -0,0 +1,20 @@
+describe("video-embed plugin", function () {
+ const videoEmbed = require("../index");
+ const cheerio = require("cheerio");
+
+ it("embeds videos from youtube, vimeo and music from bandcamp", function (done) {
+ const $ = cheerio.load(
+ `https://www.youtube.com/watch?v=MJ62hh0a9U4
+ https://vimeo.com/87952436
+ https://oliviachaney.bandcamp.com/album/circus-of-desire
+ https://cloquet.bandcamp.com/track/new-drugs
+ https://foo.com/87952436
+ `
+ );
+ videoEmbed.render($, function (err) {
+ expect(err).toEqual(null);
+ expect($("iframe").length).toEqual(4);
+ done();
+ });
+ });
+});
diff --git a/app/build/plugins/videoEmbeds/tests/vimeo.js b/app/build/plugins/videoEmbeds/tests/vimeo.js
new file mode 100644
index 00000000000..c916660443b
--- /dev/null
+++ b/app/build/plugins/videoEmbeds/tests/vimeo.js
@@ -0,0 +1,82 @@
+describe("vimeo embeds", function () {
+ const vimeo = require("../vimeo");
+ it("handles an empty href", function (done) {
+ const href = "";
+ vimeo(href, (err, template) => {
+ expect(err.message).toEqual("Could not retrieve video properties");
+ expect(template).toEqual(undefined);
+ done();
+ });
+ });
+
+ it("handles an invalid href", function (done) {
+ const href = "https://vimeo.com/^*%&^*(";
+ vimeo(href, (err, template) => {
+ expect(err.message).toEqual("Could not retrieve video properties");
+ expect(template).toEqual(undefined);
+ done();
+ });
+ });
+
+ it("handles an invalid host", function (done) {
+ const href = "https://viimeo.com/123";
+ vimeo(href, (err, template) => {
+ expect(err.message).toEqual("Could not retrieve video properties");
+ expect(template).toEqual(undefined);
+ done();
+ });
+ });
+
+ it("handles an invalid path", function (done) {
+ const href = "https://vimeo.com/invalid";
+ vimeo(href, (err, template) => {
+ expect(err.message).toEqual("Could not retrieve video properties");
+ expect(template).toEqual(undefined);
+ done();
+ });
+ });
+
+ it("handles a valid link", function (done) {
+ const href = "https://vimeo.com/87952436";
+ vimeo(href, (err, template) => {
+ expect(err).toEqual(null);
+ expect(template).toEqual(
+ `
`
+ );
+ done();
+ });
+ });
+
+ it("handles a valid link with a trailing slash", function (done) {
+ const href = "https://vimeo.com/87952436/";
+ vimeo(href, (err, template) => {
+ expect(err).toEqual(null);
+ expect(template).toEqual(
+ `
`
+ );
+ done();
+ });
+ });
+
+ it("handles a valid link with a query string", function (done) {
+ const href = "https://vimeo.com/87952436?query=string";
+ vimeo(href, (err, template) => {
+ expect(err).toEqual(null);
+ expect(template).toEqual(
+ `
`
+ );
+ done();
+ });
+ });
+
+ it("handles a valid link with a hash", function (done) {
+ const href = "https://vimeo.com/87952436#hash";
+ vimeo(href, (err, template) => {
+ expect(err).toEqual(null);
+ expect(template).toEqual(
+ `
`
+ );
+ done();
+ });
+ });
+});
diff --git a/app/build/plugins/videoEmbeds/tests/youtube.js b/app/build/plugins/videoEmbeds/tests/youtube.js
new file mode 100644
index 00000000000..70e8e11f6a3
--- /dev/null
+++ b/app/build/plugins/videoEmbeds/tests/youtube.js
@@ -0,0 +1,41 @@
+describe("youtube embeds", function () {
+ const youtube = require("../youtube");
+
+ it("handles an empty href", function (done) {
+ const href = "";
+ youtube(href, (err, template) => {
+ expect(err.message).toEqual("Could not parse youtube video");
+ expect(template).toEqual(undefined);
+ done();
+ });
+ });
+
+ it("handles an invalid href", function (done) {
+ const href = "https://www.youtube.com/watch?v=*(&*^%";
+ youtube(href, (err, template) => {
+ expect(err.message).toEqual("Could not parse youtube video");
+ expect(template).toEqual(undefined);
+ done();
+ });
+ });
+
+ it("handles an invalid host", function (done) {
+ const href = "https://www.youtubee.com/watch?v=123";
+ youtube(href, (err, template) => {
+ expect(err.message).toEqual("Could not parse youtube video");
+ expect(template).toEqual(undefined);
+ done();
+ });
+ });
+
+ it("handles a valid link", function (done) {
+ const href = "https://www.youtube.com/watch?v=YaT_5KoGh1Q";
+ youtube(href, (err, template) => {
+ expect(err).toEqual(null);
+ expect(template).toEqual(
+ `
`
+ );
+ done();
+ });
+ });
+});
diff --git a/app/build/plugins/videoEmbeds/vimeo.js b/app/build/plugins/videoEmbeds/vimeo.js
index 34d6a29f0c2..ac42730461e 100644
--- a/app/build/plugins/videoEmbeds/vimeo.js
+++ b/app/build/plugins/videoEmbeds/vimeo.js
@@ -1,63 +1,40 @@
-var request = require("request");
-var basename = require("path").basename;
-
-// we prepend a zero-width char because of a weird fucking
-// bug on mobile safari where if the embed is the first child,
-// the video player will not show. This causes issues with
-// inline elements displaying (adds extra space) solution needed
-// that doesn't disrupt page layout...
-function template(id, ratio, thumbnail) {
- return (
- '
'
- );
-}
-
-function apiURL(id) {
- return "https://vimeo.com/api/v2/video/" + id + ".json";
-}
+const fetch = require("node-fetch");
+const { parse } = require("url");
var FAIL = "Could not retrieve video properties";
-module.exports = function (href, callback) {
- var id, height, width, ratio, el, thumbnail;
-
+module.exports = async function (href, callback) {
try {
- // we trim because without it,
- // some text editors fuck up.
- id = basename(href).trim();
+ const { hostname, pathname } = parse(href);
+
+ if (!hostname || !hostname.match(/vimeo.com$/)) throw new Error(FAIL);
+
+ // parse the video id from the url, even if it has a trailing slash
+ const id = pathname.match(/\/(\d+)\/?$/)[1];
+
+ if (!id) throw new Error(FAIL);
+
+ const res = await fetch("https://vimeo.com/api/v2/video/" + id + ".json");
+ const body = await res.json();
+
+ const el = body[0];
+
+ if (!el || !el.width || !el.height) throw new Error(FAIL);
+
+ const thumbnail = el.thumbnail_large + ".jpg";
+ const height = el.height;
+ const width = el.width;
+ const ratio = (height / width) * 100;
+
+ // we prepend a zero-width char because of a weird fucking
+ // bug on mobile safari where if the embed is the first child,
+ // the video player will not show. This causes issues with
+ // inline elements displaying (adds extra space) solution needed
+ // that doesn't disrupt page layout...
+ const embedHTML = `
`;
+
+ return callback(null, embedHTML);
} catch (e) {
return callback(new Error(FAIL));
}
-
- // The request module has a known bug
- // which leaks memory and event emitters
- // during redirects. We cap the maximum
- // redirects to 5 to avoid encountering
- // errors when it creates 10+ emitters
- // for a URL with 10+ redirects...
- var options = {
- url: apiURL(id),
- json: true,
- maxRedirects: 5,
- };
-
- request(options, function (error, response, body) {
- if (error || !body) return callback(new Error(FAIL));
-
- el = body[0];
-
- if (!el || !el.width || !el.height) return callback(new Error(FAIL));
- thumbnail = el.thumbnail_large + ".jpg";
- height = el.height;
- width = el.width;
- ratio = (height / width) * 100;
-
- return callback(null, template(id, ratio, thumbnail));
- });
};
diff --git a/app/build/plugins/videoEmbeds/youtube.js b/app/build/plugins/videoEmbeds/youtube.js
index 808c374bda1..94d11dbcc58 100644
--- a/app/build/plugins/videoEmbeds/youtube.js
+++ b/app/build/plugins/videoEmbeds/youtube.js
@@ -1,93 +1,57 @@
-var request = require("request");
-var Url = require("url");
-var config = require("config");
-var cheerio = require("cheerio");
-
-var PLAYER_OPTIONS = "rel=0&wmode=transparent&rel=0&autohide=1&showinfo=0";
-
-// we prepend a zero-width char because of a bug on mobile safari
-// where if the embed is the first child,
-// the video player will not show.
-function template (id, ratio) {
- return (
- '
'
- );
-}
-
-function apiURL (id) {
- return (
- "https://www.googleapis.com/youtube/v3/videos?part=player&id=" +
- id +
- "&key=" +
- config.youtube.secret
- );
-}
-
-function fail () {
- return new Error("Could not parse youtube video");
-}
+const fetch = require("node-fetch");
+const { parse } = require("url");
+const config = require("config");
+const cheerio = require("cheerio");
+const querystring = require("querystring");
+const ERROR_MESSAGE = "Could not parse youtube video";
+
+module.exports = async function (href, callback) {
+ try {
+ const { query, hostname, pathname } = parse(href);
-function extractID (href) {
- var url = Url.parse(href, true);
- var id;
- if (url.host === "youtu.be") {
- id = url.pathname.slice(1);
- } else {
- id = url.query.v;
- }
+ if (!hostname || !hostname.match(/youtube.com$|youtu.be$/)) {
+ throw new Error(ERROR_MESSAGE);
+ }
- // Url.parse maps backslashes (used to escape) to forward
- // slashes, e.g. '/_' for some reason. We remove the forward
- // slash here, since it breaks video embeds for videos with
- // ids that contain escapable characters, e.g.
- // https://youtu.be/6orc\_lHvJKY
- id = id.split("/").join("");
+ // Url.parse maps backslashes (used to escape) to forward
+ // slashes, e.g. '/_' for some reason. We remove the forward
+ // slash here, since it breaks video embeds for videos with
+ // ids that contain escapable characters, e.g.
+ // https://youtu.be/6orc\_lHvJKY
+ const id =
+ hostname === "youtu.be"
+ ? pathname.slice(1).replace(/\\/g, "")
+ : querystring.parse(query).v;
- return id;
-}
+ if (!id) throw new Error(ERROR_MESSAGE);
-module.exports = function (href, callback) {
- var id, width, height, ratio, items, player;
+ // default ratio for youtube videos
+ let ratio = 56.25;
- try {
- id = extractID(href);
- } catch (e) {
- return callback(fail());
- }
-
- if (!id) return callback(fail());
+ try {
+ const res = await fetch(
+ "https://www.googleapis.com/youtube/v3/videos?part=player&id=" +
+ id +
+ "&key=" +
+ config.youtube.secret
+ );
- // The request module has a known bug
- // which leaks memory and event emitters
- // during redirects. We cap the maximum
- // redirects to 5 to avoid encountering
- // errors when it creates 10+ emitters
- // for a URL with 10+ redirects...
- var options = {
- url: apiURL(id),
- json: true,
- maxRedirects: 5
- };
+ const body = await res.json();
- request(options, function (error, response, body) {
- try {
var $ = cheerio.load(body.items[0].player.embedHtml);
- width = $("iframe").attr("width");
- height = $("iframe").attr("height");
+ const width = $("iframe").attr("width");
+ const height = $("iframe").attr("height");
ratio = (height / width) * 100;
- } catch (e) {
- // Fallback to default Youtube player ratio if API
- // request fails or shape of data returned changes
- ratio = 56.5;
- }
+ } catch (e) {}
+
+ // we prepend a zero-width char because of a bug on mobile safari
+ // where if the embed is the first child,
+ // the video player will not show.
+ const embedHTML = `
`;
- return callback(null, template(id, ratio));
- });
+ return callback(null, embedHTML);
+ } catch (e) {
+ return callback(new Error(ERROR_MESSAGE));
+ }
};
diff --git a/app/dashboard/account/add-new-site.js b/app/dashboard/account/add-new-site.js
index 93e7432cfa9..6de3d42e1b8 100644
--- a/app/dashboard/account/add-new-site.js
+++ b/app/dashboard/account/add-new-site.js
@@ -4,8 +4,7 @@ var Blog = require("models/blog");
var _ = require("lodash");
var prettyPrice = require("helper/prettyPrice");
var config = require("config");
-var request = require("request");
-var config = require("config");
+var fetch = require("node-fetch");
var stripe = require("stripe")(config.stripe.secret);
var User = require("models/user");
var Email = require("helper/email");
@@ -239,7 +238,11 @@ function saveBlog (req, res, next) {
}
// Begin SSL cert fetching process
- request(Blog.extend(blog).url, function () {});
+ // in the background
+ fetch(Blog.extend(blog).url)
+ .then(function () {})
+ .catch(function () {});
+
req.blog = blog;
next();
});
diff --git a/app/dashboard/import/sources/arena/posts.js b/app/dashboard/import/sources/arena/posts.js
index 41347d7a2bf..6b7dbd88f5d 100644
--- a/app/dashboard/import/sources/arena/posts.js
+++ b/app/dashboard/import/sources/arena/posts.js
@@ -1,42 +1,35 @@
-const request = require("request");
+const fetch = require("node-fetch");
const PAGE_SIZE = 100;
-module.exports = function posts({ slug, status }) {
- return new Promise((resolve, reject) => {
- var page = 0;
- var posts = [];
- var new_posts;
+module.exports = async function posts ({ slug, status }) {
+ let page = 0;
+ let posts = [];
+ let new_posts;
+ async function fetchPage (page) {
+ const url = base(slug, page);
status(`Fetching page ${page + 1} of channel`);
- request(base(slug, page), function with_page(err, body, res) {
- if (err) return reject(err);
-
- new_posts = JSON.parse(res).contents;
-
- posts = posts.concat(new_posts);
-
- if (!new_posts.length) {
- status(`Fetched everything on channel`);
- return resolve(posts);
- }
-
- page++;
-
- status(`Fetching page ${page + 1} of channel`);
- request(base(slug, page), with_page);
- });
- });
+ const response = await fetch(url);
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+ const data = await response.json();
+ return data.contents;
+ }
+
+ new_posts = await fetchPage(page);
+ posts = posts.concat(new_posts);
+ page++;
+ while (new_posts.length === PAGE_SIZE) {
+ new_posts = await fetchPage(page);
+ posts = posts.concat(new_posts);
+ page++;
+ }
+
+ status(`Fetched everything on channel`);
+ return posts;
};
-function base(slug, page) {
- return (
- "https://api.are.na/v2/channels/" +
- slug +
- "/contents?direction=desc&sort=position&per=" +
- PAGE_SIZE +
- "&channel_slug=" +
- slug +
- "&page=" +
- page
- );
+function base (slug, page) {
+ return `https://api.are.na/v2/channels/${slug}/contents?direction=desc&sort=position&per=${PAGE_SIZE}&channel_slug=${slug}&page=${page}`;
}
diff --git a/app/dashboard/import/sources/feed/load.js b/app/dashboard/import/sources/feed/load.js
index 06291f06b0f..bac693fd293 100644
--- a/app/dashboard/import/sources/feed/load.js
+++ b/app/dashboard/import/sources/feed/load.js
@@ -1,28 +1,19 @@
-var cheerio = require("cheerio");
-var request = require("request");
+const fetch = require("node-fetch");
+const cheerio = require("cheerio");
-module.exports = function load(feed_url, callback) {
- if (!callback) throw new Error("Please pass a callback");
+module.exports = async function load (feed_url) {
+ if (!feed_url) throw new Error("Please pass a URL to an RSS feed");
- if (!feed_url) return callback(new Error("Please pass a URL to an RSS feed"));
+ const response = await fetch(feed_url);
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+ const body = await response.text();
- request(feed_url, function (err, res, body) {
- if (err) return callback(err);
-
- var $ = cheerio.load(body, {
- // This prevent cheerio from replacing characters
- // it really ought to preserve.
- decodeEntities: false,
-
- // Enabling XML mode has confusing effects
- // 1. It makes it hard to read certain non-standard
- // tags that the evernote file contains, like
- // 2. It allows us to read the contents of the tags
- // without manually removing the CDATA tags. So be
- // careful if you remove this.
- xmlMode: true,
- });
-
- callback(null, $);
+ const $ = cheerio.load(body, {
+ decodeEntities: false,
+ xmlMode: true
});
+
+ return $;
};
diff --git a/app/dashboard/import/sources/pdr/extract_article.js b/app/dashboard/import/sources/pdr/extract_article.js
deleted file mode 100644
index 4a204334129..00000000000
--- a/app/dashboard/import/sources/pdr/extract_article.js
+++ /dev/null
@@ -1,33 +0,0 @@
-var readability = require("node-readability");
-var EventEmitter = require("events");
-var MyEmitter = new EventEmitter();
-
-module.exports = function (article_url, callback) {
- var has_responded = false;
- var content;
- var html;
- var title;
- var label = "done" + article_url;
-
- MyEmitter.on(label, function () {
- callback(null, title, content, html);
- });
-
- // This seems to swallow errors for whole process?
- // WTF!
-
- readability(article_url, function (err, article) {
- if (has_responded) return;
-
- has_responded = true;
-
- if (err) return callback(err);
-
- content = article.content.slice();
- html = article.cache.body.slice();
- title = article.title.slice();
-
- MyEmitter.emit(label);
- article.close();
- });
-};
diff --git a/app/dashboard/import/sources/pdr/extract_author.js b/app/dashboard/import/sources/pdr/extract_author.js
deleted file mode 100644
index e1b00b123e8..00000000000
--- a/app/dashboard/import/sources/pdr/extract_author.js
+++ /dev/null
@@ -1,47 +0,0 @@
-module.exports = function ($) {
- console.log($.html());
-
- var candidates = [];
- var best_guess;
-
- function calculate_score(el) {
- var score = 0;
-
- var text = $(el).text();
- var number_of_words = text.split(" ").length;
- var has_numbers = text.match(/\d+/);
- var next_node_starts_with_is =
- el.next &&
- el.next.type === "text" &&
- el.next.data.trim().toLowerCase().indexOf("is") === 0;
-
- // console.log(text, {next_node_starts_with_is: next_node_starts_with_is, has_numbers: has_numbers, number_of_words: number_of_words});
- if (!el.prev) score++;
- if (number_of_words === 2) score++;
- if (next_node_starts_with_is) score++;
- if (number_of_words > 5) score--;
- if (has_numbers) score--;
-
- return score;
- }
-
- $("hr + p strong")
- .last()
- .add($("hr + p span strong").last())
- .add($("p span strong").last())
- .add($("p em"))
- .add($("p strong"))
- .each(function (i, el) {
- candidates.push({ text: $(el).text(), score: calculate_score(el) });
- });
-
- console.log(candidates);
-
- best_guess = candidates.reduce(function (sum, value) {
- return sum.score > value.score ? sum : value;
- }, candidates[0]);
-
- console.log("BEST GUESS", best_guess.text);
-
- return best_guess.text;
-};
diff --git a/app/dashboard/import/sources/pdr/extract_summary.js b/app/dashboard/import/sources/pdr/extract_summary.js
deleted file mode 100644
index ee11e639c17..00000000000
--- a/app/dashboard/import/sources/pdr/extract_summary.js
+++ /dev/null
@@ -1,3 +0,0 @@
-module.exports = function ($) {
- return $("p").first().text().trim();
-};
diff --git a/app/dashboard/import/sources/pdr/extract_tags.js b/app/dashboard/import/sources/pdr/extract_tags.js
deleted file mode 100644
index f6778283ba9..00000000000
--- a/app/dashboard/import/sources/pdr/extract_tags.js
+++ /dev/null
@@ -1,31 +0,0 @@
-var cheerio = require("cheerio");
-
-module.exports = function (html) {
- var $ = cheerio.load(html, { decodeEntities: false });
- var class_names = $(".hpy_single_article article").first().attr("class");
-
- var tags = class_names
- .split(" ")
- .filter(function (name) {
- name = name.trim().toLowerCase();
-
- return (
- name &&
- name.indexOf("category-") === 0 &&
- name.indexOf("featured") === -1 &&
- name.indexOf("article") === -1
- );
- })
- .map(function (name) {
- name = name.trim().toLowerCase().slice("category-".length);
- name = name.split("-").join(" ");
- name = name[0].toUpperCase() + name.slice(1);
-
- if (name === "Science medicine") name = "Science";
- if (name === "Art and illustrations") name = "Art";
-
- return name;
- });
-
- return tags;
-};
diff --git a/app/dashboard/import/sources/pdr/find_thumbnail.js b/app/dashboard/import/sources/pdr/find_thumbnail.js
deleted file mode 100644
index 5880632ebd2..00000000000
--- a/app/dashboard/import/sources/pdr/find_thumbnail.js
+++ /dev/null
@@ -1,28 +0,0 @@
-var thumbnails = require("fs-extra")
- .readFileSync(__dirname + "/thumbnails.txt", "utf-8")
- .trim()
- .split("\n");
-
-module.exports = function ($) {
- var thumbnail, src;
-
- // Fix bare URLs in footnotes
- $("img").each(function (i, el) {
- src = $(el).attr("src");
-
- if (thumbnails.indexOf(src) > -1 && !!thumbnail) {
- console.log(thumbnail);
- console.log(src);
- throw new Error(
- "Two valid thumbnails for a given entry, remove one of them"
- );
- }
-
- if (thumbnails.indexOf(src) > -1 && !thumbnail) {
- thumbnail = src;
- console.log("FOUND A THUMBNAIl", thumbnail);
- }
- });
-
- return thumbnail;
-};
diff --git a/app/dashboard/import/sources/pdr/fix_azon.js b/app/dashboard/import/sources/pdr/fix_azon.js
deleted file mode 100644
index b939eaf288c..00000000000
--- a/app/dashboard/import/sources/pdr/fix_azon.js
+++ /dev/null
@@ -1,58 +0,0 @@
-module.exports = function ($) {
- $("p").each(function (i, el) {
- if ($(el).text().indexOf("Discover more recommended books") > -1)
- $(el).remove();
- if ($(el).text().indexOf("[easyazon_link") > -1) $(el).remove();
- });
-
- $(".bookinfo").each(function (i, el) {
- var text = "";
-
- // Remove empty p tags
- $(el)
- .find("p")
- .each(function (i, el) {
- if (!$(el).html().trim()) $(el).remove();
- });
-
- $(el)
- .find("span")
- .each(function (i, el) {
- text += $(el).text();
-
- $(el).remove();
- });
-
- text += $(el).find(".bookauthor").first().text();
-
- $(el).find(".bookauthor").remove();
-
- $(el).prepend("" + text + "
");
- });
-
- $("a").each(function (i, el) {
- $(el)
- .contents()
- .each(function fix(i, el) {
- if (el.type !== "text") return $(el).contents().each(fix);
-
- var text = el.data;
-
- // [easyazon_link identifier=“191001009X” locale=“US” tag=“thepubdomrev-20”]
- if (text.indexOf("[easyazon_link") === -1) return;
-
- console.log("BEFORE", text);
-
- var start = text.indexOf("[easyazon_link");
- var end = text.slice(start).indexOf("]") + start + 1;
-
- console.log(start, end);
-
- text = text.slice(0, start) + text.slice(end);
-
- console.log("AFTER", text);
-
- el.data = text;
- });
- });
-};
diff --git a/app/dashboard/import/sources/pdr/fix_broken_images.js b/app/dashboard/import/sources/pdr/fix_broken_images.js
deleted file mode 100644
index d99b56acbf2..00000000000
--- a/app/dashboard/import/sources/pdr/fix_broken_images.js
+++ /dev/null
@@ -1,13 +0,0 @@
-module.exports = function ($) {
- $("img").each(function (i, el) {
- var html = $.html(el);
-
- if (html.indexOf("=") === -1) return;
-
- var new_el = $(" ");
-
- for (var x in el.attribs) if (x !== '"') new_el.attr(x, el.attribs[x]);
-
- $(el).replaceWith(new_el);
- });
-};
diff --git a/app/dashboard/import/sources/pdr/fix_empty_public_domain_works.js b/app/dashboard/import/sources/pdr/fix_empty_public_domain_works.js
deleted file mode 100644
index 7db6eda79cd..00000000000
--- a/app/dashboard/import/sources/pdr/fix_empty_public_domain_works.js
+++ /dev/null
@@ -1,43 +0,0 @@
-module.exports = function ($) {
- // This was a specific issue with
- // https://publicdomainreview.org/2017/05/31/gustav-wunderwalds-paintings-of-weimar-berlin/
- // and produced markdown that pandoc couldn't parse
- $("p strong br").remove();
-
- var has_upper_case = false;
- var has_lower_case = false;
-
- $("p").each(function (i, el) {
- if ($(el).text() === "PUBLIC DOMAIN WORKS") has_upper_case = true;
-
- if ($(el).text().toLowerCase() === "public domain works" && !has_upper_case)
- has_lower_case = true;
- });
-
- if (has_upper_case && has_upper_case) {
- $("p").each(function (i, el) {
- if ($(el).text() === "PUBLIC DOMAIN WORKS") $(el).remove();
- });
- }
-
- // This papers over a bug with readability which clipped
- // the last list in the article.
- $("p").each(function (i, el) {
- var text = $(el).text();
-
- if (text !== "Public Domain Works") return;
-
- var next_text = "";
-
- $(el)
- .nextAll()
- .each(function (i, el) {
- next_text += $(el).text().trim();
- });
-
- if (!next_text) {
- $(el).prevUntil("hr").prev().remove();
- $(el).remove();
- }
- });
-};
diff --git a/app/dashboard/import/sources/pdr/index.js b/app/dashboard/import/sources/pdr/index.js
deleted file mode 100644
index f85d56c0cbe..00000000000
--- a/app/dashboard/import/sources/pdr/index.js
+++ /dev/null
@@ -1,31 +0,0 @@
-var load = require("./load");
-var parse = require("./parse");
-var fs = require("fs-extra");
-
-if (require.main === module)
- main(process.argv[2], function (err) {
- if (err) throw err;
-
- process.exit();
- });
-
-function main(output_directory, callback) {
- if (!callback) throw new Error("Please pass a callback");
-
- if (output_directory)
- return callback(
- new Error("Please pass an output directory as the second argument")
- );
-
- load(function (err, blog) {
- if (err) return callback(err);
-
- fs.emptyDir(output_directory, function (err) {
- if (err) return callback(err);
-
- parse(output_directory, blog, callback);
- });
- });
-}
-
-module.exports = main;
diff --git a/app/dashboard/import/sources/pdr/insert_disclaimer.js b/app/dashboard/import/sources/pdr/insert_disclaimer.js
deleted file mode 100644
index 6127a2a8769..00000000000
--- a/app/dashboard/import/sources/pdr/insert_disclaimer.js
+++ /dev/null
@@ -1,6 +0,0 @@
-module.exports = function (text) {
- return (
- "{|<} *This essay was originally published in [The Public Domain Review](http://publicdomainreview.org/) under a Creative Commons License. Please see [their rules for reuse](http://publicdomainreview.org/legal/).*\n\n" +
- text
- );
-};
diff --git a/app/dashboard/import/sources/pdr/load.js b/app/dashboard/import/sources/pdr/load.js
deleted file mode 100644
index 2a5463416cd..00000000000
--- a/app/dashboard/import/sources/pdr/load.js
+++ /dev/null
@@ -1,103 +0,0 @@
-var cheerio = require("cheerio");
-var request = require("request");
-var fs = require("fs-extra");
-var extract_article = require("./extract_article");
-var for_each = require("dashboard/importer/helper").for_each;
-
-if (require.main === module) {
- var output_file = process.argv[2];
-
- if (!output_file)
- throw new Error("Please pass filename to write links to as first argument");
-
- main(function (err, blog) {
- if (err) throw err;
-
- fs.outputJson(output_file, blog, { spaces: 2 }, function (err) {
- if (err) throw err;
-
- process.exit();
- });
- });
-}
-
-function main(callback) {
- var page_no = 1;
-
- // For some reason these show on the homepage but not the essay page
- // so we hard code them here for now...
- var articles = [
- "http://publicdomainreview.org/2018/04/04/fallen-angels-birds-of-paradise-in-early-modern-europe/",
- "http://publicdomainreview.org/2018/04/18/made-in-taiwan-how-a-frenchman-fooled-18th-century-london/",
- ];
-
- var base_url = "http://publicdomainreview.org/essays/page/";
-
- console.log("Retrieving articles...");
-
- request(base_url + page_no + "/", function then(err, res, body) {
- if (err) return callback(err);
-
- var has_more = false;
- var $ = cheerio.load(body, {
- // This prevent cheerio from replacing characters
- // it really ought to preserve.
- decodeEntities: false,
-
- // Enabling XML mode has confusing effects
- // 1. It makes it hard to read certain non-standard
- // tags that the evernote file contains, like
- // 2. It allows us to read the contents of the tags
- // without manually removing the CDATA tags. So be
- // careful if you remove this.
- // xmlMode: true
- });
-
- $("article").each(function (i, el) {
- articles.push($(el).find("a").first().attr("href"));
- });
-
- console.log("... Found", articles.length, "articles...");
-
- has_more = $(".link-last a").text().trim() === "Next »";
-
- if (has_more) return request(base_url + ++page_no + "/", then);
-
- console.log("Fetching article content...");
-
- var blog = {
- title: "Public Domain Review",
- host: "publicdomainreview.org",
- posts: [],
- };
-
- var called = 0;
- var total = articles.length;
-
- for_each.multi(5)(
- articles,
- function (article_url, next) {
- console.log("...", ++called, "/", total, article_url);
-
- extract_article(article_url, function (err, title, content, html) {
- // third arg: meta
-
- blog.posts.push({
- title: title,
- content: content,
- html: html,
- url: article_url,
- });
-
- next();
- });
- },
- function () {
- console.log("Done!");
- callback(null, blog);
- }
- );
- });
-}
-
-module.exports = main;
diff --git a/app/dashboard/import/sources/pdr/package.json b/app/dashboard/import/sources/pdr/package.json
deleted file mode 100644
index d9a284c5eb9..00000000000
--- a/app/dashboard/import/sources/pdr/package.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "name": "pdr",
- "version": "1.0.0",
- "main": "index.js",
- "license": "CC0",
- "dependencies": {
- "cheerio": "^1.0.0-rc.2",
- "fs-extra": "^5.0.0",
- "node-readability": "^3.0.0",
- "pretty": "^2.0.0",
- "request": "^2.85.0"
- }
-}
diff --git a/app/dashboard/import/sources/pdr/parse.js b/app/dashboard/import/sources/pdr/parse.js
deleted file mode 100644
index 8fa887dd596..00000000000
--- a/app/dashboard/import/sources/pdr/parse.js
+++ /dev/null
@@ -1,147 +0,0 @@
-var fs = require("fs-extra");
-var cheerio = require("cheerio");
-var helper = require("dashboard/importer/helper");
-
-var insert_video_embeds = helper.insert_video_embeds;
-var determine_path = helper.determine_path;
-var download_images = helper.download_images;
-var insert_metadata = helper.insert_metadata;
-var to_markdown = helper.to_markdown;
-var for_each = helper.for_each;
-
-var extract_tags = require("./extract_tags");
-var extract_summary = require("./extract_summary");
-var find_thumbnail = require("./find_thumbnail");
-var insert_disclaimer = require("./insert_disclaimer");
-var tidy_figures = require("./tidy_figures");
-var fix_azon = require("./fix_azon");
-var fix_empty_public_domain_works = require("./fix_empty_public_domain_works");
-var fix_broken_images = require("./fix_broken_images");
-var tidy_footnotes = require("./tidy_footnotes");
-var relative_links = require("./relative_links");
-
-function main(output_directory, blog, callback) {
- var done = 0;
-
- for_each(
- blog.posts,
- function (post, next) {
- // console.log(post.title, post.url);
-
- var created, updated;
- var dateStamp, tags, draft, page, metadata, summary;
- var $, content, title, html, url;
-
- content = post.content;
- title = post.title;
- html = post.html;
- url = post.url;
-
- var date_string = url.split("/").slice(3, 6).join("/");
-
- created = updated = dateStamp = new Date(date_string).valueOf();
- draft = page = false;
- metadata = {};
- tags = extract_tags(html);
-
- content = insert_video_embeds(content);
-
- $ = cheerio.load(content, { decodeEntities: false });
-
- // author = extract_author($);
- // metadata.author = author || 'Adam Green';
-
- tidy_figures($);
- tidy_footnotes($);
- fix_azon($);
- fix_empty_public_domain_works($);
- fix_broken_images($);
- relative_links($, url);
-
- summary = extract_summary($);
- content = $.html();
-
- post = {
- draft: false,
- page: false,
-
- // We don't know any of these properties
- // as far as I can tell.
- name: "",
- permalink: "",
- summary: summary,
- html: content,
- title: title,
-
- dateStamp: dateStamp,
- created: created,
- updated: updated,
- tags: tags,
- metadata: metadata,
-
- // Clean up the contents of the
- // tag. Evernote has quite a lot of cruft.
- // Then convert into Markdown!
- content: content,
- };
-
- post = determine_path(post);
-
- download_images(post, function (err, post) {
- if (err) throw err;
-
- $ = cheerio.load(post.html, { decodeEntities: false });
-
- if (find_thumbnail($)) metadata.thumbnail = find_thumbnail($);
-
- post.content = to_markdown(post.html);
- post.content = insert_disclaimer(post.content);
-
- post = insert_metadata(post);
-
- console.log(++done + "/" + blog.posts.length, "...", post.path);
- fs.outputFile(post.path, post.content, function (err) {
- if (err) return callback(err);
-
- next();
- });
- });
- },
- function () {
- callback(null, blog);
- }
- );
-}
-
-if (require.main === module) {
- var input_file = process.argv[2];
- var output_directory = process.argv[3];
- var filter = process.argv[4];
-
- if (!input_file)
- throw new Error("Please pass filename to read links to as first argument");
- if (!output_directory)
- throw new Error("Please pass output directory as second argument");
-
- var blog = fs.readJsonSync(input_file);
-
- // console.log('!!!!! generating trimmed version of site');
- // blog.posts = blog.posts.slice(0, 100);
-
- if (filter)
- blog.posts = blog.posts.filter(function (post) {
- return post.url.trim().toLowerCase().indexOf(filter) > -1;
- });
-
- fs.emptyDir(output_directory, function (err) {
- if (err) throw err;
-
- main(output_directory, blog, function (err) {
- if (err) throw err;
-
- console.log("Complete!");
- });
- });
-}
-
-module.exports = main;
diff --git a/app/dashboard/import/sources/pdr/relative_links.js b/app/dashboard/import/sources/pdr/relative_links.js
deleted file mode 100644
index 56d61c2968e..00000000000
--- a/app/dashboard/import/sources/pdr/relative_links.js
+++ /dev/null
@@ -1,9 +0,0 @@
-module.exports = function ($, url) {
- $("a").each(function (i, el) {
- var href = $(el).attr("href");
-
- if (href && href.indexOf(url) === 0) {
- $(el).attr("href", href.slice(url.length));
- }
- });
-};
diff --git a/app/dashboard/import/sources/pdr/sources.json b/app/dashboard/import/sources/pdr/sources.json
deleted file mode 100644
index 4ee25105f60..00000000000
--- a/app/dashboard/import/sources/pdr/sources.json
+++ /dev/null
@@ -1,156 +0,0 @@
-{
- "www.loc.gov": "Library of Congress",
- "docnum.u-strasbg.fr": "L\"Université de Strasbourg",
- "commons.wikimedia.org": "Wikimedia Commons",
- "wellcomecollection.org": "Wellcome Library",
- "www.biodiversitylibrary.org": "Biodiversity Library",
- "archive.org": "Internet Archive",
- "www.wdl.org": "World Digital Library Home",
- "daten.digitale-sammlungen.de": "",
- "johannes.library.manchester.ac.uk:8181": "Manchester City Library",
- "library.princeton.edu": "Princeton University Library",
- "www.metmuseum.org": "The Metropolitan Museum of Art",
- "newberrylibrary.tumblr.com": "The Newberry",
- "digitallibrary.tulane.edu": "Tulane University Digital Library",
- "gallica.bnf.fr": "Gallica",
- "images.bnf.fr": "Consultation de la base des clichés Daguerre",
- "books.google.ca": "Google Books",
- "digitalcollections.nypl.org": "NYPL Digital Collections",
- "www.bl.uk": "The British Library",
- "babel.hathitrust.org": "HathiTrust Digital Library",
- "whitmanarchive.org": "The Walt Whitman Archive",
- "bivaldi.gva.es": "GVA",
- "wellcomeimages.org": "Wellcome Library",
- "www.deutsche-digitale-bibliothek.de": "Deutsche Digitale Bibliothek",
- "www.nlm.nih.gov": "National Library of Medicine",
- "www.kunstkopie.de": "Kunstkopie",
- "www.liburuklik.euskadi.eus": "Liburuklik",
- "collections.nlm.nih.gov": "National Library of Medicine",
- "www.nga.gov": "National Gallery of Art",
- "digital.nls.uk": "National Library of Scotland",
- "brbl-dl.library.yale.edu": "Yale",
- "www.flickr.com": "Flickr",
- "blogs.harvard.edu": "Harvard",
- "ariyamagga.net": "Ariyamagga",
- "sites.nd.edu": "Notre Dame",
- "collections.britishart.yale.edu": "Yale",
- "en.wikipedia.org": "Wikipedia",
- "www.rijksmuseum.nl": "Rijksmuseum",
- "www.insidecdcr.ca.gov": "California Department of Corrections and Rehabilitation",
- "catalogue.nli.ie": "National Library of Ireland",
- "www.christies.com": " Christie's",
- "grandmasgraphics.com": "Grandma's Graphics",
- "www.oughterardheritage.org": "Oughterard Heritage",
- "fineartamerica.com": "Fine Art America",
- "50watts.com": "50 Watts",
- "art.thewalters.org": "The Walters Art Museum",
- "garfield.jtsa.edu:1801": "JTSA",
- "www.britishmuseum.org": "British Museum",
- "collections.lacma.org": "LACMA",
- "www.youtube.com": "YouTube",
- "earlyamericanists.com": "The Junto",
- "digi.ub.uni-heidelberg.de": "UB Heidelberg",
- "www.academia.edu": "Academia.edu",
- "www.victorianlondon.org": "The Dictionary of Victorian London",
- "blogs.ucl.ac.uk": "UCL",
- "sweetgum.nybg.org": "NYBG",
- "biodiversitylibrary.org": "Biodiversity Heritage Library",
- "dc.lib.unc.edu": "UNC Chapel Hill Libraries",
- "4.bp.blogspot.com": "Blogpost",
- "www.blumenbach-online.de": "Blumenbach",
- "thedabbler.co.uk": "The Dabbler",
- "spitalfieldslife.com": "Spitalfields",
- "lhldigital.lindahall.org": "LHL Digital",
- "parisolympiapress.com": "Paris Olympia Press",
- "www.mfa.org": "Boston Museum of Fine Arts",
- "bildsuche.digitale-sammlungen.de": "Bildähnlichkeitssuche",
- "caliban.mpipz.mpg.de": "Kurt Stüber",
- "digital.zbmed.de": "ZB MED",
- "www.deutschestextarchiv.de": "Deutsches Textarchiv",
- "www.csdl.tamu.edu:8080": "TAMU",
- "exhibitions.nypl.org": "The New York Public Library",
- "www.qbi2005.com": "QBI Slots",
- "www.elfindog.sakura.ne.jp": "Sakura",
- "www.getty.edu": "The Getty",
- "stuff.mit.edu": "MIT",
- "greekmythology.wikia.com": "Greek Mythology Wiki",
- "www.wga.hu": "Web Gallery of Art",
- "www.lib.unimelb.edu.au": "UNIMELB",
- "www.the-athenaeum.org": "The Athenaeum",
- "www.dnalc.org": "DNA Learning Center",
- "www.digitalcommonwealth.org": "Digital Commonwealth",
- "postalmuseum.si.edu": "Postal Museum",
- "streetsofsalem.files.wordpress.com": "SOS",
- "www.nyu.edu": "NYU",
- "www.archive.org": "Internet Archive",
- "www.artic.edu": "The Art Institute of Chicago",
- "www.unesco-ci.org": "Unesco Ci",
- "wellcomelibrary.org": "Wellcome Library",
- "luna.folger.edu": "Folger Digital Image Collection",
- "florencegriswoldmuseum.org": "Florence Griswold Museum",
- "thecanadasite.com": "The Canada Site",
- "digital.lib.uh.edu": "University of Houston",
- "www.dreweatts.com": "Dreweatts",
- "www.gutenberg.org": "Gutenberg",
- "hrc.contentdm.oclc.org": "CONTENTdm",
- "jv.gilead.org.il": "Zvi Har’El",
- "airandspace.si.edu": "National Air and Space Museum |",
- "imaginaryinstruments.org": "Museum of Imaginary Musical Instruments",
- "jaredandkyal.files.wordpress.com": "jaredandkyal",
- "digital.ub.uni-duesseldorf.de": "ULB Düsseldorf",
- "ebooks.adelaide.edu.au": "Adelaide",
- "images.library.yale.edu": "Yale",
- "unruly18thcentury.blogspot.co.uk": "Unruly Eighteenth-Century Britain",
- "s-media-cache-ak0.pinimg.com": "PINIMG",
- "www.altomagazine.com": "Elite Traveler",
- "www.pinterest.com": "Pinterest",
- "www.tate.org.uk": "Tate",
- "jcb.lunaimaging.com": "JCB",
- "www.bne.es": "Biblioteca Nacional",
- "circulatingnow.nlm.nih.gov": "NLM",
- "books.google.co.uk": "Google Books",
- "museumofthemind.org.uk": "Bethlem Museum of the Mind",
- "www.stltoday.com": "St. Louis website",
- "www.google.com": "Google",
- "web.stanford.edu": "Stanford University",
- "www.themorgan.org": "The Morgan Library & Museum",
- "www.armitt.com": "ARMITT",
- "bibliodyssey.blogspot.de": "BibliOdyssey",
- "www.vam.ac.uk": "V&A",
- "blog.etsy.com": "Etsy",
- "www.berfrois.com": "Berfrois",
- "publicdomainreview.org": "The Public Domain Review",
- "kimberlyevemusings.blogspot.de": "Victorian Musings",
- "www.amdigital.co.uk": "Adam Matthew Digital",
- "www.nasa.gov": "NASA",
- "memory.loc.gov": "American Memory: Remaining Collections",
- "hdl.handle.net": "Handle Proxy",
- "upload.wikimedia.org": "Wikimedia Commons",
- "theibtaurisblog.com": "The I.B.Tauris Blog",
- "museejjrousseau.montmorency.fr": "Musée Jean-Jacques Rousseau de Montmorency",
- "www.amazon.com": "Amazon",
- "www.oldlongisland.com": "Old Long Island",
- "www.jssgallery.org": "John Singer Sargent Virtual Gallery",
- "www.uni-salzburg.at": "Salzburg Uni",
- "www.pirates-corsaires.com": "Pirates & Corsaires",
- "farm8.staticflickr.com": "Flickr",
- "collections.countway.harvard.edu": "Harvard",
- "diglib.hab.de": "Wolfenbütteler Digitale Bibliothek",
- "echo.mpiwg-berlin.mpg.de": "ECHO",
- "www.americanantiquarian.org": "American Antiquarian Society",
- "www.wormfood.com": "Amy Stewart",
- "play.google.com": "Google Play",
- "pressandpolicy.bl.uk": "The British Library",
- "farm9.staticflickr.com": "Flickr",
- "www.chemheritage.org": "Science History Institute",
- "www.wikipaintings.org": "WikiArt",
- "special.lib.gla.ac.uk": "University of Glasgow",
- "uploads4.wikipaintings.org": "Wikipaintings",
- "de.wikisource.org": "Wikisource",
- "www.spamula.net": "Spamula",
- "2.bp.blogspot.com": "Blogspot",
- "www.bsb-muenchen.de": "BSB Muenchen",
- "fullerton.academia.edu": "CSU Fullerton",
- "iiif.lib.harvard.edu": "Harvard",
- "theappendix.net": "The Appendix"
-}
diff --git a/app/dashboard/import/sources/pdr/thumbnails.txt b/app/dashboard/import/sources/pdr/thumbnails.txt
deleted file mode 100644
index ab19fe67c2e..00000000000
--- a/app/dashboard/import/sources/pdr/thumbnails.txt
+++ /dev/null
@@ -1,62 +0,0 @@
-2018
-
-_39729072460_448fe7f96a_o.jpg
-_27339783618_645c8ec010_b.jpg
-_39537337401_be82242e19_b.jpg
-_39729603801_9139865171_b.jpg
-_39419393964_0d43e5b285_b.jpg
-_26424139858_4308f81570_b.jpg
-_40626273312_8d5eae3625_b.jpg
-_40897185072_0ba58deaf2_b.jpg
-
-2017
-
-_32477923166_11ac077bbf_c.jpg
-_32739208636_d999567ce1_o.jpg
-_32191435154_e1006a7696_b.jpg
-_32939152210_bfaa856eec_z.jpg
-_33458219511_0deb0817ec_b.jpg
-_32914513074_fa5d57cd6f_o.jpg
-_33961375642_c80044b627_b.jpg
-_34385852236_fc37ca430c_c.jpg
-_33871440234_ba0916e1f6_o.jpg
-_34947278816_d8a53da104_o.jpg
-_35172568521_7fcc9ecb10_c.jpg
-_35549576736_8556a26a90_b.jpg
-_35835912416_83efcb9699_o.jpg
-_36025209781_cefe072bb2_c.jpg
-_35772554654_75211b60f6_o.jpg
-_36742555122_9a3629b8a7_o.png
-_36267618664_27587c1a18_c.jpg
-_36665252783_0c28b3aa92_b.jpg
-_37532093481_8ec24a70f4_b.jpg
-_37197683024_150a11b4b4_c.jpg
-_38287703681_737264203c_b.jpg
-_37691151385_b01b06bc2b_b.jpg
-_27115095529_7abcd5c0ba_b.jpg
-
-2016
-
-_23565530654_c3ae721476_o.jpg
-_Christopher_Marlowe.jpg
-_24269152474_1e7a6ff2c6_b.jpg
-_24866292319_20cfaef5f5_b.jpg
-_25314329950_1674c63145_b.jpg
-_25964387156_a8a91976a1_b.jpg
-_25999339080_14357d6bd8_o.jpg
-_25950321504_9e2b83950a_b.jpg
-_26793334355_10e53e58db_c.jpg
-_26470194873_92e96484c3_o.jpg
-_27301604661_7841ff0f1e_h.jpg
-_27612383666_cc02e8cf9f_b.jpg
-_800px-Erotische_Aufnahme_c1880s.jpg
-_28326632622_a7b89c65c0_b.jpg
-_28081241544_8b6ce4aef1_b.jpg
-_28737899780_6b78015994_c.jpg
-_29464111776_7bb40aedda_b.jpg
-_29405343460_601ae260fa_c.jpg
-_29645543523_bca916974a_c.jpg
-_800px-1572_Typus_Orbis_Terrarum_Ortelius.jpg
-_30898148625_c6c3bd4aa5_b.jpg
-_800px-Illustrations_to_Robert_Blair%27s_The_Grave_%2C_object_9_The_Soul_Hovering_over_the_Body.jpg
-_30638906824_0afa3f480d_o.jpg
diff --git a/app/dashboard/import/sources/pdr/tidy_figures.js b/app/dashboard/import/sources/pdr/tidy_figures.js
deleted file mode 100644
index 99b39c8704d..00000000000
--- a/app/dashboard/import/sources/pdr/tidy_figures.js
+++ /dev/null
@@ -1,83 +0,0 @@
-var pretty = require("pretty");
-var parse = require("url").parse;
-var request = require("request");
-var fs = require("fs-extra");
-var SOURCES = require("./sources.json");
-
-function fetch_source(host) {
- request("http://" + host, function (err, res, body) {
- if (err || !body) {
- console.log("HOST", host);
- return;
- }
-
- var $ = require("cheerio").load(body);
- var title = $("head title").text();
-
- if (title) SOURCES[host] = title;
-
- fs.outputJsonSync(__dirname + "/sources.json", SOURCES, { spaces: 2 });
- });
-}
-module.exports = function ($) {
- $("figure, figcaption, figure img").each(function (i, el) {
- $(el).removeAttr("class");
- });
-
- $("figure").each(function (i, el) {
- $(el).replaceWith(pretty($.html(el)));
- });
-
- $("figure img").each(function (i, el) {
- $(el).removeAttr("width");
- $(el).removeAttr("height");
- });
-
- $("figcaption a").each(function (i, el) {
- // console.log('BEFORE:', parent.text().split('\n').join(''));
-
- if ($(el).text().toLowerCase().indexOf("source") === -1) return;
-
- var host = $(el).attr("href");
-
- var parsed_host = parse(host);
-
- if (parsed_host.host) host = parsed_host.host;
-
- // Don't ask
- if (parsed_host.protocol === "file:") host = "commons.wikimedia.org";
-
- $(el).removeAttr("rel");
- $(el).removeAttr("target");
-
- if (el.prev.type === "text") {
- var data = el.prev.data;
-
- if (data.trim().slice(-1) === "—") {
- data = data.trim().slice(0, -1);
- }
-
- if (el.next.data.indexOf(".") > -1) data = data.trim() + ".";
-
- data += " ";
-
- el.prev.data = data;
- }
-
- if (el.next.type === "text") {
- $(el.next).remove();
- }
-
- if (SOURCES[host]) {
- host = SOURCES[host];
- } else {
- fetch_source(host);
- }
-
- $(el).text(host);
-
- $(el).replaceWith($("" + $.html(el) + " "));
-
- // console.log('AFTER:', parent.text().split('\n').join(''));
- });
-};
diff --git a/app/dashboard/import/sources/pdr/tidy_footnotes.js b/app/dashboard/import/sources/pdr/tidy_footnotes.js
deleted file mode 100644
index ef4846c2fa0..00000000000
--- a/app/dashboard/import/sources/pdr/tidy_footnotes.js
+++ /dev/null
@@ -1,26 +0,0 @@
-var parse = require("url").parse;
-
-module.exports = function ($) {
- // Remove hr before footnotes definition
- // since the markdown parser creates a new one
- $('sup[id="fn1"]').parent().prevUntil("hr").prev().remove();
-
- // Fix bare URLs in footnotes
- $('sup[id^="fn"]').each(function (i, el) {
- $(el)
- .find("a")
- .each(function (i, el) {
- var link_text = $(el).text();
-
- if (link_text.indexOf("://") === -1) return;
-
- try {
- link_text = parse(link_text).host;
- } catch (e) {
- return;
- }
-
- if (link_text) $(el).text(link_text);
- });
- });
-};
diff --git a/app/dashboard/import/sources/pdr/tidy_sources.js b/app/dashboard/import/sources/pdr/tidy_sources.js
deleted file mode 100644
index c49bc1eeadf..00000000000
--- a/app/dashboard/import/sources/pdr/tidy_sources.js
+++ /dev/null
@@ -1,15 +0,0 @@
-var sources = require("./sources");
-var fs = require("fs-extra");
-
-for (var i in sources) {
- var label = sources[i];
-
- label = label.split("\n").join("");
- label = label.split("\r").join("");
- label = label.split("\t").join("");
-
- sources[i] = label;
-}
-
-fs.outputJsonSync("sources-fixed.json", sources, { spaces: 2 });
-console.log("Done!");
diff --git a/app/dashboard/import/sources/tumblr/load.js b/app/dashboard/import/sources/tumblr/load.js
index 236a05738eb..922480d2524 100644
--- a/app/dashboard/import/sources/tumblr/load.js
+++ b/app/dashboard/import/sources/tumblr/load.js
@@ -1,114 +1,76 @@
-var fs = require("fs-extra");
-var string = require("string");
-var API_KEY = process.env.BLOT_TUMBLR_KEY;
-var URL_TEMPLATE =
+const fetch = require("node-fetch");
+const fs = require("fs-extra");
+const API_KEY = process.env.BLOT_TUMBLR_KEY;
+const URL_TEMPLATE =
"http://api.tumblr.com/v2/blog/{{url}}/{{resource}}?api_key={{API_KEY}}";
-var request = require("request");
-var helper = require("dashboard/importer/helper");
-var for_each = helper.for_each;
-var parse = require("url").parse;
-function tidy_source_url(source_url) {
- source_url = source_url.split("http://").join("");
- source_url = source_url.split("https://").join("");
- source_url = source_url.split("/").join("");
-
- return source_url;
+function tidy_source_url (source_url) {
+ return source_url
+ .replace(/https?:\/\//, "")
+ .split("/")
+ .join("");
}
-function main(source_url, callback) {
- var blog = {};
-
+async function main (source_url) {
source_url = tidy_source_url(source_url);
- get_info(source_url, function (err, info) {
- if (err) return callback(err);
+ const info = await get_info(source_url);
+ const posts = await get_posts(source_url, info.total_posts);
- get_posts(source_url, info.total_posts, function (err, posts) {
- if (err) return callback(err);
+ const blog = {
+ title: info.title,
+ posts: posts,
+ host: new URL(info.url).host
+ };
- blog.title = info.title;
- blog.posts = posts;
- blog.host = parse(info.url).host;
-
- return callback(null, blog);
- });
- });
+ return blog;
}
-function get_posts(source_url, total_posts, callback) {
- var urls = [];
- var posts = [];
-
- for (var offset = 0; offset < total_posts; offset += 20) {
- urls.push(
- string(URL_TEMPLATE + "&offset={{offset}}&limit={{limit}}").template({
- url: source_url,
- offset: offset,
- limit: 20,
- API_KEY: API_KEY,
- resource: "posts",
- }).s
- );
+async function get_posts (source_url, total_posts) {
+ let posts = [];
+ const limit = 20;
+
+ for (let offset = 0; offset < total_posts; offset += limit) {
+ const url = URL_TEMPLATE.replace("{{url}}", source_url)
+ .replace("{{offset}}", offset)
+ .replace("{{limit}}", limit)
+ .replace("{{API_KEY}}", API_KEY)
+ .replace("{{resource}}", "posts");
+ console.log(posts.length);
+
+ const response = await fetch(url);
+ const body = await response.json();
+ posts = posts.concat(body.response.posts);
}
- for_each(
- urls,
- function (url, next) {
- console.log(posts.length);
-
- request(url, function (err, res, body) {
- if (err) return callback(err);
-
- body = JSON.parse(body);
- body = body.response;
-
- posts = posts.concat(body.posts);
-
- next();
- });
- },
- function () {
- console.log("Done!");
- callback(null, posts);
- }
- );
+ console.log("Done!");
+ return posts;
}
-function get_info(source_url, callback) {
- var url = string(URL_TEMPLATE).template({
- url: source_url,
- API_KEY: API_KEY,
- resource: "info",
- }).s;
-
- request(url, function (err, res, body) {
- if (err) return callback(err);
+async function get_info (source_url) {
+ const url = URL_TEMPLATE.replace("{{url}}", source_url)
+ .replace("{{API_KEY}}", API_KEY)
+ .replace("{{resource}}", "info");
- body = JSON.parse(body);
- body = body.response.blog;
-
- return callback(null, body);
- });
+ const response = await fetch(url);
+ const body = await response.json();
+ return body.response.blog;
}
if (require.main === module) {
- var source_url = process.argv[2];
- var output_file = process.argv[3];
+ const source_url = process.argv[2];
+ const output_file = process.argv[3];
if (!source_url) throw new Error("Please pass tumblr URL as first argument");
if (!output_file)
throw new Error("Please pass filename to write blog to as second argument");
- main(source_url, function (err, blog) {
- if (err) throw err;
-
- fs.outputJson(output_file, blog, { spaces: 2 }, function (err) {
- if (err) throw err;
-
- process.exit();
+ main(source_url)
+ .then(blog => fs.outputJson(output_file, blog, { spaces: 2 }))
+ .then(() => process.exit())
+ .catch(err => {
+ throw err;
});
- });
}
module.exports = main;
diff --git a/app/dashboard/settings/verify-domain.js b/app/dashboard/settings/verify-domain.js
index 181574adfea..2d059096c5c 100644
--- a/app/dashboard/settings/verify-domain.js
+++ b/app/dashboard/settings/verify-domain.js
@@ -1,30 +1,31 @@
-var makeRequest = require("request");
-var url = require("url");
+const fetch = require("node-fetch");
+const url = require("url");
-// Called on the site to call the individual
-// blog. We could make this call directly but
-// to do so would violate our CSP. This is posssibly safer
module.exports = function (request, response) {
- var domain = request.params.domain;
- domain = domain.replace(" ", "");
+ let domain = request.params.domain;
+ domain = domain.replace(/\s/g, ""); // Remove all spaces
- if (domain.indexOf("//") > -1) domain = url.parse(domain).hostname;
+ if (domain.indexOf("//") > -1) domain = new URL(domain).hostname;
- var options = {
- // Change this to https is the
- // user requries SSL to visit blog
- uri: "http://" + domain + "/verify/domain-setup",
+ // Use HTTPS to ensure secure communication
+ const endpoint = `https://${domain}/verify/domain-setup`;
- // The request module has a known bug
- // which leaks memory and event emitters
- // during redirects. We cap the maximum
- // redirects to 5 to avoid encountering
- // errors when it creates 10+ emitters
- // for a URL with 10+ redirects...
- maxRedirects: 5,
- };
-
- makeRequest(options, function (error, res, body) {
- response.send(body === request.blog.handle);
- });
+ fetch(endpoint)
+ .then(res => {
+ if (!res.ok) {
+ throw new Error(`HTTP error! status: ${res.status}`);
+ }
+ return res.text();
+ })
+ .then(body => {
+ // Send back a boolean response whether the body matches `request.blog.handle`
+ response.send(body === request.blog.handle);
+ })
+ .catch(error => {
+ // Handle any errors that occurred during fetch
+ console.error("Fetch error:", error);
+ response
+ .status(500)
+ .send("An error occurred while verifying the domain setup");
+ });
};
diff --git a/app/helper/transformer/download/index.js b/app/helper/transformer/download/index.js
index 0ddfa83c9bc..7d8819b4a87 100644
--- a/app/helper/transformer/download/index.js
+++ b/app/helper/transformer/download/index.js
@@ -1,24 +1,23 @@
-var ensure = require("helper/ensure");
-
-var request = require("request");
-var fs = require("fs");
-var writeStream = fs.createWriteStream;
-var UID = require("helper/makeUid");
-var callOnce = require("helper/callOnce");
-var tempDir = require("helper/tempDir")();
-var nameFrom = require("helper/nameFrom");
-var tidy = require("./tidy");
-var invalid = require("./invalid");
-
-var IF_NONE_MATCH = "If-None-Match";
-var IF_MODIFIED_SINCE = "If-Modified-Since";
-var LAST_MODIFIED = "last-modified";
-var CACHE_CONTROL = "cache-control";
-
-var MAX_REDIRECTS = 5; // prevent event emitter leak...
-var TIMEOUT = 5000; // 5s
-
-var debug = function () {}; // console.log ||
+const fetch = require("node-fetch");
+const fs = require("fs").promises;
+const { createWriteStream } = require("fs");
+const ensure = require("helper/ensure");
+const UID = require("helper/makeUid");
+const callOnce = require("helper/callOnce");
+const tempDir = require("helper/tempDir")();
+const nameFrom = require("helper/nameFrom");
+const tidy = require("./tidy");
+const invalid = require("./invalid");
+
+const IF_NONE_MATCH = "If-None-Match";
+const IF_MODIFIED_SINCE = "If-Modified-Since";
+const LAST_MODIFIED = "last-modified";
+const CACHE_CONTROL = "cache-control";
+
+const MAX_REDIRECTS = 5;
+const TIMEOUT = 5000; // 5s
+
+const debug = function () {}; // console.log || noop for debugging
module.exports = function (url, headers, callback) {
// Verify the url has a host, and protocol
@@ -33,55 +32,47 @@ module.exports = function (url, headers, callback) {
// We don't need to download anything.
if (isFresh(headers)) return callback();
- var file, download, path, options;
-
callback = callOnce(callback);
- path = tempDir + UID(6) + "-" + nameFrom(url);
-
- options = {
- headers: { "user-agent": "node-request" },
- maxRedirects: MAX_REDIRECTS,
- timeout: TIMEOUT,
- url: url,
+ const path = tempDir + UID(6) + "-" + nameFrom(url);
+ const file = createWriteStream(path);
+
+ const options = {
+ headers: {
+ "User-Agent": "node-fetch",
+ ...(headers.etag && { [IF_NONE_MATCH]: headers.etag }),
+ ...(headers[LAST_MODIFIED] && {
+ [IF_MODIFIED_SINCE]: headers[LAST_MODIFIED]
+ })
+ },
+ redirect: "follow",
+ follow: MAX_REDIRECTS,
+ timeout: TIMEOUT
};
- if (headers && headers.etag) options.headers[IF_NONE_MATCH] = headers.etag;
-
- if (headers && headers[LAST_MODIFIED])
- options.headers[IF_MODIFIED_SINCE] = headers[LAST_MODIFIED];
-
- debug("Downloading", url, "to", path, "with request headers:");
+ debug("Downloading", url, "to", path, "with fetch headers:");
debug(print(options.headers));
- file = writeStream(path);
-
- file.on("error", done).on("finish", file.close);
+ fetch(url, options)
+ .then(res => {
+ debug("Received response:");
- download = request
- .get(options)
- .on("response", onResponse)
- .on("error", done)
- .on("end", done);
+ if (!res.ok) {
+ debug(" it has a bad status code:", res.status);
+ throw new Error(res.status);
+ }
- download.pipe(file);
+ if (res.status === 304) {
+ debug(" it has 304 unchanged status");
+ file.end(); // close the file stream as we won't write anything to it
+ throw new Error("Not Modified");
+ }
- function onResponse(res) {
- debug("Recieved response:");
-
- if (!res || !res.statusCode) {
- debug(" it is empty or without status code");
- return callback(new Error("No response"));
- }
-
- if (res.headers) {
- var cacheControl = res.headers[CACHE_CONTROL];
- var lastModified = res.headers[LAST_MODIFIED];
- var expires = res.headers.expires;
-
- // etags sometimes have " inside a string
- // dont remove these or it wont work...
- var etag = res.headers.etag;
+ // Update response headers
+ const cacheControl = res.headers.get(CACHE_CONTROL);
+ const lastModified = res.headers.get(LAST_MODIFIED);
+ const expires = res.headers.get("expires");
+ const etag = res.headers.get("etag");
headers[LAST_MODIFIED] = lastModified || headers[LAST_MODIFIED] || "";
headers.etag = etag || headers.etag || "";
@@ -91,63 +82,38 @@ module.exports = function (url, headers, callback) {
headers.expires ||
"";
- debug(" updated latest reponse headers for status", res.statusCode);
- }
-
- if (res.statusCode === 304) {
- debug(" it has 304 unchanged status");
- stop();
- return done();
- }
-
- // can we make this play nicely with redirects?
- if (res.statusCode < 200 || res.statusCode >= 300) {
- debug(" it has a bad status code:", res.statusCode);
- return done(new Error(res.statusCode));
- }
- }
-
- function stop() {
- debug("Aborting download and removing", path);
-
- download.abort();
-
- // we reset the path since the
- // download was stopped, there is no local file.
- // do nothing don't care if this errors
- try {
- fs.unlink(path, function (err) {
- if (err) debug(err);
- });
- } catch (e) {}
-
- path = null;
- }
-
- function done(err) {
- if (err) stop();
+ debug(" updated latest response headers for status", res.status);
+ res.body.pipe(file); // start piping the response body to the file
- debug("Calling back with path", path, "and res headers:");
- debug(print(headers));
-
- return callback(err, path, headers);
- }
+ return new Promise((resolve, reject) => {
+ file.on("finish", resolve);
+ file.on("error", reject);
+ });
+ })
+ .then(() => {
+ debug("Calling back with path", path, "and res headers:");
+ debug(print(headers));
+ callback(null, path, headers);
+ })
+ .catch(err => {
+ debug("Download error:", err);
+ file.close();
+ fs.unlink(path).catch(() => {});
+ callback(err);
+ });
};
-function isFresh(existing) {
+function isFresh (existing) {
return (
existing &&
existing.url &&
existing.expires &&
- existing.expires > Date.now()
+ new Date(existing.expires) > new Date()
);
}
-function print(obj) {
- var res = "";
- for (var i in obj) {
- if (res) res += "\n";
- res += " " + i + ': "' + obj[i] + '"';
- }
- return res;
+function print (obj) {
+ return Object.entries(obj)
+ .map(([key, value]) => ` ${key}: "${value}"`)
+ .join("\n");
}
diff --git a/app/tests/blog/drafts.js b/app/tests/blog/drafts.js
index 63349cccd7b..8fc5cd09f35 100644
--- a/app/tests/blog/drafts.js
+++ b/app/tests/blog/drafts.js
@@ -4,7 +4,7 @@ describe("drafts work", function () {
const sync = require("sync");
const blogServer = require("../../blog");
const fs = require("fs-extra");
- const request = require("request");
+ const fetch = require("node-fetch");
const Express = require("express");
const config = require("config");
const guid = require("helper/guid");
@@ -16,21 +16,39 @@ describe("drafts work", function () {
const firstContents = guid();
const secondContents = guid();
- this.writeDraft(path, firstContents, (err) => {
+ this.writeDraft(path, firstContents, err => {
if (err) return done.fail(err);
- request(this.origin + "/draft/stream" + path, { strictSSL: false })
- .on("response", () => {
- this.writeDraft(path, secondContents, (err) => {
- if (err) return done.fail(err);
+ const { Readable } = require("stream");
+
+ fetch(this.origin + "/draft/stream" + path)
+ .then(res => {
+ if (!res.ok) {
+ throw new Error(`HTTP error! status: ${res.status}`);
+ }
+ return new Promise((resolve, reject) => {
+ this.writeDraft(path, secondContents, err => {
+ if (err) {
+ reject(err);
+ } else {
+ resolve(res.body); // assuming writeDraft processes successfully, we pass on the response body stream
+ }
+ });
+ });
+ })
+ .then(body => {
+ // The response body is a stream. Create a readable stream to consume it.
+ const readableStream = new Readable().wrap(body);
+ readableStream.on("data", chunk => {
+ const data = chunk.toString().trim();
+ if (!data) return;
+ expect(data).toContain(secondContents);
+ console.log("calling done... HERE!");
+ done();
});
})
- .on("data", (data) => {
- data = data.toString().trim();
- if (!data) return;
- expect(data).toContain(secondContents);
- console.log("calling done... HERE!");
- done();
+ .catch(err => {
+ done.fail(err);
});
});
});
@@ -40,16 +58,16 @@ describe("drafts work", function () {
const view = {
name: "entry.html",
- content: `{{{entry.html}}}`,
+ content: `{{{entry.html}}}`
};
- Template.create(this.blog.id, templateName, {}, (err) => {
+ Template.create(this.blog.id, templateName, {}, err => {
if (err) return done(err);
Template.getTemplateList(this.blog.id, (err, templates) => {
let templateId = templates.filter(
({ name }) => name === templateName
)[0].id;
- Template.setView(templateId, view, (err) => {
+ Template.setView(templateId, view, err => {
if (err) return done(err);
Blog.set(
this.blog.id,
@@ -67,7 +85,7 @@ describe("drafts work", function () {
server = Express();
server.use((req, res, next) => {
const _get = req.get;
- req.get = (arg) => {
+ req.get = arg => {
if (arg === "host") {
return `${this.blog.handle}.${config.host}`;
} else return _get(arg);
@@ -75,7 +93,7 @@ describe("drafts work", function () {
next();
});
server.use(blogServer);
- this.origin = "http://localhost:" + 8919;
+ this.origin = "http://127.0.0.1:" + 8919;
this.server = server.listen(8919, done);
this.writeDraft = (path, contents, callback) => {
diff --git a/app/tests/blog/scheduled-post.js b/app/tests/blog/scheduled-post.js
index 6885829d699..93d336854e2 100644
--- a/app/tests/blog/scheduled-post.js
+++ b/app/tests/blog/scheduled-post.js
@@ -6,7 +6,6 @@ xdescribe("scheduled posts", function () {
const sync = require("sync");
const blogServer = require("../../blog");
const fs = require("fs-extra");
- const request = require("request");
const Express = require("express");
const config = require("config");
const guid = require("helper/guid");
@@ -33,7 +32,7 @@ xdescribe("scheduled posts", function () {
});
}, MINUTE);
fs.outputFileSync(this.blogDirectory + path, contents, "utf-8");
- folder.update(path, (err) => {
+ folder.update(path, err => {
if (err) return callback(err);
finish(null, () => {
request(this.origin, { strictSSL: false }, (err, res, body) => {
@@ -51,16 +50,16 @@ xdescribe("scheduled posts", function () {
const view = {
name: "entries.html",
- content: `{{#entries}}{{{html}}}{{/entries}}`,
+ content: `{{#entries}}{{{html}}}{{/entries}}`
};
- Template.create(this.blog.id, templateName, {}, (err) => {
+ Template.create(this.blog.id, templateName, {}, err => {
if (err) return done(err);
Template.getTemplateList(this.blog.id, (err, templates) => {
let templateId = templates.filter(
({ name }) => name === templateName
)[0].id;
- Template.setView(templateId, view, (err) => {
+ Template.setView(templateId, view, err => {
if (err) return done(err);
Blog.set(
this.blog.id,
@@ -77,7 +76,7 @@ xdescribe("scheduled posts", function () {
this.server = Express()
.use((req, res, next) => {
const _get = req.get;
- req.get = (arg) => {
+ req.get = arg => {
if (arg === "host") {
return `${this.blog.handle}.${config.host}`;
} else return _get(arg);
diff --git a/app/tests/dates/index.js b/app/tests/dates/index.js
index f43e6abdff1..17d847ecad4 100644
--- a/app/tests/dates/index.js
+++ b/app/tests/dates/index.js
@@ -4,7 +4,7 @@ describe("date integration tests", function () {
const fs = require("fs-extra");
const Blog = require("models/blog");
const Template = require("models/template");
- const request = require("request");
+ const fetch = require("node-fetch");
const Express = require("express");
const config = require("config");
@@ -17,18 +17,18 @@ describe("date integration tests", function () {
{
timeZone: "UTC",
dateMetadata: "1/2/2012",
- result: "Mon, 02 Jan 2012 00:00:00 +0000",
+ result: "Mon, 02 Jan 2012 00:00:00 +0000"
},
{
timeZone: "Asia/Calcutta",
dateMetadata: "2020-03-29T19:29:00+0530",
- result: "Sun, 29 Mar 2020 19:29:00 +0530",
+ result: "Sun, 29 Mar 2020 19:29:00 +0530"
},
{
timeZone: "Asia/Calcutta",
dateMetadata: "2020/03/29 19:29",
- result: "Sun, 29 Mar 2020 19:29:00 +0530",
- },
+ result: "Sun, 29 Mar 2020 19:29:00 +0530"
+ }
];
tests.forEach(({ timeZone, dateMetadata, result }) => {
@@ -48,13 +48,13 @@ describe("date integration tests", function () {
});
});
- function createTemplate(done) {
+ function createTemplate (done) {
const test = this;
const templateName = "example";
const view = {
name: "entries.html",
- content: `{{#allEntries}}{{#formatDate}}${resultFormat}{{/formatDate}}{{/allEntries}}`,
+ content: `{{#allEntries}}{{#formatDate}}${resultFormat}{{/formatDate}}{{/allEntries}}`
};
Template.create(test.blog.id, templateName, {}, function (err) {
@@ -78,7 +78,7 @@ describe("date integration tests", function () {
});
}
- function createEntryWithDate(test, date, callback) {
+ function createEntryWithDate (test, date, callback) {
const path = "/test.txt";
const contents = `Date: ${date}\n\n# Hello, world\n\nThis is a post.`;
sync(test.blog.id, function (err, folder, done) {
@@ -91,11 +91,11 @@ describe("date integration tests", function () {
});
}
- function checkDateOnBlog(test, callback) {
- request(test.origin, function (err, res, body) {
- expect(res.statusCode).toEqual(200);
- callback(null, body.trim());
- });
+ async function checkDateOnBlog (test, callback) {
+ const res = await fetch(test.origin);
+ expect(res.status).toEqual(200);
+ const body = await res.text();
+ callback(null, body.trim());
}
// Create a webserver for testing remote files
diff --git a/app/tests/index.js b/app/tests/index.js
index cf1031b1b81..91aab498b01 100644
--- a/app/tests/index.js
+++ b/app/tests/index.js
@@ -11,14 +11,14 @@ describe("Blot configuration", function () {
}).not.toThrow();
});
- var request = require("request");
+ var fetch = require("node-fetch");
var START_MESSAGE = "listening";
var server;
var stderr = "";
beforeAll(function (done) {
server = require("child_process").fork(__dirname + "/../../app", {
- silent: true,
+ silent: true
});
// App should not emit anything on standard error
@@ -37,7 +37,6 @@ describe("Blot configuration", function () {
}, LONG_TIMEOUT);
afterAll(function (done) {
-
server.on("exit", function () {
done();
});
@@ -45,16 +44,18 @@ describe("Blot configuration", function () {
server.kill();
});
- // Stripe and Dropbox webhooks require HTTPS set up, or NGINX
- // working, so they are harder to test but it would be nice to
- // do this eventually.
- it("returns OK at the health endpoint", function (done) {
- request("http://localhost:8080/health", function (err, res, body) {
- if (err) return done.fail(err);
- expect(res.statusCode).toBe(200);
- expect(body).toEqual("OK");
- done();
- });
+ it("returns OK at the health endpoint", async function () {
+ console.log("fetching health");
+
+ const res = await fetch("http://localhost:8080/health");
+
+ expect(res.status).toBe(200);
+
+ console.log("fetching health body");
+
+ const body = await res.text();
+
+ expect(body).toEqual("OK");
});
it("can connect to redis", function (done) {
diff --git a/package-lock.json b/package-lock.json
index 7068e14a948..e5b9787234f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -63,7 +63,6 @@
"pushover": "^1.3.6",
"rate-limit-redis": "^2.0.0",
"redis": "^3.1.2",
- "request": "^2.72.0",
"sharp": "^0.32.6",
"simple-git": "^1.102.0",
"stripe": "^2.9.0",
@@ -1029,6 +1028,7 @@
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@@ -1343,6 +1343,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+ "dev": true,
"engines": {
"node": ">=0.8"
}
@@ -1471,7 +1472,8 @@
"node_modules/aws4": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz",
- "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA=="
+ "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==",
+ "dev": true
},
"node_modules/b4a": {
"version": "1.6.4",
@@ -4249,6 +4251,7 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
+ "dev": true,
"engines": [
"node >=0.6.0"
]
@@ -4276,7 +4279,8 @@
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "dev": true
},
"node_modules/fast-fifo": {
"version": "1.3.2",
@@ -4302,7 +4306,8 @@
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true
},
"node_modules/fast-levenshtein": {
"version": "2.0.6",
@@ -6322,6 +6327,7 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
+ "dev": true,
"engines": {
"node": ">=4"
}
@@ -6331,6 +6337,7 @@
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
"integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
"deprecated": "this library is no longer supported",
+ "dev": true,
"dependencies": {
"ajv": "^6.12.3",
"har-schema": "^2.0.0"
@@ -7761,12 +7768,14 @@
"node_modules/json-schema": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
- "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="
+ "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==",
+ "dev": true
},
"node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
},
"node_modules/json-stable-stringify-without-jsonify": {
"version": "1.0.1",
@@ -7777,6 +7786,7 @@
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
"integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==",
+ "dev": true,
"dependencies": {
"assert-plus": "1.0.0",
"extsprintf": "1.3.0",
@@ -9033,6 +9043,7 @@
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
+ "dev": true,
"engines": {
"node": "*"
}
@@ -10018,7 +10029,8 @@
"node_modules/psl": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
- "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ=="
+ "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==",
+ "dev": true
},
"node_modules/pstree.remy": {
"version": "1.1.8",
@@ -10535,6 +10547,7 @@
"resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
"integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
"deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142",
+ "dev": true,
"dependencies": {
"aws-sign2": "~0.7.0",
"aws4": "^1.8.0",
@@ -10565,6 +10578,7 @@
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
+ "dev": true,
"engines": {
"node": "*"
}
@@ -10572,12 +10586,14 @@
"node_modules/request/node_modules/caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
- "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
+ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
+ "dev": true
},
"node_modules/request/node_modules/forever-agent": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
+ "dev": true,
"engines": {
"node": "*"
}
@@ -10586,6 +10602,7 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+ "dev": true,
"dependencies": {
"assert-plus": "^1.0.0",
"jsprim": "^1.2.2",
@@ -10600,6 +10617,7 @@
"version": "1.14.2",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz",
"integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=",
+ "dev": true,
"dependencies": {
"asn1": "~0.2.3",
"assert-plus": "^1.0.0",
@@ -10625,12 +10643,14 @@
"node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
- "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y="
+ "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=",
+ "dev": true
},
"node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/bcrypt-pbkdf": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
"integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
+ "dev": true,
"optional": true,
"dependencies": {
"tweetnacl": "^0.14.3"
@@ -10640,6 +10660,7 @@
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+ "dev": true,
"dependencies": {
"assert-plus": "^1.0.0"
},
@@ -10651,6 +10672,7 @@
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
"integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=",
+ "dev": true,
"optional": true,
"dependencies": {
"jsbn": "~0.1.0"
@@ -10660,6 +10682,7 @@
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+ "dev": true,
"dependencies": {
"assert-plus": "^1.0.0"
}
@@ -10668,38 +10691,45 @@
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
+ "dev": true,
"optional": true
},
"node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/tweetnacl": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
+ "dev": true,
"optional": true
},
"node_modules/request/node_modules/is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
- "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
+ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
+ "dev": true
},
"node_modules/request/node_modules/isstream": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
- "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
+ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
+ "dev": true
},
"node_modules/request/node_modules/json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
- "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
+ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
+ "dev": true
},
"node_modules/request/node_modules/performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
- "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
+ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
+ "dev": true
},
"node_modules/request/node_modules/qs": {
"version": "6.5.3",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz",
"integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==",
+ "dev": true,
"engines": {
"node": ">=0.6"
}
@@ -10709,6 +10739,7 @@
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
"integrity": "sha1-G0r0lV6zB3xQHCOHL8ZROBFYcTE=",
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
+ "dev": true,
"bin": {
"uuid": "bin/uuid"
}
@@ -12082,6 +12113,7 @@
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
"integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
+ "dev": true,
"dependencies": {
"psl": "^1.1.28",
"punycode": "^2.1.1"
@@ -12094,6 +12126,7 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+ "dev": true,
"engines": {
"node": ">=6"
}
@@ -12485,6 +12518,7 @@
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "dev": true,
"dependencies": {
"punycode": "^2.1.0"
}
@@ -12493,6 +12527,7 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+ "dev": true,
"engines": {
"node": ">=6"
}
@@ -12586,6 +12621,7 @@
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+ "dev": true,
"engines": [
"node >=0.6.0"
],
@@ -13580,6 +13616,7 @@
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
"requires": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@@ -13822,7 +13859,8 @@
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
- "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+ "dev": true
},
"ast-transform": {
"version": "0.0.0",
@@ -13910,7 +13948,8 @@
"aws4": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz",
- "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA=="
+ "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==",
+ "dev": true
},
"b4a": {
"version": "1.6.4",
@@ -16129,7 +16168,8 @@
"extsprintf": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
- "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
+ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
+ "dev": true
},
"faker": {
"version": "4.1.0",
@@ -16151,7 +16191,8 @@
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "dev": true
},
"fast-fifo": {
"version": "1.3.2",
@@ -16174,7 +16215,8 @@
"fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true
},
"fast-levenshtein": {
"version": "2.0.6",
@@ -17805,12 +17847,14 @@
"har-schema": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
- "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
+ "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
+ "dev": true
},
"har-validator": {
"version": "5.1.5",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
"integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
+ "dev": true,
"requires": {
"ajv": "^6.12.3",
"har-schema": "^2.0.0"
@@ -18846,12 +18890,14 @@
"json-schema": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
- "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="
+ "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==",
+ "dev": true
},
"json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
},
"json-stable-stringify-without-jsonify": {
"version": "1.0.1",
@@ -18862,6 +18908,7 @@
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
"integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==",
+ "dev": true,
"requires": {
"assert-plus": "1.0.0",
"extsprintf": "1.3.0",
@@ -19879,7 +19926,8 @@
"oauth-sign": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
- "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
+ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
+ "dev": true
},
"obj-extend": {
"version": "0.1.0",
@@ -20624,7 +20672,8 @@
"psl": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
- "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ=="
+ "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==",
+ "dev": true
},
"pstree.remy": {
"version": "1.1.8",
@@ -21014,6 +21063,7 @@
"version": "2.88.2",
"resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
"integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
+ "dev": true,
"requires": {
"aws-sign2": "~0.7.0",
"aws4": "^1.8.0",
@@ -21040,22 +21090,26 @@
"aws-sign2": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
- "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
+ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
+ "dev": true
},
"caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
- "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
+ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
+ "dev": true
},
"forever-agent": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
- "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
+ "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
+ "dev": true
},
"http-signature": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+ "dev": true,
"requires": {
"assert-plus": "^1.0.0",
"jsprim": "^1.2.2",
@@ -21066,6 +21120,7 @@
"version": "1.14.2",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz",
"integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=",
+ "dev": true,
"requires": {
"asn1": "~0.2.3",
"assert-plus": "^1.0.0",
@@ -21081,12 +21136,14 @@
"asn1": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
- "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y="
+ "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=",
+ "dev": true
},
"bcrypt-pbkdf": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
"integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
+ "dev": true,
"optional": true,
"requires": {
"tweetnacl": "^0.14.3"
@@ -21096,6 +21153,7 @@
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+ "dev": true,
"requires": {
"assert-plus": "^1.0.0"
}
@@ -21104,6 +21162,7 @@
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
"integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=",
+ "dev": true,
"optional": true,
"requires": {
"jsbn": "~0.1.0"
@@ -21113,6 +21172,7 @@
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+ "dev": true,
"requires": {
"assert-plus": "^1.0.0"
}
@@ -21121,12 +21181,14 @@
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
+ "dev": true,
"optional": true
},
"tweetnacl": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
+ "dev": true,
"optional": true
}
}
@@ -21136,32 +21198,38 @@
"is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
- "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
+ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
+ "dev": true
},
"isstream": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
- "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
+ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
+ "dev": true
},
"json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
- "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
+ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
+ "dev": true
},
"performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
- "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
+ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
+ "dev": true
},
"qs": {
"version": "6.5.3",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz",
- "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA=="
+ "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==",
+ "dev": true
},
"uuid": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
- "integrity": "sha1-G0r0lV6zB3xQHCOHL8ZROBFYcTE="
+ "integrity": "sha1-G0r0lV6zB3xQHCOHL8ZROBFYcTE=",
+ "dev": true
}
}
},
@@ -22242,6 +22310,7 @@
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
"integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
+ "dev": true,
"requires": {
"psl": "^1.1.28",
"punycode": "^2.1.1"
@@ -22250,7 +22319,8 @@
"punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
- "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+ "dev": true
}
}
},
@@ -22585,6 +22655,7 @@
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "dev": true,
"requires": {
"punycode": "^2.1.0"
},
@@ -22592,7 +22663,8 @@
"punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
- "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+ "dev": true
}
}
},
@@ -22665,6 +22737,7 @@
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+ "dev": true,
"requires": {
"assert-plus": "^1.0.0",
"core-util-is": "1.0.2",
diff --git a/package.json b/package.json
index 3a177b6923e..a2fef2988e6 100644
--- a/package.json
+++ b/package.json
@@ -86,7 +86,6 @@
"pushover": "^1.3.6",
"rate-limit-redis": "^2.0.0",
"redis": "^3.1.2",
- "request": "^2.72.0",
"sharp": "^0.32.6",
"simple-git": "^1.102.0",
"stripe": "^2.9.0",
diff --git a/tests/broken-links/index.js b/tests/broken-links/index.js
index 12e445c991f..562448c4035 100644
--- a/tests/broken-links/index.js
+++ b/tests/broken-links/index.js
@@ -53,7 +53,6 @@ xdescribe("Blot's website'", function () {
it(
"does not have any broken links for logged-in users",
function (done) {
- var request = require("request");
var test = this;
request.post(