From 480af6ccd7a5540e0b23b2bb8a26b144039f859f Mon Sep 17 00:00:00 2001 From: Paul Robert Lloyd Date: Sat, 23 Nov 2024 13:24:19 +0000 Subject: [PATCH 1/2] feat: addCollection API method --- .../lib/controllers/json-feed.js | 4 +- packages/endpoint-media/index.js | 1 + .../endpoint-media/lib/controllers/query.js | 9 +-- packages/endpoint-media/lib/media-data.js | 15 ++--- .../endpoint-media/lib/media-type-count.js | 8 +-- packages/endpoint-media/lib/utils.js | 3 +- .../endpoint-media/test/unit/media-data.js | 8 ++- .../test/unit/media-type-count.js | 3 +- packages/endpoint-micropub/index.js | 1 + .../lib/controllers/query.js | 9 +-- packages/endpoint-micropub/lib/post-data.js | 18 +++--- .../endpoint-micropub/lib/post-type-count.js | 8 +-- packages/endpoint-micropub/lib/utils.js | 3 +- .../endpoint-micropub/test/unit/post-data.js | 8 ++- .../test/unit/post-type-count.js | 3 +- .../lib/controllers/syndicate.js | 6 +- packages/endpoint-syndicate/lib/utils.js | 9 ++- .../endpoint-syndicate/test/unit/utils.js | 9 ++- packages/indiekit/index.js | 18 +++--- packages/indiekit/lib/controllers/feed.js | 5 +- packages/indiekit/lib/middleware/locals.js | 12 +++- packages/indiekit/test/index.js | 60 ++++++++----------- packages/indiekit/test/server.js | 49 +++++++++++++++ 23 files changed, 165 insertions(+), 104 deletions(-) create mode 100644 packages/indiekit/test/server.js diff --git a/packages/endpoint-json-feed/lib/controllers/json-feed.js b/packages/endpoint-json-feed/lib/controllers/json-feed.js index 1138fa506..18c6bbbcd 100644 --- a/packages/endpoint-json-feed/lib/controllers/json-feed.js +++ b/packages/endpoint-json-feed/lib/controllers/json-feed.js @@ -3,7 +3,9 @@ import { jsonFeed } from "../json-feed.js"; export const jsonFeedController = async (request, response) => { const { application } = request.app.locals; const feedUrl = new URL(request.originalUrl, application.url).href; - const posts = await application.posts + + const postsCollection = application?.collections?.get("posts"); + const posts = await postsCollection .find({ "properties.post-status": { $ne: "draft", diff --git a/packages/endpoint-media/index.js b/packages/endpoint-media/index.js index 6beef4db3..bfa2cc402 100644 --- a/packages/endpoint-media/index.js +++ b/packages/endpoint-media/index.js @@ -29,6 +29,7 @@ export default class MediaEndpoint { } init(Indiekit) { + Indiekit.addCollection("media"); Indiekit.addEndpoint(this); // Use private value to register Micropub media endpoint path diff --git a/packages/endpoint-media/lib/controllers/query.js b/packages/endpoint-media/lib/controllers/query.js index 9a89160d0..b324c70b6 100644 --- a/packages/endpoint-media/lib/controllers/query.js +++ b/packages/endpoint-media/lib/controllers/query.js @@ -8,6 +8,7 @@ import { getMediaProperties } from "../utils.js"; */ export const queryController = async (request, response, next) => { const { application } = request.app.locals; + const mediaCollection = application.collections.get("media"); try { const limit = Number(request.query.limit) || 0; @@ -25,8 +26,8 @@ export const queryController = async (request, response, next) => { // Return properties for a given URL let mediaData; - if (application.media) { - mediaData = await application.media.findOne({ + if (mediaCollection) { + mediaData = await mediaCollection.findOne({ "properties.url": url, }); } @@ -46,8 +47,8 @@ export const queryController = async (request, response, next) => { hasPrev: false, }; - if (application.media) { - cursor = await getCursor(application.media, after, before, limit); + if (mediaCollection) { + cursor = await getCursor(mediaCollection, after, before, limit); } response.json({ diff --git a/packages/endpoint-media/lib/media-data.js b/packages/endpoint-media/lib/media-data.js index 58660ab1a..5b48b1e13 100644 --- a/packages/endpoint-media/lib/media-data.js +++ b/packages/endpoint-media/lib/media-data.js @@ -17,7 +17,7 @@ export const mediaData = { async create(application, publication, file) { debug(`Create %O`, { file }); - const { media, timeZone } = application; + const { timeZone } = application; const { me, postTypes } = publication; // Media properties @@ -59,9 +59,10 @@ export const mediaData = { const mediaData = { path, properties }; // Add data to media collection (or replace existing if present) - if (media) { + const mediaCollection = application?.collections?.get("media"); + if (mediaCollection) { const query = { "properties.url": properties.url }; - await media.replaceOne(query, mediaData, { upsert: true }); + await mediaCollection.replaceOne(query, mediaData, { upsert: true }); } return mediaData; @@ -76,10 +77,10 @@ export const mediaData = { async read(application, url) { debug(`Read ${url}`); - const { media } = application; const query = { "properties.url": url }; - const mediaData = await media.findOne(query); + const mediaCollection = application?.collections?.get("media"); + const mediaData = await mediaCollection.findOne(query); if (!mediaData) { throw IndiekitError.notFound(url); } @@ -96,10 +97,10 @@ export const mediaData = { async delete(application, url) { debug(`Delete ${url}`); - const { media } = application; const query = { "properties.url": url }; - const result = await media.deleteOne(query); + const mediaCollection = application?.collections?.get("media"); + const result = await mediaCollection.deleteOne(query); if (result?.deletedCount === 1) { return true; } diff --git a/packages/endpoint-media/lib/media-type-count.js b/packages/endpoint-media/lib/media-type-count.js index 91e5ffc39..216726669 100644 --- a/packages/endpoint-media/lib/media-type-count.js +++ b/packages/endpoint-media/lib/media-type-count.js @@ -1,12 +1,12 @@ export const mediaTypeCount = { /** * Count the number of media of a given type - * @param {object} application - Application configuration + * @param {object} postsCollection - Posts database collection * @param {object} properties - Media properties * @returns {Promise} Media count */ - async get(application, properties) { - if (!application.posts || !application.posts.count()) { + async get(postsCollection, properties) { + if (!postsCollection || !postsCollection.count()) { console.warn("No database configuration provided"); console.info( "See https://getindiekit.com/configuration/application/#mongodburl", @@ -20,7 +20,7 @@ export const mediaTypeCount = { const startDate = new Date(new Date(properties.published).toDateString()); const endDate = new Date(startDate); endDate.setDate(endDate.getDate() + 1); - const response = await application.posts + const response = await postsCollection .aggregate([ { $addFields: { diff --git a/packages/endpoint-media/lib/utils.js b/packages/endpoint-media/lib/utils.js index 13edd0efb..447bc5aa0 100644 --- a/packages/endpoint-media/lib/utils.js +++ b/packages/endpoint-media/lib/utils.js @@ -48,7 +48,8 @@ export const renderPath = async (path, properties, application) => { tokens.D60 = newbase60.DateToSxg(dateObject); // Add count of media type for the day - const count = await mediaTypeCount.get(application, properties); + const postsCollection = application?.collections?.get("posts"); + const count = await mediaTypeCount.get(postsCollection, properties); tokens.n = count + 1; // Add file extension token diff --git a/packages/endpoint-media/test/unit/media-data.js b/packages/endpoint-media/test/unit/media-data.js index 651b50227..705e82763 100644 --- a/packages/endpoint-media/test/unit/media-data.js +++ b/packages/endpoint-media/test/unit/media-data.js @@ -9,7 +9,6 @@ describe("endpoint-media/lib/media-data", async () => { let application; let publication; const { client, database, mongoServer } = await testDatabase(); - const media = database.collection("media"); const file = { data: getFixture("file-types/photo.jpg", false), name: "photo.jpg", @@ -22,7 +21,8 @@ describe("endpoint-media/lib/media-data", async () => { }); beforeEach(async () => { - await media.insertOne({ + const mediaCollection = database.collection("media"); + await mediaCollection.insertOne({ path: "photo.jpg", properties: { "media-type": "photo", @@ -31,8 +31,10 @@ describe("endpoint-media/lib/media-data", async () => { }); const config = await testConfig({ usePostTypes: true }); + const collections = new Map(); + collections.set("media", mediaCollection); - application = { media }; + application = { collections }; publication = config.publication; }); diff --git a/packages/endpoint-media/test/unit/media-type-count.js b/packages/endpoint-media/test/unit/media-type-count.js index e590fb2a8..5d0283d08 100644 --- a/packages/endpoint-media/test/unit/media-type-count.js +++ b/packages/endpoint-media/test/unit/media-type-count.js @@ -5,7 +5,6 @@ import { mediaTypeCount } from "../../lib/media-type-count.js"; const { client, database, mongoServer } = await testDatabase(); const posts = database.collection("posts"); -const application = { posts }; describe("endpoint-media/lib/media-type-count", () => { before(async () => { @@ -25,7 +24,7 @@ describe("endpoint-media/lib/media-type-count", () => { }); it("Counts the number of media of a given type", async () => { - const result = await mediaTypeCount.get(application, { + const result = await mediaTypeCount.get(posts, { type: "entry", published: new Date(), name: "Bar", diff --git a/packages/endpoint-micropub/index.js b/packages/endpoint-micropub/index.js index 9881b953a..f40a83a1c 100644 --- a/packages/endpoint-micropub/index.js +++ b/packages/endpoint-micropub/index.js @@ -20,6 +20,7 @@ export default class MicropubEndpoint { } init(Indiekit) { + Indiekit.addCollection("posts"); Indiekit.addEndpoint(this); // Use private value to register Micropub endpoint path diff --git a/packages/endpoint-micropub/lib/controllers/query.js b/packages/endpoint-micropub/lib/controllers/query.js index fa951be98..b73f1bdee 100644 --- a/packages/endpoint-micropub/lib/controllers/query.js +++ b/packages/endpoint-micropub/lib/controllers/query.js @@ -9,6 +9,7 @@ import { getMf2Properties, jf2ToMf2 } from "../mf2.js"; */ export const queryController = async (request, response, next) => { const { application, publication } = request.app.locals; + const postsCollection = application?.collections?.get("posts"); try { const config = getConfig(application, publication); @@ -40,8 +41,8 @@ export const queryController = async (request, response, next) => { // Return mf2 for a given URL (optionally filtered by properties) let postData; - if (application.posts) { - postData = await application.posts.findOne({ + if (postsCollection) { + postData = await postsCollection.findOne({ "properties.url": url, }); } @@ -62,8 +63,8 @@ export const queryController = async (request, response, next) => { hasPrev: false, }; - if (application.posts) { - cursor = await getCursor(application.posts, after, before, limit); + if (postsCollection) { + cursor = await getCursor(postsCollection, after, before, limit); } const items = []; diff --git a/packages/endpoint-micropub/lib/post-data.js b/packages/endpoint-micropub/lib/post-data.js index 98a36fae1..cf2c8baa3 100644 --- a/packages/endpoint-micropub/lib/post-data.js +++ b/packages/endpoint-micropub/lib/post-data.js @@ -84,10 +84,10 @@ export const postData = { async read(application, url) { debug(`Read ${url}`); - const { posts } = application; const query = { "properties.url": url }; + const postsCollection = application?.collections?.get("posts"); - const postData = await posts.findOne(query); + const postData = await postsCollection.findOne(query); if (!postData) { throw IndiekitError.notFound(url); } @@ -108,8 +108,9 @@ export const postData = { async update(application, publication, url, operation) { debug(`Update ${url} %O`, { operation }); - const { posts, timeZone } = application; + const { timeZone } = application; const { me, postTypes } = publication; + const postsCollection = application?.collections?.get("posts"); // Read properties let { path: _originalPath, properties } = await this.read(application, url); @@ -171,7 +172,7 @@ export const postData = { // Update data in posts collection const postData = { _originalPath, path, properties }; const query = { "properties.url": url }; - await posts.replaceOne(query, postData); + await postsCollection.replaceOne(query, postData); return postData; }, @@ -188,8 +189,9 @@ export const postData = { async delete(application, publication, url) { debug(`Delete ${url}`); - const { posts, timeZone } = application; + const { timeZone } = application; const { postTypes } = publication; + const postsCollection = application?.collections?.get("posts"); // Read properties const { properties } = await this.read(application, url); @@ -222,7 +224,7 @@ export const postData = { // Update data in posts collection const postData = { path, properties, _deletedProperties }; const query = { "properties.url": url }; - await posts.replaceOne(query, postData); + await postsCollection.replaceOne(query, postData); return postData; }, @@ -240,8 +242,8 @@ export const postData = { async undelete(application, publication, url, draftMode) { debug(`Undelete ${url} %O`, { draftMode }); - const { posts } = application; const { postTypes } = publication; + const postsCollection = application?.collections?.get("posts"); // Read deleted properties const { _deletedProperties } = await this.read(application, url); @@ -270,7 +272,7 @@ export const postData = { // Update data in posts collection const postData = { path, properties }; const query = { "properties.url": url }; - await posts.replaceOne(query, postData); + await postsCollection.replaceOne(query, postData); return postData; }, diff --git a/packages/endpoint-micropub/lib/post-type-count.js b/packages/endpoint-micropub/lib/post-type-count.js index 373893e15..98e1a1464 100644 --- a/packages/endpoint-micropub/lib/post-type-count.js +++ b/packages/endpoint-micropub/lib/post-type-count.js @@ -3,12 +3,12 @@ import { getObjectId } from "@indiekit/util"; export const postTypeCount = { /** * Count the number of posts of a given type - * @param {object} application - Application configuration + * @param {object} postsCollection - Posts database collection * @param {object} properties - JF2 properties * @returns {Promise} Post count */ - async get(application, properties) { - if (!application.posts || !application.posts.count()) { + async get(postsCollection, properties) { + if (!postsCollection || !postsCollection.count()) { console.warn("No database configuration provided"); console.info( "See https://getindiekit.com/configuration/application/#mongodburl", @@ -23,7 +23,7 @@ export const postTypeCount = { const startDate = new Date(new Date(properties.published).toDateString()); const endDate = new Date(startDate); endDate.setDate(endDate.getDate() + 1); - const response = await application.posts + const response = await postsCollection .aggregate([ { $addFields: { diff --git a/packages/endpoint-micropub/lib/utils.js b/packages/endpoint-micropub/lib/utils.js index 28c956a7a..6f18c10cf 100644 --- a/packages/endpoint-micropub/lib/utils.js +++ b/packages/endpoint-micropub/lib/utils.js @@ -111,7 +111,8 @@ export const renderPath = async ( tokens.D60 = newbase60.DateToSxg(dateObject); // Add count of post-type for the day - const count = await postTypeCount.get(application, properties); + const postsCollection = application?.collections?.get("posts"); + const count = await postTypeCount.get(postsCollection, properties); tokens.n = count + 1; // Add slug token diff --git a/packages/endpoint-micropub/test/unit/post-data.js b/packages/endpoint-micropub/test/unit/post-data.js index 6ea4cff0c..b9ef8442a 100644 --- a/packages/endpoint-micropub/test/unit/post-data.js +++ b/packages/endpoint-micropub/test/unit/post-data.js @@ -8,7 +8,6 @@ describe("endpoint-micropub/lib/post-data", async () => { let application; let publication; const { client, database, mongoServer } = await testDatabase(); - const posts = database.collection("posts"); const properties = { type: "entry", published: "2020-07-26T20:10:57.062Z", @@ -23,7 +22,8 @@ describe("endpoint-micropub/lib/post-data", async () => { }); beforeEach(async () => { - await posts.insertOne({ + const postsCollection = database.collection("posts"); + await postsCollection.insertOne({ path: "foo", properties: { type: "entry", @@ -38,8 +38,10 @@ describe("endpoint-micropub/lib/post-data", async () => { }); const config = await testConfig({ usePostTypes: true }); + const collections = new Map(); + collections.set("posts", postsCollection); - application = { posts }; + application = { collections }; publication = config.publication; }); diff --git a/packages/endpoint-micropub/test/unit/post-type-count.js b/packages/endpoint-micropub/test/unit/post-type-count.js index de697b9cd..88d4f898e 100644 --- a/packages/endpoint-micropub/test/unit/post-type-count.js +++ b/packages/endpoint-micropub/test/unit/post-type-count.js @@ -5,7 +5,6 @@ import { postTypeCount } from "../../lib/post-type-count.js"; const { client, database, mongoServer } = await testDatabase(); const posts = database.collection("posts"); -const application = { posts }; describe("endpoint-media/lib/post-type-count", () => { before(async () => { @@ -27,7 +26,7 @@ describe("endpoint-media/lib/post-type-count", () => { it("Counts the number of posts of a given type", async () => { const post = await posts.findOne({}); - const result = await postTypeCount.get(application, { + const result = await postTypeCount.get(posts, { uid: post._id.toString(), type: "entry", published: new Date(), diff --git a/packages/endpoint-syndicate/lib/controllers/syndicate.js b/packages/endpoint-syndicate/lib/controllers/syndicate.js index 6624a7ba9..2b43be7fd 100644 --- a/packages/endpoint-syndicate/lib/controllers/syndicate.js +++ b/packages/endpoint-syndicate/lib/controllers/syndicate.js @@ -7,13 +7,13 @@ export const syndicateController = { try { const { application, publication } = request.app.locals; const bearerToken = findBearerToken(request); - const sourceUrl = request.query.source_url || request.body.syndication?.source_url; const redirectUri = request.query.redirect_uri || request.body.syndication?.redirect_uri; - if (!application.posts) { + const postsCollection = application?.collections?.get("posts"); + if (!postsCollection) { throw IndiekitError.notImplemented( response.locals.__("NotImplementedError.database"), ); @@ -29,7 +29,7 @@ export const syndicateController = { } // Get post data - const postData = await getPostData(application, sourceUrl); + const postData = await getPostData(postsCollection, sourceUrl); if (!postData && sourceUrl) { return response.json({ diff --git a/packages/endpoint-syndicate/lib/utils.js b/packages/endpoint-syndicate/lib/utils.js index 997fab276..bbd667301 100644 --- a/packages/endpoint-syndicate/lib/utils.js +++ b/packages/endpoint-syndicate/lib/utils.js @@ -1,21 +1,20 @@ /** * Get post data - * @param {object} application - Application configuration + * @param {object} postsCollection - Posts database collection * @param {string} url - URL of existing post (optional) * @returns {Promise} Post data for given URL else recently published post */ -export const getPostData = async (application, url) => { - const { posts } = application; +export const getPostData = async (postsCollection, url) => { let postData = {}; if (url) { // Get item in database which matching URL - postData = await posts.findOne({ + postData = await postsCollection.findOne({ "properties.url": url, }); } else { // Get published posts awaiting syndication and return first item - const items = await posts + const items = await postsCollection .find({ "properties.mp-syndicate-to": { $exists: true, diff --git a/packages/endpoint-syndicate/test/unit/utils.js b/packages/endpoint-syndicate/test/unit/utils.js index 8eb2eaa28..3eb388ca7 100644 --- a/packages/endpoint-syndicate/test/unit/utils.js +++ b/packages/endpoint-syndicate/test/unit/utils.js @@ -8,13 +8,12 @@ import { } from "../../lib/utils.js"; const { client, database, mongoServer } = await testDatabase(); -const posts = database.collection("posts"); -const application = { posts }; +const postsCollection = database.collection("posts"); const url = "https://website.example/post/12345"; describe("endpoint-syndicate/lib/token", () => { beforeEach(async () => { - await posts.insertOne({ + await postsCollection.insertOne({ properties: { type: "entry", "mp-syndicate-to": "https://mastodon.example/", @@ -29,7 +28,7 @@ describe("endpoint-syndicate/lib/token", () => { }); it("Gets post for given URL from database", async () => { - const result = await getPostData(application, url); + const result = await getPostData(postsCollection, url); assert.equal( result.properties["mp-syndicate-to"], @@ -38,7 +37,7 @@ describe("endpoint-syndicate/lib/token", () => { }); it("Gets post data from database", async () => { - const result = await getPostData(application, ""); + const result = await getPostData(postsCollection, ""); assert.equal( result.properties["mp-syndicate-to"], diff --git a/packages/indiekit/index.js b/packages/indiekit/index.js index c4a98f4a7..38d138283 100644 --- a/packages/indiekit/index.js +++ b/packages/indiekit/index.js @@ -22,6 +22,7 @@ export const Indiekit = class { */ constructor(config) { this.config = config; + this.collections = new Map(); this.application = this.config.application; this.plugins = this.config.plugins; this.publication = this.config.publication; @@ -36,6 +37,15 @@ export const Indiekit = class { return new Indiekit(config); } + addCollection(name) { + if (this.collections.has(name)) { + console.warn(`Collection ‘${name}’ already added`); + } else if (this.database) { + this.collections.set(name, this.database.collection(name)); + debug(`Added database collection: ${name}`); + } + } + addEndpoint(endpoint) { this.application.endpoints.push(endpoint); } @@ -129,14 +139,6 @@ export const Indiekit = class { process.exit(); } - if (this.database) { - debug(`Bootstrap: add database collection posts`); - this.application.posts = this.database.collection("posts"); - - debug(`Bootstrap: add database collection media`); - this.application.media = this.database.collection("media"); - } - // Update application configuration this.application.installedPlugins = await getInstalledPlugins(this); this.application.localeCatalog = await getLocaleCatalog(this.application); diff --git a/packages/indiekit/lib/controllers/feed.js b/packages/indiekit/lib/controllers/feed.js index 39ebd8eec..2d60b4c33 100644 --- a/packages/indiekit/lib/controllers/feed.js +++ b/packages/indiekit/lib/controllers/feed.js @@ -3,8 +3,9 @@ export const jf2 = async (request, response) => { const feedUrl = new URL(request.originalUrl, application.url).href; let posts = []; - if (application.posts) { - posts = await application.posts + const postsCollection = application?.collections?.get("posts"); + if (postsCollection) { + posts = await postsCollection .find({ "properties.post-status": { $ne: "draft", diff --git a/packages/indiekit/lib/middleware/locals.js b/packages/indiekit/lib/middleware/locals.js index 970aa57af..b80e03736 100644 --- a/packages/indiekit/lib/middleware/locals.js +++ b/packages/indiekit/lib/middleware/locals.js @@ -16,8 +16,13 @@ const cssHash = sha1(await styles()); export const locals = (indiekitConfig) => async function (request, response, next) { try { - const { application, database, mongodbClientError, publication } = - indiekitConfig; + const { + application, + collections, + database, + mongodbClientError, + publication, + } = indiekitConfig; // Application request.app.locals.application = application; @@ -30,6 +35,9 @@ export const locals = (indiekitConfig) => // Application database client application.database = database; + // Application database collections + application.collections = collections; + // Application locale application.localeUsed = response.locals.getLocale(); diff --git a/packages/indiekit/test/index.js b/packages/indiekit/test/index.js index 5935a0c3f..02b025e7f 100644 --- a/packages/indiekit/test/index.js +++ b/packages/indiekit/test/index.js @@ -1,28 +1,40 @@ import { strict as assert } from "node:assert"; -import { beforeEach, describe, it, mock } from "node:test"; +import { after, before, describe, it, mock } from "node:test"; import { testConfig } from "@indiekit-test/config"; +import { testDatabase } from "@indiekit-test/database"; import TestStore from "@indiekit-test/store"; import { Indiekit } from "../index.js"; -describe("indiekit", () => { +describe("indiekit", async () => { let indiekit; - let application, publication; + const { client, mongoServer, mongoUri } = await testDatabase(); - beforeEach(async () => { - const config = await testConfig(); + before(async () => { + mock.method(console, "info", () => {}); + const config = await testConfig({ mongodbUrl: mongoUri }); indiekit = await Indiekit.initialize({ config }); - const bootstrappedConfig = await indiekit.bootstrap(); - application = bootstrappedConfig.application; - publication = bootstrappedConfig.publication; + await indiekit.connectMongodbClient(); + }); + + after(async () => { + await client.close(); + await mongoServer.stop(); + indiekit.closeMongodbClient(); }); - it("Gets application configuration value", () => { - assert.equal(application.name, "Test configuration"); + it("Adds database collection", async () => { + indiekit.addCollection("test"); + + assert.equal(indiekit.collections.has("test"), true); }); - it("Gets publication configuration values", () => { - assert.equal(publication.slugSeparator, "-"); - assert.equal(publication.me, "https://website.example"); + it("Doesn’t allow duplicate database collections", async () => { + mock.method(console, "warn", () => {}); + + indiekit.addCollection("test"); + const result = console.warn.mock.calls[0].arguments[0]; + + assert.equal(result.includes(`Collection ‘test’ already added`), true); }); it("Adds endpoint", () => { @@ -61,26 +73,4 @@ describe("indiekit", () => { assert.equal(indiekit.application.stores[0].info.name, "Test store"); }); - - it("Exits process if no publication URL in configuration", async () => { - mock.method(console, "error", () => {}); - mock.method(console, "info", () => {}); - mock.method(process, "exit", () => {}); - - publication.me = undefined; - await assert.rejects(indiekit.server({ port: 1234 })); - const result = console.error.mock.calls[0].arguments[0]; - - assert.equal(result.includes("No publication URL in configuration"), true); - assert.equal(process.exit.mock.calls.length, 1); - }); - - it("Returns a server bound to given port", async () => { - mock.method(console, "info", () => {}); - const result = await indiekit.server({ port: 1234 }); - - assert.match(result._connectionKey, /::::1234/); - - result.close(); - }); }); diff --git a/packages/indiekit/test/server.js b/packages/indiekit/test/server.js new file mode 100644 index 000000000..804eb7e50 --- /dev/null +++ b/packages/indiekit/test/server.js @@ -0,0 +1,49 @@ +import { strict as assert } from "node:assert"; +import { before, describe, it, mock } from "node:test"; +import { testConfig } from "@indiekit-test/config"; +import { Indiekit } from "../index.js"; + +describe("indiekit server", async () => { + let indiekit; + let application, publication; + + before(async () => { + const config = await testConfig(); + indiekit = await Indiekit.initialize({ config }); + const bootstrappedConfig = await indiekit.bootstrap(); + application = bootstrappedConfig.application; + publication = bootstrappedConfig.publication; + }); + + it("Gets application configuration value", () => { + assert.equal(application.name, "Test configuration"); + }); + + it("Gets publication configuration values", () => { + assert.equal(publication.slugSeparator, "-"); + assert.equal(publication.me, "https://website.example"); + }); + + it("Exits process if no publication URL in configuration", async () => { + mock.method(console, "error", () => {}); + mock.method(console, "info", () => {}); + mock.method(process, "exit", () => {}); + + publication.me = undefined; + await assert.rejects(indiekit.server({ port: 1234 })); + const result = console.error.mock.calls[0].arguments[0]; + + assert.equal(result.includes("No publication URL in configuration"), true); + assert.equal(process.exit.mock.calls.length, 1); + }); + + it("Returns a server bound to given port", async () => { + mock.method(console, "info", () => {}); + publication.me = "https://website.example"; + const result = await indiekit.server({ port: 1234 }); + + assert.match(result._connectionKey, /::::1234/); + + result.close(); + }); +}); From c541db0c214a40633ac9675e675a7a4e3af76a37 Mon Sep 17 00:00:00 2001 From: Paul Robert Lloyd Date: Sat, 23 Nov 2024 18:51:33 +0000 Subject: [PATCH 2/2] docs: addCollection API method --- docs/.vitepress/config.js | 4 ++++ docs/api/add-collection.md | 18 ++++++++++++++++++ docs/api/index.md | 2 ++ 3 files changed, 24 insertions(+) create mode 100644 docs/api/add-collection.md diff --git a/docs/.vitepress/config.js b/docs/.vitepress/config.js index d9c08051f..7a0b710e9 100644 --- a/docs/.vitepress/config.js +++ b/docs/.vitepress/config.js @@ -42,6 +42,10 @@ const sidebar = [ const sidebarApi = [ { text: "Introduction", link: "/api/" }, + { + text: "Indiekit.addCollection", + link: "/api/add-collection", + }, { text: "Indiekit.addEndpoint", link: "/api/add-endpoint", diff --git a/docs/api/add-collection.md b/docs/api/add-collection.md new file mode 100644 index 000000000..820b88f1d --- /dev/null +++ b/docs/api/add-collection.md @@ -0,0 +1,18 @@ +--- +outline: deep +--- + +# `Indiekit.addCollection` + +This method is enables plug-ins to add a new collection to the MongoDB database for storing data. + +## Syntax + +```js +new Indiekit.addCollection(name); +``` + +## Constructor + +`name` +: Collection name. This cannot share the name of a collection added by another plug-in. Indiekit currently adds 2 collections: `posts` and `media`. diff --git a/docs/api/index.md b/docs/api/index.md index f9e5672a2..bdbf49753 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -12,6 +12,8 @@ A plug-in can provide any of the following features: * [content store functions](add-store.md) * [syndication functions](add-syndicator.md) +A plug-in can also [add a collection](add-collection.md) to the MongoDb database. + ## Anatomy of a plug-in A plug-in is a `Class` with an `init()` function that is used to register endpoints, presets, stores and syndicators. You can also use the `init()` function to modify Indiekit’s [configuration](../configuration/index.md). For example: