2023-02-10 09:44:49 +01:00

143 lines
3.8 KiB
JavaScript

'use strict';
const { mapAsync } = require('@strapi/utils');
const { FOLDER_MODEL_UID, FILE_MODEL_UID } = require('../constants');
const { getService } = require('../utils');
const getFolderPath = async (folderId) => {
if (!folderId) return '/';
const parentFolder = await strapi.entityService.findOne(FOLDER_MODEL_UID, folderId);
return parentFolder.path;
};
const deleteByIds = async (ids = []) => {
const filesToDelete = await strapi.db
.query(FILE_MODEL_UID)
.findMany({ where: { id: { $in: ids } } });
await Promise.all(filesToDelete.map((file) => getService('upload').remove(file)));
return filesToDelete;
};
const signFileUrl = async (fileIdentifier) => {
const { provider } = strapi.plugins.upload;
const { url } = await provider.getSignedUrl(fileIdentifier);
return url;
};
// TODO: Make this non mutating?
const signFileUrls = async (file) => {
const { provider } = strapi.plugins.upload;
const { provider: providerConfig } = strapi.config.get('plugin.upload');
// Check file provider and if provider is private
if (file.provider !== providerConfig || !provider.isPrivate()) {
return;
}
const signUrl = async (file) => {
const signedUrl = await provider.getSignedUrl(file);
file.url = signedUrl.url;
};
// Sign each file format
await signUrl(file);
if (file.formats) {
await mapAsync(Object.values(file.formats), signUrl);
}
};
/**
*
* Iterate through an entity manager result
* Check which modelAttributes are media and pre sign the image URLs
* if they are from the current upload provider
* @param {Object} entity
* @param {Object} modelAttributes
* @param {String} providerConfig
* @returns
*/
const signEntityMedia = async (entity, uid) => {
const model = strapi.getModel(uid);
for (const [key, value] of Object.entries(entity)) {
// eslint-disable-next-line no-continue
if (!value) continue;
const attribute = model.attributes[key];
switch (attribute?.type) {
case 'media':
await signFileUrls(value);
break;
case 'component':
if (attribute.repeatable) {
await Promise.all(
value.map((component) => signEntityMedia(component, attribute.component))
);
} else {
await signEntityMedia(value, attribute.component);
}
break;
case 'dynamiczone':
await Promise.all(
value.map((component) => signEntityMedia(component, component.__component))
);
break;
default:
break;
}
}
return entity;
};
const addSignedFileUrlsToAdmin = () => {
const { provider } = strapi.plugins.upload;
// We only need to sign the file urls if the provider is private
if (!provider.isPrivate()) {
return;
}
// TOPICS:
// What about the webhooks emitted by the entity manager?
// Do we want to sign the file urls in the event payload?
// We need to do this for create/update/delete/publish/unpublish too no?
strapi.container
.get('services')
.extend(`plugin::content-manager.entity-manager`, (entityManager) => {
const findWithRelationCountsPage = async (opts, uid) => {
const entities = await entityManager.findWithRelationCountsPage(opts, uid);
await mapAsync(entities.results, async (entity) => signEntityMedia(entity, uid));
return entities;
};
const findOneWithCreatorRolesAndCount = async (id, uid) => {
// TODO: What if the entity is not found?
const entity = await entityManager.findOneWithCreatorRolesAndCount(id, uid);
await signEntityMedia(entity, uid);
return entity;
};
return {
...entityManager,
findOneWithCreatorRolesAndCount,
findWithRelationCountsPage,
};
});
};
module.exports = {
getFolderPath,
deleteByIds,
signFileUrl,
signFileUrls,
addSignedFileUrlsToAdmin,
};