-
-
Notifications
You must be signed in to change notification settings - Fork 37
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(endpoint-posts): split post management into new plug-in
- Loading branch information
1 parent
b63ef8d
commit cb1bf6c
Showing
18 changed files
with
449 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# @indiekit/endpoint-posts | ||
|
||
Post management endpoint for Indiekit. | ||
|
||
## Installation | ||
|
||
`npm i @indiekit/endpoint-posts` | ||
|
||
## Usage | ||
|
||
Add `@indiekit/endpoint-posts` to your list of plug-ins, specifying options as required: | ||
|
||
```jsonc | ||
{ | ||
"plugins": ["@indiekit/endpoint-posts"], | ||
"@indiekit/endpoint-posts": { | ||
"mountPath": "/artikel" // de-DE | ||
} | ||
} | ||
``` | ||
|
||
## Options | ||
|
||
| Option | Type | Description | | ||
| :---------- | :------- | :-------------------------------------------------------------- | | ||
| `mountPath` | `string` | Path to management interface. _Optional_, defaults to `/posts`. | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import express from "express"; | ||
import { postController } from "./lib/controllers/post.js"; | ||
import { postsController } from "./lib/controllers/posts.js"; | ||
|
||
const defaults = { | ||
mountPath: "/posts", | ||
}; | ||
|
||
export const PostsEndpoint = class { | ||
constructor(options = {}) { | ||
this.id = "endpoint-posts"; | ||
this.meta = import.meta; | ||
this.name = "Post management endpoint"; | ||
this.options = { ...defaults, ...options }; | ||
this.mountPath = this.options.mountPath; | ||
this._router = express.Router(); // eslint-disable-line new-cap | ||
} | ||
|
||
navigationItems(application) { | ||
if (application.hasDatabase) { | ||
return { | ||
href: this.options.mountPath, | ||
text: "posts.title", | ||
}; | ||
} | ||
} | ||
|
||
get routes() { | ||
const router = this._router; | ||
|
||
router.get("/", postsController); | ||
router.get("/:id", postController); | ||
|
||
return router; | ||
} | ||
|
||
init() { | ||
return true; | ||
} | ||
}; | ||
|
||
export default PostsEndpoint; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { mf2tojf2 } from "@paulrobertlloyd/mf2tojf2"; | ||
import httpError from "http-errors"; | ||
|
||
/** | ||
* View previously published post | ||
* | ||
* @param {object} request HTTP request | ||
* @param {object} response HTTP response | ||
* @param {Function} next Next middleware callback | ||
* @returns {object} HTTP response | ||
*/ | ||
export const postController = async (request, response, next) => { | ||
try { | ||
const { publication } = request.app.locals; | ||
const { id } = request.params; | ||
const url = Buffer.from(id, "base64").toString("utf8"); | ||
|
||
const parameters = new URLSearchParams({ | ||
q: "source", | ||
url, | ||
}).toString(); | ||
|
||
const endpointResponse = await fetch( | ||
`${publication.micropubEndpoint}?${parameters}`, | ||
{ | ||
headers: { | ||
accept: "application/json", | ||
// TODO: Third-party media endpoint may require a separate token | ||
authorization: `Bearer ${request.session.token}`, | ||
}, | ||
} | ||
); | ||
|
||
const body = await endpointResponse.json(); | ||
|
||
if (!endpointResponse.ok) { | ||
throw httpError( | ||
endpointResponse.status, | ||
body.error_description || endpointResponse.statusText | ||
); | ||
} | ||
|
||
const post = mf2tojf2(body); | ||
|
||
response.render("post", { | ||
title: post.name, | ||
post, | ||
parent: response.__("posts.posts.title"), | ||
}); | ||
} catch (error) { | ||
next(error); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import { Buffer } from "node:buffer"; | ||
import { mf2tojf2 } from "@paulrobertlloyd/mf2tojf2"; | ||
import httpError from "http-errors"; | ||
import { fetch } from "undici"; | ||
|
||
/** | ||
* List previously published posts | ||
* | ||
* @param {object} request HTTP request | ||
* @param {object} response HTTP response | ||
* @param {Function} next Next middleware callback | ||
* @returns {object} HTTP response | ||
*/ | ||
export const postsController = async (request, response, next) => { | ||
try { | ||
const { publication } = request.app.locals; | ||
|
||
let { page, limit, offset, success } = request.query; | ||
page = Number.parseInt(page, 10) || 1; | ||
limit = Number.parseInt(limit, 10) || 12; | ||
offset = Number.parseInt(offset, 10) || (page - 1) * limit; | ||
|
||
const parameters = new URLSearchParams({ | ||
q: "source", | ||
page, | ||
limit, | ||
offset, | ||
}).toString(); | ||
|
||
const endpointResponse = await fetch( | ||
`${publication.micropubEndpoint}?${parameters}`, | ||
{ | ||
headers: { | ||
accept: "application/json", | ||
// TODO: Third-party media endpoint may require a separate token | ||
authorization: `Bearer ${request.session.token}`, | ||
}, | ||
} | ||
); | ||
|
||
const body = await endpointResponse.json(); | ||
|
||
if (!endpointResponse.ok) { | ||
throw httpError( | ||
endpointResponse.status, | ||
body.error_description || endpointResponse.statusText | ||
); | ||
} | ||
|
||
let posts; | ||
if (body?.items?.length > 0) { | ||
const mf2 = mf2tojf2(body); | ||
const items = mf2.children ? mf2.children : [mf2]; | ||
posts = items.map((item) => { | ||
item.id = Buffer.from(item.url).toString("base64"); | ||
return item; | ||
}); | ||
} | ||
|
||
response.render("posts", { | ||
title: response.__("posts.posts.title"), | ||
posts, | ||
page, | ||
limit, | ||
count: await publication.media.countDocuments(), | ||
parentUrl: request.baseUrl + request.path, | ||
success, | ||
}); | ||
} catch (error) { | ||
next(error); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
{ | ||
"posts": { | ||
"post": { | ||
"properties": "Eigenschaften" | ||
}, | ||
"posts": { | ||
"none": "Keine Beiträge", | ||
"title": "Veröffentlichte Beiträge" | ||
}, | ||
"title": "Beiträge" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
{ | ||
"posts": { | ||
"post": { | ||
"properties": "Properties" | ||
}, | ||
"posts": { | ||
"title": "Published posts", | ||
"none": "No posts" | ||
}, | ||
"title": "Posts" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
{ | ||
"posts": { | ||
"post": { | ||
"properties": "Propiedades" | ||
}, | ||
"posts": { | ||
"none": "No hay publicaciones", | ||
"title": "Publicaciones publicadas" | ||
}, | ||
"title": "Publicaciones" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
{ | ||
"posts": { | ||
"post": { | ||
"properties": "Propriétés" | ||
}, | ||
"posts": { | ||
"none": "Pas d'articles", | ||
"title": "Articles publiés" | ||
}, | ||
"title": "Articles" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
{ | ||
"posts": { | ||
"post": { | ||
"properties": "Properti" | ||
}, | ||
"posts": { | ||
"none": "Tidak ada postingan", | ||
"title": "Postingan yang diterbitkan" | ||
}, | ||
"title": "Postingan" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
{ | ||
"posts": { | ||
"post": { | ||
"properties": "Eigenschappen" | ||
}, | ||
"posts": { | ||
"none": "Geen posts", | ||
"title": "Gepubliceerde berichten" | ||
}, | ||
"title": "Berichten" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
{ | ||
"posts": { | ||
"post": { | ||
"properties": "Propriedades" | ||
}, | ||
"posts": { | ||
"none": "Nenhuma postagem", | ||
"title": "Postagens publicadas" | ||
}, | ||
"title": "Postagens" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
{ | ||
"name": "@indiekit/endpoint-posts", | ||
"version": "1.0.0-alpha.5", | ||
"description": "Post management endpoint for Indiekit", | ||
"keywords": [ | ||
"indiekit", | ||
"indiekit-plugin", | ||
"indieweb" | ||
], | ||
"homepage": "https://getindiekit.com", | ||
"author": { | ||
"name": "Paul Robert Lloyd", | ||
"url": "https://paulrobertlloyd.com" | ||
}, | ||
"license": "MIT", | ||
"engines": { | ||
"node": ">=18" | ||
}, | ||
"type": "module", | ||
"main": "index.js", | ||
"files": [ | ||
"lib", | ||
"locales", | ||
"views", | ||
"index.js" | ||
], | ||
"bugs": { | ||
"url": "https://github.com/getindiekit/indiekit/issues" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/getindiekit/indiekit.git", | ||
"directory": "packages/endpoint-posts" | ||
}, | ||
"dependencies": { | ||
"@paulrobertlloyd/mf2tojf2": "^1.0.0", | ||
"express": "^4.17.1", | ||
"http-errors": "^2.0.0", | ||
"undici": "^5.2.0" | ||
}, | ||
"publishConfig": { | ||
"access": "public" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import process from "node:process"; | ||
import test from "ava"; | ||
import nock from "nock"; | ||
import { JSDOM } from "jsdom"; | ||
import { testServer } from "@indiekit-test/server"; | ||
|
||
test("Views previously published post", async (t) => { | ||
nock("https://api.github.com") | ||
.put((uri) => uri.includes("foobar.md")) | ||
.reply(200); | ||
|
||
// Create post | ||
const request = await testServer(); | ||
await request | ||
.post("/micropub") | ||
.auth(process.env.TEST_TOKEN, { type: "bearer" }) | ||
.set("accept", "application/json") | ||
.send("h=entry") | ||
.send("name=Foobar"); | ||
|
||
// Get post data by parsing list of posts and getting values from link | ||
const postsResponse = await request.get("/posts"); | ||
const postsDom = new JSDOM(postsResponse.text); | ||
const postLink = postsDom.window.document.querySelector(".file-list a"); | ||
const postName = postLink.textContent; | ||
const postId = postLink.href.split("/").pop(); | ||
|
||
// Visit post page | ||
const postResponse = await request.get(`/posts/${postId}`); | ||
const postDom = new JSDOM(postResponse.text); | ||
|
||
const result = postDom.window.document; | ||
|
||
t.is( | ||
result.querySelector("title").textContent, | ||
`${postName} - Test configuration` | ||
); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import test from "ava"; | ||
import { JSDOM } from "jsdom"; | ||
import { testServer } from "@indiekit-test/server"; | ||
import { cookie } from "@indiekit-test/session"; | ||
|
||
test("Returns list of previously published posts", async (t) => { | ||
const request = await testServer(); | ||
const response = await request.get("/posts").set("cookie", [cookie]); | ||
const dom = new JSDOM(response.text); | ||
|
||
const result = dom.window.document; | ||
|
||
t.is( | ||
result.querySelector("title").textContent, | ||
"Published posts - Test configuration" | ||
); | ||
}); |
Oops, something went wrong.