UNPKG

gatsby-source-strapi

Version:

Gatsby source plugin for building websites using Strapi as a data source

211 lines (204 loc) 6.44 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); exports.__esModule = true; exports.downloadMediaFiles = exports.downloadFile = void 0; var _commonmark = require("commonmark"); var _qs = _interopRequireDefault(require("qs")); var _gatsbySourceFilesystem = require("gatsby-source-filesystem"); var _helpers = require("./helpers"); const reader = new _commonmark.Parser(); /** * Retrieves all medias from the markdown * @param {String} text * @param {String} apiURL * @returns {Object[]} */ const extractFiles = (text, apiURL) => { const files = []; // parse the markdown content const parsed = reader.parse(text); const walker = parsed.walker(); let event, node; while (event = walker.next()) { node = event.node; // process image nodes if (event.entering && node.type === "image") { var _node$firstChild; let destination; const alternativeText = ((_node$firstChild = node.firstChild) === null || _node$firstChild === void 0 ? void 0 : _node$firstChild.literal) || ""; if (/^\//.test(node.destination)) { destination = `${apiURL}${node.destination}`; } else if (/^http/i.test(node.destination)) { destination = node.destination; } if (destination) { files.push({ url: destination, src: node.destination, alternativeText }); } } } return files.filter(Boolean); }; /** * Download file and create node * @param {Object} file * @param {Object} ctx * @returns {String} node Id */ const downloadFile = async (file, context) => { const { actions: { createNode, touchNode }, cache, createNodeId, getNode, store, strapiConfig } = context; const { apiURL, remoteFileHeaders } = strapiConfig; let fileNodeID; const mediaDataCacheKey = `strapi-media-${file.id}`; const cacheMediaData = await cache.get(mediaDataCacheKey); // If we have cached media data and it wasn't modified, reuse // previously created file node to not try to redownload if (cacheMediaData && cacheMediaData.updatedAt === file.updatedAt) { fileNodeID = cacheMediaData.fileNodeID; touchNode(getNode(fileNodeID)); } if (!fileNodeID) { try { // full media url const source_url = `${file.url.startsWith("http") ? "" : apiURL}${file.url}`; const fileNode = await (0, _gatsbySourceFilesystem.createRemoteFileNode)({ url: source_url, store, cache, createNode, createNodeId, httpHeaders: remoteFileHeaders || {} }); if (fileNode) { fileNodeID = fileNode.id; await cache.set(mediaDataCacheKey, { fileNodeID, updatedAt: file.updatedAt }); } } catch (error) { // Ignore console.log("err", error); } } return fileNodeID; }; /** * Extract images and create remote nodes for images in all fields. * @param {Object} item the entity * @param {Object} context gatsby function * @param {String} uid the main schema uid */ exports.downloadFile = downloadFile; const extractImages = async (item, context, uid) => { const { schemas, strapiConfig, axiosInstance } = context; const schema = (0, _helpers.getContentTypeSchema)(schemas, uid); const { apiURL } = strapiConfig; for (const attributeName of Object.keys(item)) { const value = item[attributeName]; const attribute = schema.schema.attributes[attributeName]; const type = (attribute === null || attribute === void 0 ? void 0 : attribute.type) || undefined; if (value && type) { if (type === "richtext") { const extractedFiles = extractFiles(value.data, apiURL); const files = await Promise.all(extractedFiles.map(async ({ url }) => { const filters = _qs.default.stringify({ filters: { url: url.replace(`${apiURL}`, "") } }, { encode: false }); const { data } = await axiosInstance.get(`/api/upload/files?${filters}`); const file = data[0]; if (!file) { return; } const fileNodeID = await downloadFile(file, context); return { fileNodeID, file }; })); const fileNodes = files.filter(Boolean); for (const [index, fileNode] of fileNodes.entries()) { item[attributeName].medias.push({ alternativeText: extractedFiles[index].alternativeText, url: extractedFiles[index].url, src: extractedFiles[index].src, localFile___NODE: fileNode.fileNodeID, file: fileNode.file }); } } if (type === "dynamiczone") { for (const element of value) { await extractImages(element, context, element.strapi_component); } } if (type === "component") { if (attribute.repeatable) { for (const element of value) { await extractImages(element, context, attribute.component); } } else { await extractImages(value, context, attribute.component); } } if (type === "relation") { await extractImages(value, context, attribute.target); } if (type === "media") { const isMultiple = attribute.multiple; const imagesField = isMultiple ? value : [value]; // Dowload all files const files = await Promise.all(imagesField.map(async file => { const fileNodeID = await downloadFile(file, context); return fileNodeID; })); const images = files.filter(Boolean); if (images && images.length > 0) { if (isMultiple) { for (let index = 0; index < value.length; index++) { item[attributeName][index][`localFile___NODE`] = images[index]; } } else { item[attributeName][`localFile___NODE`] = isMultiple ? images : images[0]; } } } } } }; // Downloads media from image type fields const downloadMediaFiles = async (entities, context, contentTypeUid) => Promise.all(entities.map(async entity => { await extractImages(entity, context, contentTypeUid); return entity; })); exports.downloadMediaFiles = downloadMediaFiles;