Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide addCollection API method, add to application.collections Map #780

Merged
merged 2 commits into from
Nov 23, 2024
Merged
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
4 changes: 4 additions & 0 deletions docs/.vitepress/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ const sidebar = [

const sidebarApi = [
{ text: "Introduction", link: "/api/" },
{
text: "<code>Indiekit.addCollection</code>",
link: "/api/add-collection",
},
{
text: "<code>Indiekit.addEndpoint</code>",
link: "/api/add-endpoint",
Expand Down
18 changes: 18 additions & 0 deletions docs/api/add-collection.md
Original file line number Diff line number Diff line change
@@ -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`.
2 changes: 2 additions & 0 deletions docs/api/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
4 changes: 3 additions & 1 deletion packages/endpoint-json-feed/lib/controllers/json-feed.js
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
1 change: 1 addition & 0 deletions packages/endpoint-media/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 5 additions & 4 deletions packages/endpoint-media/lib/controllers/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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,
});
}
Expand All @@ -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({
Expand Down
15 changes: 8 additions & 7 deletions packages/endpoint-media/lib/media-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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);
}
Expand All @@ -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;
}
Expand Down
8 changes: 4 additions & 4 deletions packages/endpoint-media/lib/media-type-count.js
Original file line number Diff line number Diff line change
@@ -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<object>} 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",
Expand All @@ -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: {
Expand Down
3 changes: 2 additions & 1 deletion packages/endpoint-media/lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 5 additions & 3 deletions packages/endpoint-media/test/unit/media-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand All @@ -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;
});

Expand Down
3 changes: 1 addition & 2 deletions packages/endpoint-media/test/unit/media-type-count.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand All @@ -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",
Expand Down
1 change: 1 addition & 0 deletions packages/endpoint-micropub/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export default class MicropubEndpoint {
}

init(Indiekit) {
Indiekit.addCollection("posts");
Indiekit.addEndpoint(this);

// Use private value to register Micropub endpoint path
Expand Down
9 changes: 5 additions & 4 deletions packages/endpoint-micropub/lib/controllers/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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,
});
}
Expand All @@ -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 = [];
Expand Down
18 changes: 10 additions & 8 deletions packages/endpoint-micropub/lib/post-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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);
Expand Down Expand Up @@ -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;
},
Expand All @@ -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);
Expand Down Expand Up @@ -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;
},
Expand All @@ -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);
Expand Down Expand Up @@ -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;
},
Expand Down
8 changes: 4 additions & 4 deletions packages/endpoint-micropub/lib/post-type-count.js
Original file line number Diff line number Diff line change
Expand Up @@ -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<object>} 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",
Expand All @@ -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: {
Expand Down
3 changes: 2 additions & 1 deletion packages/endpoint-micropub/lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 5 additions & 3 deletions packages/endpoint-micropub/test/unit/post-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand All @@ -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;
});

Expand Down
Loading
Loading