diff --git a/.gitignore b/.gitignore index dd1a7b6..04c2b68 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ +data/* + .yarn/* !.yarn/patches !.yarn/plugins diff --git a/src/config.js b/src/config.js index 1c7caa8..7dbdefe 100644 --- a/src/config.js +++ b/src/config.js @@ -1,12 +1,30 @@ +const { existsSync, mkdirSync } = require('fs') + +const allowedWebmentionSources = [ + "brainbaking.com", + "jefklakscodex.com" +] + +function setupDataDirs() { + allowedWebmentionSources.forEach(domain => { + const dir = `data/${domain}` + console.log(` -- configured for ${domain}`) + if(!existsSync(dir)) { + mkdirSync(dir, { + recursive: true + }) + } + }) +} + + module.exports = { port: 4000, host: "localhost", utcOffset: 60, - allowedWebmentionSources: [ - "brainbaking.com", - "jefklakscodex.com" - ] + allowedWebmentionSources, + setupDataDirs } diff --git a/src/serve.js b/src/serve.js index e8dba6a..48ce633 100644 --- a/src/serve.js +++ b/src/serve.js @@ -27,10 +27,10 @@ app.use(bodyParser({ urlencoded: true })); - // route docs: https://github.com/koajs/router/blob/HEAD/API.md#module_koa-router--Router+get%7Cput%7Cpost%7Cpatch%7Cdelete%7Cdel require("./webmention/route").route(router); const config = require("./config"); +config.setupDataDirs(); app.use(router.routes()).use(router.allowedMethods()); diff --git a/src/webmention/receive.js b/src/webmention/receive.js index 36e5f14..f5ffddf 100644 --- a/src/webmention/receive.js +++ b/src/webmention/receive.js @@ -52,10 +52,18 @@ async function isValidTargetUrl(target) { return false } -async function saveWebmentionToDisk(source, target, mentiondata) { - console.log(`source=${source},target=${target}`) +function asPath(source, target) { const filename = md5(`source=${source},target=${target}`) - await fsp.writeFile(`data/${filename}.json`, mentiondata, 'utf-8') + const domain = config.allowedWebmentionSources.find(d => target.indexOf(d) >= 0) + return `data/${domain}/${filename}.json` +} + +async function deletePossibleOlderWebmention(source, target) { + await fsp.unlink(asPath(source, target)) +} + +async function saveWebmentionToDisk(source, target, mentiondata) { + await fsp.writeFile(asPath(source, target), mentiondata, 'utf-8') } function publishedNow() { @@ -121,6 +129,7 @@ async function receive(body) { src = await got(body.source) } catch(unknownSource) { console.log(` ABORT: invalid source url: ` + unknownSource) + await deletePossibleOlderWebmention(body.source, body.target) return } await processSourceBody(src.body, body.source, body.target) diff --git a/test/__mocks__/got.js b/test/__mocks__/got.js index a51eba2..5a1b33b 100644 --- a/test/__mocks__/got.js +++ b/test/__mocks__/got.js @@ -1,7 +1,8 @@ const fs = require('fs').promises async function got(url) { - const body = await fs.readFile(`./test/__mocks__/${url}`, 'utf8') + const relativeUrl = url.replace('https://brainbaking.com/', '') + const body = await fs.readFile(`./test/__mocks__/${relativeUrl}`, 'utf8') return { body } diff --git a/test/__mocks__/valid-indieweb-source-with-summary.html b/test/__mocks__/valid-indieweb-source-with-summary.html index cc07852..300b239 100644 --- a/test/__mocks__/valid-indieweb-source-with-summary.html +++ b/test/__mocks__/valid-indieweb-source-with-summary.html @@ -282,7 +282,7 @@ This is cool, this is a summary!

-

This is cool, I just found out about valid indieweb target - so cool

+

This is cool, I just found out about valid indieweb target - so cool

diff --git a/test/__mocks__/valid-indieweb-source.html b/test/__mocks__/valid-indieweb-source.html index 4baffad..8dde647 100644 --- a/test/__mocks__/valid-indieweb-source.html +++ b/test/__mocks__/valid-indieweb-source.html @@ -279,7 +279,7 @@
-

This is cool, I just found out about valid indieweb target - so cool

+

This is cool, I just found out about valid indieweb target - so cool

diff --git a/test/__mocks__/valid-nonindieweb-source.html b/test/__mocks__/valid-nonindieweb-source.html index df1b6d0..6d2aca6 100644 --- a/test/__mocks__/valid-nonindieweb-source.html +++ b/test/__mocks__/valid-nonindieweb-source.html @@ -385,7 +385,7 @@
-

Hey look at me i'm mentioning this cool site!

+

Hey look at me i'm mentioning this cool site!

I’ve been playing a lot of retro and more modern hack and slash games lately: from the more near-perfect D2 clone Torchlight, the more unique Sacred and charming Nox to the boring Dungeon Siege and too easy Diablo 3. And then I found someone (my brother-in-law, also a hardcore D2 fan) to replay Diablo II and Lord of Destruction with, providing the perfect opportunity for a retrospective to see if Blizard North’s smash hit still holds up compared to more recent hack & slash revisions. The entire genre would not exist if it were not for this early 2000s game!

1. World Design

diff --git a/test/webmention/receive-process.test.js b/test/webmention/receive-process.test.js index a46897c..014fbc6 100644 --- a/test/webmention/receive-process.test.js +++ b/test/webmention/receive-process.test.js @@ -6,7 +6,7 @@ const { rmdir } = require('./../utils') jest.mock('got'); const md5 = require('md5') const { receive } = require('../../src/webmention/receive') -const dumpdir = 'data' +const dumpdir = 'data/brainbaking.com' const MockDate = require('mockdate') describe("receive webmention process tests happy path", () => { @@ -20,14 +20,18 @@ describe("receive webmention process tests happy path", () => { MockDate.set('2020-01-01') }) - test("receive saves a JSON file of indieweb-metadata if all is valid", async () => { - await receive({ - source: "valid-indieweb-source.html", - target: "valid-indieweb-target.html" - }) + function asFilename(body) { + return `${dumpdir}/` + md5(`source=${body.source},target=${body.target}`) + } - const filename = md5(`source=valid-indieweb-source.html,target=valid-indieweb-target.html`) - const result = await fsp.readFile(`data/${filename}.json`, 'utf-8') + test("receive saves a JSON file of indieweb-metadata if all is valid", async () => { + const body = { + source: "https://brainbaking.com/valid-indieweb-source.html", + target: "https://brainbaking.com/valid-indieweb-target.html" + } + await receive(body) + + const result = await fsp.readFile(`${asFilename(body)}.json`, 'utf-8') const data = JSON.parse(result) expect(data).toEqual({ @@ -36,38 +40,74 @@ describe("receive webmention process tests happy path", () => { picture: "https://brainbaking.com//img/avatar.jpg" }, content: "This is cool, I just found out about valid indieweb target - so cool...", - source: "valid-indieweb-source.html", - target: "valid-indieweb-target.html", + source: body.source, + target: body.target, + published: "2021-03-06T12:41:00" + }) + }) + + test("receive saves a JSON file of indieweb-metadata with summary as content if present", async () => { + const body = { + source: "https://brainbaking.com/valid-indieweb-source-with-summary.html", + target: "https://brainbaking.com/valid-indieweb-target.html" + } + await receive(body) + + const result = await fsp.readFile(`${asFilename(body)}.json`, 'utf-8') + const data = JSON.parse(result) + + expect(data).toEqual({ + author: { + name: "Wouter Groeneveld", + picture: "https://brainbaking.com//img/avatar.jpg" + }, + content: "This is cool, this is a summary!", + source: body.source, + target: body.target, published: "2021-03-06T12:41:00" }) }) test("receive saves a JSON file of non-indieweb-data such as title if all is valid", async () => { - await receive({ - source: "valid-nonindieweb-source.html", - target: "valid-indieweb-target.html" - }) + const body = { + source: "https://brainbaking.com/valid-nonindieweb-source.html", + target: "https://brainbaking.com/valid-indieweb-target.html" + } + await receive(body) - const filename = md5(`source=valid-nonindieweb-source.html,target=valid-indieweb-target.html`) - const result = await fsp.readFile(`data/${filename}.json`, 'utf-8') + const result = await fsp.readFile(`${asFilename(body)}.json`, 'utf-8') const data = JSON.parse(result) expect(data).toEqual({ author: { - name: "valid-nonindieweb-source.html", + name: "https://brainbaking.com/valid-nonindieweb-source.html", }, content: "Diablo 2 Twenty Years Later: A Retrospective | Jefklaks Codex", - source: "valid-nonindieweb-source.html", - target: "valid-indieweb-target.html", + source: body.source, + target: body.target, published: "2020-01-01T01:00:00" }) }) test("receive a target that does not point to the source does nothing", async () => { - await receive({ - source: "valid-indieweb-source.html", - target: "valid-indieweb-source.html" - }) + const body = { + source: "https://brainbaking.com/valid-indieweb-source.html", + target: "https://brainbaking.com/valid-indieweb-source.html" + } + await receive(body) + + const data = fs.readdirSync(dumpdir) + expect(data.length).toBe(0) + }) + + test("receive a source that does not exist should also delete older webmention files", async () => { + const body = { + source: "https://wubanga2001.boom/lolz", + target: "https://brainbaking.com/valid-indieweb-source.html" + } + + await fsp.writeFile(`${asFilename(body)}.json`, JSON.stringify({ lolz: "aha" }), 'utf-8') + await receive(body) const data = fs.readdirSync(dumpdir) expect(data.length).toBe(0)