enables deletion of files, adds additional meta data
This commit is contained in:
@@ -5,43 +5,98 @@ const sanitize = require('./sanitize');
|
||||
|
||||
function registerCollections() {
|
||||
this.config.collections.forEach((collection) => {
|
||||
const schema = buildSchema(collection, this.config);
|
||||
const formattedCollection = { ...collection };
|
||||
|
||||
if (collection.upload) {
|
||||
const uploadFields = {
|
||||
filename: {
|
||||
type: String,
|
||||
unique: true,
|
||||
let uploadFields = [
|
||||
{
|
||||
name: 'filename',
|
||||
label: 'Filename',
|
||||
type: 'text',
|
||||
required: true,
|
||||
unique: true,
|
||||
readOnly: true,
|
||||
}, {
|
||||
name: 'mimeType',
|
||||
label: 'MIME Type',
|
||||
type: 'text',
|
||||
readOnly: true,
|
||||
}, {
|
||||
name: 'filesize',
|
||||
label: 'File Size',
|
||||
type: 'number',
|
||||
readOnly: true,
|
||||
},
|
||||
mimeType: { type: String },
|
||||
width: { type: Number },
|
||||
height: { type: Number },
|
||||
};
|
||||
];
|
||||
|
||||
if (collection.upload.imageSizes && Array.isArray(collection.upload.imageSizes)) {
|
||||
uploadFields.sizes = collection.upload.imageSizes.reduce((sizes, size) => {
|
||||
return {
|
||||
...sizes,
|
||||
[size.name]: {
|
||||
width: { type: Number },
|
||||
height: { type: Number },
|
||||
filename: { type: String },
|
||||
_id: false,
|
||||
},
|
||||
};
|
||||
}, {});
|
||||
uploadFields = uploadFields.concat([
|
||||
{
|
||||
name: 'width',
|
||||
label: 'Width',
|
||||
type: 'number',
|
||||
readOnly: true,
|
||||
}, {
|
||||
name: 'height',
|
||||
label: 'Height',
|
||||
type: 'number',
|
||||
readOnly: true,
|
||||
},
|
||||
{
|
||||
name: 'sizes',
|
||||
label: 'Sizes',
|
||||
type: 'group',
|
||||
fields: collection.upload.imageSizes.map(size => ({
|
||||
label: size.name,
|
||||
name: size.name,
|
||||
type: 'group',
|
||||
fields: [
|
||||
{
|
||||
name: 'width',
|
||||
label: 'Width',
|
||||
type: 'number',
|
||||
readOnly: true,
|
||||
}, {
|
||||
name: 'height',
|
||||
label: 'Height',
|
||||
type: 'number',
|
||||
readOnly: true,
|
||||
}, {
|
||||
name: 'mimeType',
|
||||
label: 'MIME Type',
|
||||
type: 'text',
|
||||
readOnly: true,
|
||||
}, {
|
||||
name: 'filesize',
|
||||
label: 'File Size',
|
||||
type: 'number',
|
||||
readOnly: true,
|
||||
}, {
|
||||
name: 'filename',
|
||||
label: 'File Name',
|
||||
type: 'text',
|
||||
readOnly: true,
|
||||
},
|
||||
],
|
||||
})),
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
schema.add(uploadFields);
|
||||
formattedCollection.fields = [
|
||||
...formattedCollection.fields,
|
||||
...uploadFields,
|
||||
];
|
||||
}
|
||||
|
||||
this.collections[collection.slug] = {
|
||||
Model: mongoose.model(collection.slug, schema),
|
||||
config: sanitize(this.collections, collection),
|
||||
const schema = buildSchema(formattedCollection, this.config);
|
||||
|
||||
this.collections[formattedCollection.slug] = {
|
||||
Model: mongoose.model(formattedCollection.slug, schema),
|
||||
config: sanitize(this.collections, formattedCollection),
|
||||
};
|
||||
|
||||
this.router.use(collectionRoutes(this.collections[collection.slug]));
|
||||
this.router.use(collectionRoutes(this.collections[formattedCollection.slug]));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -36,37 +36,32 @@ const create = async (args) => {
|
||||
// /////////////////////////////////////
|
||||
|
||||
if (args.config.upload) {
|
||||
const { staticDir, imageSizes } = options.req.collection.config.upload;
|
||||
|
||||
const fileData = {};
|
||||
|
||||
if (!args.req.files || Object.keys(args.req.files).length === 0) {
|
||||
throw new MissingFile();
|
||||
}
|
||||
|
||||
const { staticDir, imageSizes } = options.req.collection.config.upload;
|
||||
await mkdirp(staticDir);
|
||||
|
||||
try {
|
||||
await mkdirp(staticDir);
|
||||
const fsSafeName = await getSafeFilename(staticDir, options.req.files.file.name);
|
||||
const fsSafeName = await getSafeFilename(staticDir, options.req.files.file.name);
|
||||
|
||||
try {
|
||||
await options.req.files.file.mv(`${staticDir}/${fsSafeName}`);
|
||||
await options.req.files.file.mv(`${staticDir}/${fsSafeName}`);
|
||||
|
||||
fileData.filename = fsSafeName;
|
||||
fileData.filename = fsSafeName;
|
||||
fileData.filesize = options.req.files.file.size;
|
||||
fileData.mimeType = options.req.files.file.mimetype;
|
||||
|
||||
if (imageSizes) {
|
||||
fileData.sizes = await resizeAndSave(options.config, fsSafeName);
|
||||
}
|
||||
|
||||
options.data = {
|
||||
...options.data,
|
||||
...fileData,
|
||||
};
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
} catch (err) {
|
||||
throw err;
|
||||
if (imageSizes) {
|
||||
fileData.sizes = await resizeAndSave(options.config, fsSafeName, fileData.mimeType);
|
||||
}
|
||||
|
||||
options.data = {
|
||||
...options.data,
|
||||
...fileData,
|
||||
};
|
||||
}
|
||||
|
||||
// /////////////////////////////////////
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
const fs = require('fs');
|
||||
const { NotFound } = require('../../errors');
|
||||
const executePolicy = require('../../users/executePolicy');
|
||||
|
||||
@@ -22,7 +23,7 @@ const deleteQuery = async (args) => {
|
||||
}
|
||||
|
||||
// /////////////////////////////////////
|
||||
// 3. Perform database operation
|
||||
// 3. Get existing document
|
||||
// /////////////////////////////////////
|
||||
|
||||
const {
|
||||
@@ -34,9 +35,39 @@ const deleteQuery = async (args) => {
|
||||
},
|
||||
} = options;
|
||||
|
||||
let result = await Model.findOneAndDelete({ _id: id });
|
||||
let resultToDelete = await Model.findOne({ _id: id });
|
||||
|
||||
if (!result) throw new NotFound();
|
||||
if (!resultToDelete) throw new NotFound();
|
||||
|
||||
resultToDelete = resultToDelete.toJSON({ virtuals: true });
|
||||
|
||||
if (locale && resultToDelete.setLocale) {
|
||||
resultToDelete.setLocale(locale, fallbackLocale);
|
||||
}
|
||||
|
||||
// /////////////////////////////////////
|
||||
// 4. Delete any associated files
|
||||
// /////////////////////////////////////
|
||||
|
||||
const { staticDir } = options.req.collection.config.upload;
|
||||
|
||||
fs.unlink(`${staticDir}/${resultToDelete.filename}`, (err) => {
|
||||
console.log('Error deleting file:', err);
|
||||
});
|
||||
|
||||
if (resultToDelete.sizes) {
|
||||
Object.values(resultToDelete.sizes).forEach((size) => {
|
||||
fs.unlink(`${staticDir}/${size.filename}`, (err) => {
|
||||
console.log('Error deleting file:', err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// /////////////////////////////////////
|
||||
// 5. Delete database document
|
||||
// /////////////////////////////////////
|
||||
|
||||
let result = await Model.findOneAndDelete({ _id: id });
|
||||
|
||||
result = result.toJSON({ virtuals: true });
|
||||
|
||||
@@ -44,11 +75,6 @@ const deleteQuery = async (args) => {
|
||||
result.setLocale(locale, fallbackLocale);
|
||||
}
|
||||
|
||||
// /////////////////////////////////////
|
||||
// TODO - if upload is present on the collection,
|
||||
// delete the file here
|
||||
// /////////////////////////////////////
|
||||
|
||||
// /////////////////////////////////////
|
||||
// 4. Execute after collection hook
|
||||
// /////////////////////////////////////
|
||||
|
||||
@@ -72,16 +72,12 @@ const update = async (args) => {
|
||||
if (args.req.files || args.req.files.file) {
|
||||
const fsSafeName = await getSafeFilename(staticDir, options.req.files.file.name);
|
||||
|
||||
try {
|
||||
await options.req.files.file.mv(`${staticDir}/${fsSafeName}`);
|
||||
await options.req.files.file.mv(`${staticDir}/${fsSafeName}`);
|
||||
|
||||
fileData.filename = fsSafeName;
|
||||
fileData.filename = fsSafeName;
|
||||
|
||||
if (imageSizes) {
|
||||
fileData.sizes = await resizeAndSave(options.config, fsSafeName);
|
||||
}
|
||||
} catch (error) {
|
||||
throw error;
|
||||
if (imageSizes) {
|
||||
fileData.sizes = await resizeAndSave(options.config, fsSafeName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ function getOutputImage(sourceImage, size) {
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = async function resizeAndSave(config, savedFilename) {
|
||||
module.exports = async function resizeAndSave(config, savedFilename, mimeType) {
|
||||
/**
|
||||
* Resize images according to image desired width and height and return sizes
|
||||
* @param config Object
|
||||
@@ -38,15 +38,23 @@ module.exports = async function resizeAndSave(config, savedFilename) {
|
||||
.map(async (desiredSize) => {
|
||||
const outputImage = getOutputImage(savedFilename, desiredSize);
|
||||
const imageNameWithDimensions = `${outputImage.name}-${outputImage.width}x${outputImage.height}.${outputImage.extension}`;
|
||||
await sharp(sourceImage)
|
||||
const output = await sharp(sourceImage)
|
||||
.resize(desiredSize.width, desiredSize.height, {
|
||||
// would it make sense for this to be set by the uploader?
|
||||
position: desiredSize.crop || 'centre',
|
||||
})
|
||||
.toFile(`${staticDir}/${imageNameWithDimensions}`);
|
||||
return { ...desiredSize, filename: imageNameWithDimensions };
|
||||
|
||||
return {
|
||||
...desiredSize,
|
||||
filename: imageNameWithDimensions,
|
||||
filesize: output.size,
|
||||
mimeType,
|
||||
};
|
||||
});
|
||||
|
||||
const savedSizes = await Promise.all(sizes);
|
||||
|
||||
return savedSizes.reduce((results, size) => {
|
||||
return {
|
||||
...results,
|
||||
@@ -54,6 +62,8 @@ module.exports = async function resizeAndSave(config, savedFilename) {
|
||||
width: size.width,
|
||||
height: size.height,
|
||||
filename: size.filename,
|
||||
mimeType: size.mimeType,
|
||||
filesize: size.filesize,
|
||||
},
|
||||
};
|
||||
}, {});
|
||||
|
||||
Reference in New Issue
Block a user