enables deletion of files, adds additional meta data

This commit is contained in:
James
2020-05-06 16:31:03 -04:00
parent 8fac03c442
commit 4929763ba9
6 changed files with 146 additions and 83 deletions

View File

@@ -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]));
});
}

View File

@@ -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,
};
}
// /////////////////////////////////////

View File

@@ -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
// /////////////////////////////////////

View File

@@ -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);
}
}

View File

@@ -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,
},
};
}, {});