Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 0 additions & 31 deletions helpers/mock-agent/endpoint-posts.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,37 +35,6 @@ export function mockClient() {
})
.persist();

// Get source information for all items from external micropub endpoint
agent
.get(micropubEndpointOrigin)
.intercept({
path: "/?q=source",
})
.reply(200, {
items: [
{
type: ["h-entry"],
properties: {
uid: ["123"],
name: ["Foobar"],
"post-type": ["note"],
published: ["2024-12-21"],
url: [postOrigin],
},
},
{
type: ["h-entry"],
properties: {
uid: ["401"],
name: ["401"],
"post-type": ["note"],
url: [postBadOrigin],
},
},
],
})
.persist();

// Upload file to external micropub endpoint
agent
.get(micropubEndpointOrigin)
Expand Down
6 changes: 1 addition & 5 deletions packages/endpoint-posts/lib/middleware/post-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,7 @@ export const postData = {
const { action, uid } = request.params;
const { access_token, scope } = request.session;

const properties = await getPostProperties(
uid,
application.micropubEndpoint,
access_token,
);
const properties = await getPostProperties(uid, application);

if (!properties) {
throw IndiekitError.notFound(response.locals.__("NotFoundError.page"));
Expand Down
37 changes: 20 additions & 17 deletions packages/endpoint-posts/lib/utils.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { Buffer } from "node:buffer";

import { sanitise, ISO_6709_RE } from "@indiekit/util";
import { mf2tojf2 } from "@paulrobertlloyd/mf2tojf2";
import { getObjectId, sanitise, ISO_6709_RE } from "@indiekit/util";
import formatcoords from "formatcoords";

import { endpoint } from "./endpoint.js";
import { statusTypes } from "./status-types.js";

/**
Expand Down Expand Up @@ -151,25 +149,30 @@ export const getPostName = (publication, properties) => {
};

/**
* Query Micropub endpoint for post data
* @param {string} uid - Item UID
* @param {string} micropubEndpoint - Micropub endpoint
* @param {string} accessToken - Access token
* @returns {Promise<object>} JF2 properties
* Get post properties
* @param {string} uid - Post ID
* @param {object} application - Application configuration
* @returns {Promise<object|false>} JF2 properties, else false if not found
*/
export const getPostProperties = async (uid, micropubEndpoint, accessToken) => {
const micropubUrl = new URL(micropubEndpoint);
micropubUrl.searchParams.append("q", "source");
export const getPostProperties = async (uid, application) => {
const postsCollection = application?.collections?.get("posts");
if (!postsCollection) {
return false;
}

const micropubResponse = await endpoint.get(micropubUrl.href, accessToken);
let postData;
try {
postData = await postsCollection.findOne({ _id: getObjectId(uid) });
} catch {
// Not a valid ObjectId
return false;
}

if (micropubResponse?.items?.length > 0) {
const jf2 = mf2tojf2(micropubResponse);
const items = jf2.children || [jf2];
return items.find((item) => item.uid === uid);
if (!postData?.properties) {
return false;
}

return false;
return { ...postData.properties, uid: postData._id.toString() };
};

/**
Expand Down
29 changes: 26 additions & 3 deletions packages/endpoint-posts/test/integration/200-get-delete.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,41 @@
import { strict as assert } from "node:assert";
import { after, describe, it } from "node:test";

import { testDatabase } from "@indiekit-test/database";
import { mockAgent } from "@indiekit-test/mock-agent";
import { postData } from "@indiekit-test/post-data";
import { testServer } from "@indiekit-test/server";
import { testCookie } from "@indiekit-test/session";
import { JSDOM } from "jsdom";
import supertest from "supertest";

await mockAgent("endpoint-posts");
const { client, mongoServer, mongoUri } = await testDatabase();
const server = await testServer({
application: { micropubEndpoint: "https://micropub-endpoint.example" },
application: {
micropubEndpoint: "https://micropub-endpoint.example",
mongodbUrl: mongoUri,
},
});
const request = supertest.agent(server);

const { insertedId } = await client
.db("indiekit")
.collection("posts")
.insertOne({
...postData,
properties: {
...postData.properties,
name: "Foobar",
url: "https://website.example/foobar",
},
});
const uid = insertedId.toString();

describe("endpoint-posts GET /posts/:uid/delete", () => {
it("Gets delete confirmation page", async () => {
const response = await request
.get(`/posts/123/delete`)
.get(`/posts/${uid}/delete`)
.set("cookie", testCookie());
const dom = new JSDOM(response.text);
const result = dom.window.document.querySelector("title").textContent;
Expand All @@ -27,5 +46,9 @@ describe("endpoint-posts GET /posts/:uid/delete", () => {
);
});

after(() => server.close());
after(async () => {
await client.close();
await mongoServer.stop();
server.close((error) => process.exit(error ? 1 : 0));
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { strict as assert } from "node:assert";
import { after, describe, it } from "node:test";

import { testDatabase } from "@indiekit-test/database";
import { testServer } from "@indiekit-test/server";
import { testCookie } from "@indiekit-test/session";
import { JSDOM } from "jsdom";
import supertest from "supertest";

const { client, mongoServer, mongoUri } = await testDatabase();
const server = await testServer({
application: { mongodbUrl: mongoUri },
});
const request = supertest.agent(server);

// Cursor pagination returns 40 posts by default; the oldest post here is
// the 41st most recent, so it never appears in a `?q=source` listing
const { insertedIds } = await client
.db("indiekit")
.collection("posts")
.insertMany(
Array.from({ length: 41 }, (_, index) => ({
path: `post-${index}.md`,
properties: {
name: `Post ${index}`,
"post-status": "published",
"post-type": "note",
published: new Date(2020, 0, 1 + index).toISOString(),
url: `https://website.example/post-${index}`,
},
})),
);
const oldestUid = insertedIds[0].toString();

describe("endpoint-posts GET /posts/:uid", () => {
it("Returns post that is not among the 40 most recent", async () => {
const response = await request
.get(`/posts/${oldestUid}`)
.set("cookie", testCookie());
const dom = new JSDOM(response.text);
const result = dom.window.document.querySelector("title").textContent;

assert.equal(response.status, 200);
assert.equal(result, "Post 0 - Test configuration");
});

after(async () => {
await client.close();
await mongoServer.stop();
server.close((error) => process.exit(error ? 1 : 0));
});
});
31 changes: 27 additions & 4 deletions packages/endpoint-posts/test/integration/200-post.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,51 @@
import { strict as assert } from "node:assert";
import { after, describe, it } from "node:test";

import { testDatabase } from "@indiekit-test/database";
import { mockAgent } from "@indiekit-test/mock-agent";
import { postData } from "@indiekit-test/post-data";
import { testServer } from "@indiekit-test/server";
import { testCookie } from "@indiekit-test/session";
import { JSDOM } from "jsdom";
import supertest from "supertest";

await mockAgent("endpoint-posts");
const { client, mongoServer, mongoUri } = await testDatabase();
const server = await testServer({
application: { micropubEndpoint: "https://micropub-endpoint.example" },
application: {
micropubEndpoint: "https://micropub-endpoint.example",
mongodbUrl: mongoUri,
},
});
const request = supertest.agent(server);

const { insertedId } = await client
.db("indiekit")
.collection("posts")
.insertOne({
...postData,
properties: {
...postData.properties,
name: "Foobar",
url: "https://website.example/foobar",
},
});
const uid = insertedId.toString();

describe("endpoint-posts GET /posts/:uid", () => {
it("Returns published post", async () => {
const response = await request
.get(`/posts/123`)
.get(`/posts/${uid}`)
.set("cookie", testCookie());
const dom = new JSDOM(response.text);
const result = dom.window.document.querySelector("title").textContent;

assert.equal(result, `Foobar - Test configuration`);
assert.equal(result, "Foobar - Test configuration");
});

after(() => server.close());
after(async () => {
await client.close();
await mongoServer.stop();
server.close((error) => process.exit(error ? 1 : 0));
});
});
29 changes: 26 additions & 3 deletions packages/endpoint-posts/test/integration/302-get-delete.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,49 @@
import { strict as assert } from "node:assert";
import { after, describe, it } from "node:test";

import { testDatabase } from "@indiekit-test/database";
import { mockAgent } from "@indiekit-test/mock-agent";
import { postData } from "@indiekit-test/post-data";
import { testServer } from "@indiekit-test/server";
import { testCookie } from "@indiekit-test/session";
import supertest from "supertest";

await mockAgent("endpoint-posts");
const { client, mongoServer, mongoUri } = await testDatabase();
const server = await testServer({
application: { micropubEndpoint: "https://micropub-endpoint.example" },
application: {
micropubEndpoint: "https://micropub-endpoint.example",
mongodbUrl: mongoUri,
},
});
const request = supertest.agent(server);

const { insertedId } = await client
.db("indiekit")
.collection("posts")
.insertOne({
...postData,
properties: {
...postData.properties,
name: "Foobar",
url: "https://website.example/foobar",
},
});
const uid = insertedId.toString();

describe("endpoint-posts GET /posts/:uid/delete", () => {
it("Redirects to post page if no delete permissions", async () => {
const result = await request
.get(`/posts/123/delete`)
.get(`/posts/${uid}/delete`)
.set("cookie", testCookie({ scope: "create" }));

assert.equal(result.status, 302);
assert.match(result.text, /Found. Redirecting to \/posts\/(.*)/);
});

after(() => server.close());
after(async () => {
await client.close();
await mongoServer.stop();
server.close((error) => process.exit(error ? 1 : 0));
});
});
29 changes: 26 additions & 3 deletions packages/endpoint-posts/test/integration/302-post-delete.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,50 @@
import { strict as assert } from "node:assert";
import { after, describe, it } from "node:test";

import { testDatabase } from "@indiekit-test/database";
import { mockAgent } from "@indiekit-test/mock-agent";
import { postData } from "@indiekit-test/post-data";
import { testServer } from "@indiekit-test/server";
import { testCookie } from "@indiekit-test/session";
import supertest from "supertest";

await mockAgent("endpoint-posts");
const { client, mongoServer, mongoUri } = await testDatabase();
const server = await testServer({
application: { micropubEndpoint: "https://micropub-endpoint.example" },
application: {
micropubEndpoint: "https://micropub-endpoint.example",
mongodbUrl: mongoUri,
},
});
const request = supertest.agent(server);

const { insertedId } = await client
.db("indiekit")
.collection("posts")
.insertOne({
...postData,
properties: {
...postData.properties,
name: "Foobar",
url: "https://website.example/foobar",
},
});
const uid = insertedId.toString();

describe("endpoint-posts POST /posts/:uid/delete", () => {
it("Deletes file and redirects to posts page", async () => {
const result = await request
.post(`/posts/123/delete`)
.post(`/posts/${uid}/delete`)
.set("cookie", testCookie())
.send({ url: "https://website.example/foobar" });

assert.equal(result.status, 302);
assert.match(result.text, /Found. Redirecting to \/posts\?success/);
});

after(() => server.close());
after(async () => {
await client.close();
await mongoServer.stop();
server.close((error) => process.exit(error ? 1 : 0));
});
});
Loading
Loading