UNPKG

@indiekit/endpoint-posts

Version:

Post management endpoint for Indiekit. View posts published by your Micropub endpoint and publish new posts to it.

202 lines (175 loc) 5.48 kB
import { Buffer } from "node:buffer"; import { sanitise, ISO_6709_RE } from "@indiekit/util"; import { mf2tojf2 } from "@paulrobertlloyd/mf2tojf2"; import formatcoords from "formatcoords"; import { endpoint } from "./endpoint.js"; import { statusTypes } from "./status-types.js"; /** * Get channel `items` for checkboxes component * @param {object} publication - Publication configuration * @returns {object} Items for checkboxes component */ export const getChannelItems = (publication) => { return Object.entries(publication.channels).map(([uid, channel]) => ({ label: channel.name, value: uid, })); }; /** * Get geographic coordinates property * @param {string} geo - Latitude and longitude, comma separated * @returns {object} JF2 geo location property */ export const getGeoProperty = (geo) => { const { latitude, longitude } = geo.match(ISO_6709_RE).groups; return { type: "geo", name: formatcoords(geo).format({ decimalPlaces: 2, }), latitude: Number(latitude), longitude: Number(longitude), }; }; /** * Get comma separated geographic coordinates * @param {object} location - JF2 location property * @returns {string|undefined} Latitude and longitude, comma separated */ export const getGeoValue = (location) => { if (location && location.geo) { return [location.geo.latitude, location.geo.longitude].toString(); } else if (location && location.type === "geo") { return [location.latitude, location.longitude].toString(); } }; /** * Get location property * @param {object} values - Latitude and longitude, comma separated * @returns {object} JF2 location property */ export const getLocationProperty = (values) => { const { geo, location } = values; const hasGeo = geo && geo.length > 0; const hasLocation = location && Object.entries(sanitise(location)).length > 0; // Determine Microformat type if (hasLocation && location.name) { location.type = "card"; } else if (hasLocation && !hasGeo) { location.type = "adr"; } // Add (or use) any provided geo location properties if (hasLocation && hasGeo) { location.geo = getGeoProperty(geo); } else if (hasGeo) { return getGeoProperty(geo); } return sanitise(location); }; /** * Get photo URL * @param {object} publication - Publication configuration * @param {object} properties - JF2 properties * @returns {object|boolean} Photo object, with URL */ export const getPhotoUrl = (publication, properties) => { const photo = Array.isArray(properties.photo) ? properties.photo[0] : properties.photo; if (!photo) { return false; } else if (URL.canParse(photo.url)) { return photo; } else { return { url: new URL(photo.url, publication.me).href, }; } }; /** * Get post status badges * @param {object} post - Post * @param {import("express").Response} response - Response * @returns {Array} Badges */ export const getPostStatusBadges = (post, response) => { const badges = []; if (post["post-status"]) { const statusType = post["post-status"]; badges.push({ color: statusTypes[statusType].color, size: "small", text: response.locals.__(statusTypes[statusType].text), }); } if (post.deleted) { badges.push({ color: statusTypes.deleted.color, size: "small", text: response.locals.__(statusTypes.deleted.text), }); } return badges; }; /** * Get post name, falling back to post type name * @param {object} publication - Publication configuration * @param {object} properties - JF2 properties * @returns {string} Post name or post type name */ export const getPostName = (publication, properties) => { if (properties.name) { return properties.name; } const type = properties["post-type"]; const { name } = publication.postTypes[type]; return name; }; /** * 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 */ export const getPostProperties = async (uid, micropubEndpoint, accessToken) => { const micropubUrl = new URL(micropubEndpoint); micropubUrl.searchParams.append("q", "source"); const micropubResponse = await endpoint.get(micropubUrl.href, accessToken); if (micropubResponse?.items?.length > 0) { const jf2 = mf2tojf2(micropubResponse); const items = jf2.children || [jf2]; return items.find((item) => item.uid === uid); } return false; }; /** * Get post URL from ID * @param {string} id - ID * @returns {string} Post URL */ export const getPostUrl = (id) => { const url = Buffer.from(id, "base64url").toString("utf8"); return new URL(url).href; }; /** * Get syndication target `items` for checkboxes component * @param {object} publication - Publication configuration * @param {boolean} [checkTargets] - Select ’checked’ targets * @returns {object} Items for checkboxes component */ export const getSyndicateToItems = (publication, checkTargets = false) => { return publication.syndicationTargets.map((target) => ({ label: target.info.service.name, ...(target?.info?.error ? { disabled: true, hint: target?.info?.error || false, } : { hint: target?.info.uid, value: target?.info.uid, ...(checkTargets && { checked: target.options.checked }), }), })); };