This commit is contained in:
parent
abaf038520
commit
a838bac66f
|
@ -887,6 +887,15 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/nodemailer": {
|
||||||
|
"version": "6.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.0.tgz",
|
||||||
|
"integrity": "sha512-KY7bFWB0MahRZvVW4CuW83qcCDny59pJJ0MQ5ifvfcjNwPlIT0vW4uARO4u1gtkYnWdhSvURegecY/tzcukJcA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/prop-types": {
|
"@types/prop-types": {
|
||||||
"version": "15.7.3",
|
"version": "15.7.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
|
||||||
|
@ -928,6 +937,16 @@
|
||||||
"@types/mime": "*"
|
"@types/mime": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/smtp-server": {
|
||||||
|
"version": "3.5.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/smtp-server/-/smtp-server-3.5.3.tgz",
|
||||||
|
"integrity": "sha512-15g2q1C2F3iiVOQlEjChndNb9wAZZiNBLIO0Xg4+JGc9FvdiD1p6DaLVkbU1I8eHd0g624xz0ateamo3nY0ENw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*",
|
||||||
|
"@types/nodemailer": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/stack-utils": {
|
"@types/stack-utils": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz",
|
||||||
|
@ -1320,6 +1339,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"base32.js": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/base32.js/-/base32.js-0.1.0.tgz",
|
||||||
|
"integrity": "sha1-tYLexpPC8R6JPPBk7mrFthMaIgI="
|
||||||
|
},
|
||||||
"bcrypt-pbkdf": {
|
"bcrypt-pbkdf": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
|
||||||
|
@ -2866,6 +2890,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
||||||
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
|
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
|
||||||
},
|
},
|
||||||
|
"ipv6-normalize": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ipv6-normalize/-/ipv6-normalize-1.0.1.tgz",
|
||||||
|
"integrity": "sha1-GzJYKQ02X6gyOeiZB93kWS52IKg="
|
||||||
|
},
|
||||||
"is-accessor-descriptor": {
|
"is-accessor-descriptor": {
|
||||||
"version": "0.1.6",
|
"version": "0.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
|
||||||
|
@ -4924,6 +4953,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nodemailer": {
|
||||||
|
"version": "6.4.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.4.5.tgz",
|
||||||
|
"integrity": "sha512-NH7aNVQyZLAvGr2+EOto7znvz+qJ02Cb/xpou98ApUt5tEAUSVUxhvHvgV/8I5dhjKTYqUw0nasoKzLNBJKrDQ=="
|
||||||
|
},
|
||||||
"nodemon": {
|
"nodemon": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.2.tgz",
|
||||||
|
@ -6051,6 +6085,16 @@
|
||||||
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
|
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"smtp-server": {
|
||||||
|
"version": "3.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/smtp-server/-/smtp-server-3.6.0.tgz",
|
||||||
|
"integrity": "sha512-DVEVWzL4s1GWzAs4+6rbhNZpAn61+V8l4b7R8zHLAW2jmlwKz9IKQmdgm5sNruCRnS01BYyitI98vJo7LDnXfg==",
|
||||||
|
"requires": {
|
||||||
|
"base32.js": "0.1.0",
|
||||||
|
"ipv6-normalize": "1.0.1",
|
||||||
|
"nodemailer": "6.4.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"snapdragon": {
|
"snapdragon": {
|
||||||
"version": "0.8.2",
|
"version": "0.8.2",
|
||||||
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
|
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"react": "^16.13.0",
|
"react": "^16.13.0",
|
||||||
"react-dom": "^16.13.0",
|
"react-dom": "^16.13.0",
|
||||||
|
"smtp-server": "^3.6.0",
|
||||||
"xml2js": "^0.4.23"
|
"xml2js": "^0.4.23"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -17,6 +18,7 @@
|
||||||
"@types/node-fetch": "^2.5.5",
|
"@types/node-fetch": "^2.5.5",
|
||||||
"@types/react": "^16.9.23",
|
"@types/react": "^16.9.23",
|
||||||
"@types/react-dom": "^16.9.5",
|
"@types/react-dom": "^16.9.5",
|
||||||
|
"@types/smtp-server": "^3.5.3",
|
||||||
"@types/xml2js": "^0.4.5",
|
"@types/xml2js": "^0.4.5",
|
||||||
"concurrently": "^5.1.0",
|
"concurrently": "^5.1.0",
|
||||||
"jest": "^25.1.0",
|
"jest": "^25.1.0",
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import express from "express";
|
import express from "express";
|
||||||
import { Server } from "http";
|
import { Server } from "http";
|
||||||
|
import { SMTPServer } from "smtp-server";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import ReactDOMServer from "react-dom/server";
|
import ReactDOMServer from "react-dom/server";
|
||||||
import { Builder } from "xml2js";
|
import { Builder } from "xml2js";
|
||||||
|
@ -11,7 +12,7 @@ const webApp = express()
|
||||||
.use(express.urlencoded({ extended: true }))
|
.use(express.urlencoded({ extended: true }))
|
||||||
.get("/", (req, res) =>
|
.get("/", (req, res) =>
|
||||||
res.send(
|
res.send(
|
||||||
renderHtml(
|
renderHTML(
|
||||||
<Layout>
|
<Layout>
|
||||||
<Form></Form>
|
<Form></Form>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
@ -20,9 +21,9 @@ const webApp = express()
|
||||||
)
|
)
|
||||||
.post("/", (req, res) => {
|
.post("/", (req, res) => {
|
||||||
const inbox: Inbox = { name: req.body.name, token: newToken() };
|
const inbox: Inbox = { name: req.body.name, token: newToken() };
|
||||||
fs.writeFileSync(feedPath(inbox.token), renderXml(Feed(inbox)));
|
fs.writeFileSync(feedPath(inbox.token), renderXML(Feed(inbox)));
|
||||||
res.send(
|
res.send(
|
||||||
renderHtml(
|
renderHTML(
|
||||||
<Layout>
|
<Layout>
|
||||||
<Created inbox={inbox}></Created>
|
<Created inbox={inbox}></Created>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
@ -30,6 +31,8 @@ const webApp = express()
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const emailServer = new SMTPServer();
|
||||||
|
|
||||||
export let developmentWebServer: Server;
|
export let developmentWebServer: Server;
|
||||||
|
|
||||||
if (process.env.NODE_ENV === "production") {
|
if (process.env.NODE_ENV === "production") {
|
||||||
|
@ -48,8 +51,10 @@ if (process.env.NODE_ENV === "production") {
|
||||||
.use(webApp);
|
.use(webApp);
|
||||||
productionWebApp.listen(80);
|
productionWebApp.listen(80);
|
||||||
productionWebApp.listen(443);
|
productionWebApp.listen(443);
|
||||||
|
emailServer.listen(25);
|
||||||
} else {
|
} else {
|
||||||
developmentWebServer = webApp.listen(8000);
|
developmentWebServer = webApp.listen(8000);
|
||||||
|
emailServer.listen(2525);
|
||||||
}
|
}
|
||||||
|
|
||||||
type Inbox = {
|
type Inbox = {
|
||||||
|
@ -144,7 +149,7 @@ function Created({ inbox: { name, token } }: { inbox: Inbox }) {
|
||||||
<p>
|
<p>
|
||||||
Subscribe to the Atom feed at
|
Subscribe to the Atom feed at
|
||||||
<br />
|
<br />
|
||||||
<code>{feedUrl(token)}</code>
|
<code>{feedURL(token)}</code>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Don’t share these addresses.
|
Don’t share these addresses.
|
||||||
|
@ -176,7 +181,7 @@ function Feed(inbox: Inbox) {
|
||||||
$: {
|
$: {
|
||||||
rel: "self",
|
rel: "self",
|
||||||
type: "application/atom+xml",
|
type: "application/atom+xml",
|
||||||
href: feedUrl(token)
|
href: feedURL(token)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -237,7 +242,7 @@ export function feedPath(token: string) {
|
||||||
return `static/feeds/${token}.xml`;
|
return `static/feeds/${token}.xml`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function feedUrl(token: string) {
|
function feedURL(token: string) {
|
||||||
return `https://www.kill-the-newsletter.com/feeds/${token}.xml`;
|
return `https://www.kill-the-newsletter.com/feeds/${token}.xml`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,10 +254,10 @@ function id(token: string) {
|
||||||
return `urn:kill-the-newsletter:${token}`;
|
return `urn:kill-the-newsletter:${token}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderHtml(component: React.ReactElement): string {
|
function renderHTML(component: React.ReactElement): string {
|
||||||
return `<!DOCTYPE html>\n${ReactDOMServer.renderToStaticMarkup(component)}`;
|
return `<!DOCTYPE html>\n${ReactDOMServer.renderToStaticMarkup(component)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderXml(xml: object): string {
|
function renderXML(xml: object): string {
|
||||||
return new Builder().buildObject(xml);
|
return new Builder().buildObject(xml);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { developmentWebServer, feedPath } from ".";
|
import { developmentWebServer, emailServer, feedPath } from ".";
|
||||||
import fetch from "node-fetch";
|
import fetch from "node-fetch";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
|
|
||||||
|
@ -16,4 +16,5 @@ test("create feed", async () => {
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
developmentWebServer.close();
|
developmentWebServer.close();
|
||||||
|
emailServer.close(() => {});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue