WIP - merges media storage
This commit is contained in:
14
.vscode/launch.json
vendored
Normal file
14
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Launch Program",
|
||||||
|
"program": "${workspaceFolder}/demo/init.js"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
69
src/controllers/media.controller.js
Normal file
69
src/controllers/media.controller.js
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import mkdirp from 'mkdirp';
|
||||||
|
import { resizeAndSave } from '../utils/imageResizer';
|
||||||
|
import httpStatus from 'http-status';
|
||||||
|
import modelById from '../resolvers/modelById';
|
||||||
|
|
||||||
|
export async function update(req, res, next, config) {
|
||||||
|
req.model.setDefaultLocale(req.locale);
|
||||||
|
|
||||||
|
let doc = await modelById(req, { returnRawDoc: true });
|
||||||
|
if (!doc)
|
||||||
|
return res.status(httpStatus.NOT_FOUND).send('Not Found');
|
||||||
|
|
||||||
|
Object.keys(req.body).forEach(e => {
|
||||||
|
doc[e] = req.body[e];
|
||||||
|
});
|
||||||
|
|
||||||
|
if (req.files && req.files.file) {
|
||||||
|
doc['filename'] = req.files.file.name;
|
||||||
|
let outputFilepath = `${config.staticDir}/${req.files.file.name}`;
|
||||||
|
let moveError = await req.files.file.mv(outputFilepath);
|
||||||
|
if (moveError) return res.status(500).send(moveError);
|
||||||
|
doc['sizes'] = await resizeAndSave(config, req.files.file);
|
||||||
|
}
|
||||||
|
|
||||||
|
doc.save((saveError) => {
|
||||||
|
if (saveError)
|
||||||
|
return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ error: saveError });
|
||||||
|
|
||||||
|
return res.json({
|
||||||
|
message: 'success',
|
||||||
|
result: doc.toJSON({ virtuals: true })
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function upload(req, res, next, config) {
|
||||||
|
if (!req.files || Object.keys(req.files).length === 0) {
|
||||||
|
return res.status(400).send('No files were uploaded.');
|
||||||
|
}
|
||||||
|
|
||||||
|
mkdirp(config.staticDir, (err) => {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
res.status(500).send('Upload failed.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let outputFilepath = `${config.staticDir}/${req.files.file.name}`;
|
||||||
|
let moveError = await req.files.file.mv(outputFilepath);
|
||||||
|
if (moveError) return res.status(500).send(moveError);
|
||||||
|
let outputSizes = await resizeAndSave(config, req.files.file);
|
||||||
|
|
||||||
|
req.model.create({
|
||||||
|
name: req.body.name,
|
||||||
|
caption: req.body.caption,
|
||||||
|
description: req.body.description,
|
||||||
|
filename: req.files.file.name,
|
||||||
|
sizes: outputSizes
|
||||||
|
}, (mediaCreateError, result) => {
|
||||||
|
if (mediaCreateError)
|
||||||
|
return res.status(500).json({ error: mediaCreateError });
|
||||||
|
|
||||||
|
return res.status(201)
|
||||||
|
.json({
|
||||||
|
message: 'success',
|
||||||
|
result: result.toJSON({ virtuals: true })
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
import mkdirp from 'mkdirp';
|
|
||||||
import { resize } from '../../src/utils/imageResizer';
|
|
||||||
import Media from '../models/Media.model';
|
|
||||||
|
|
||||||
function upload(req, res, next, config) {
|
|
||||||
if (Object.keys(req.files).length === 0) {
|
|
||||||
return res.status(400).send('No files were uploaded.');
|
|
||||||
}
|
|
||||||
|
|
||||||
mkdirp(config.staticDir, (err) => {
|
|
||||||
if (err) {
|
|
||||||
console.error(err);
|
|
||||||
res.status(500).send('Upload failed.');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let outputFilepath = `${config.staticDir}/${req.files.file.name}`;
|
|
||||||
req.files.file.mv(outputFilepath, (err) => {
|
|
||||||
if (err) return res.status(500).send(err);
|
|
||||||
|
|
||||||
if (req.files.file.mimetype.split('/')[0] === 'image') {
|
|
||||||
resize(config, req.files.file);
|
|
||||||
}
|
|
||||||
|
|
||||||
Media.create({
|
|
||||||
name: req.files.file.name,
|
|
||||||
filename: req.files.file.name
|
|
||||||
}, (err, result) => {
|
|
||||||
if (err)
|
|
||||||
return res.status(500).json({ error: err });
|
|
||||||
|
|
||||||
return res.status(201)
|
|
||||||
.json({
|
|
||||||
message: 'success',
|
|
||||||
result: {
|
|
||||||
id: result.id,
|
|
||||||
name: result.name
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export default { upload };
|
|
||||||
@@ -1,15 +1,28 @@
|
|||||||
import mongoose from 'mongoose';
|
import mongoose from 'mongoose';
|
||||||
import buildQuery from '../plugins/buildQuery';
|
import buildQuery from '../plugins/buildQuery';
|
||||||
import paginate from '../plugins/paginate';
|
import paginate from '../plugins/paginate';
|
||||||
|
import internationalization from '../plugins/internationalization';
|
||||||
|
|
||||||
const MediaSchema = new mongoose.Schema({
|
const mediaModelLoader = (config) => {
|
||||||
name: { type: String },
|
const MediaSchema = new mongoose.Schema({
|
||||||
caption: { type: String },
|
name: { type: String, intl: true },
|
||||||
description: { type: String },
|
caption: { type: String, intl: true },
|
||||||
filename: { type: String },
|
description: { type: String, intl: true },
|
||||||
});
|
filename: { type: String },
|
||||||
|
sizes: [{
|
||||||
|
height: { type: Number},
|
||||||
|
width: { type: Number},
|
||||||
|
_id: false
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{ timestamps: true }
|
||||||
|
);
|
||||||
|
|
||||||
MediaSchema.plugin(paginate);
|
MediaSchema.plugin(paginate);
|
||||||
MediaSchema.plugin(buildQuery);
|
MediaSchema.plugin(buildQuery);
|
||||||
|
MediaSchema.plugin(internationalization, config.localization);
|
||||||
|
|
||||||
export default mongoose.model('Media', MediaSchema);
|
return mongoose.model('Media', MediaSchema);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default mediaModelLoader;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import httpStatus from 'http-status';
|
import httpStatus from 'http-status';
|
||||||
import { modelById } from '../resolvers';
|
import { modelById } from '../resolvers';
|
||||||
import {createAutopopulateOptions} from '../helpers/mongoose/createAutopopulateOptions';
|
import { createAutopopulateOptions } from '../helpers/mongoose/createAutopopulateOptions';
|
||||||
|
|
||||||
const findOne = (req, res) => {
|
const findOne = (req, res) => {
|
||||||
|
|
||||||
@@ -10,7 +10,7 @@ const findOne = (req, res) => {
|
|||||||
locale: req.locale,
|
locale: req.locale,
|
||||||
fallback: req.query['fallback-locale']
|
fallback: req.query['fallback-locale']
|
||||||
};
|
};
|
||||||
modelById(query, {...createAutopopulateOptions(req.query.depth)})
|
modelById(query, { ...createAutopopulateOptions(req.query.depth) })
|
||||||
.then(doc => res.json(doc))
|
.then(doc => res.json(doc))
|
||||||
.catch(err => res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ error: err }));
|
.catch(err => res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ error: err }));
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const modelById = (query, options)=> {
|
const modelById = (query, options) => {
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
query.Model.findOne({ _id: query.id }, {}, options, (err, doc) => {
|
query.Model.findOne({ _id: query.id }, {}, options, (err, doc) => {
|
||||||
@@ -11,10 +11,12 @@ const modelById = (query, options)=> {
|
|||||||
|
|
||||||
if (query.locale) {
|
if (query.locale) {
|
||||||
doc.setLocale(query.locale, query.fallback);
|
doc.setLocale(query.locale, query.fallback);
|
||||||
const json = doc.toJSON({ virtuals: true });
|
result = doc.toJSON({ virtuals: true });
|
||||||
result = json;
|
|
||||||
}
|
}
|
||||||
resolve(result);
|
|
||||||
|
resolve(options.returnRawDoc
|
||||||
|
? doc
|
||||||
|
: result);
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,25 +1,32 @@
|
|||||||
import express from 'express';
|
import express from 'express';
|
||||||
import passport from 'passport';
|
import passport from 'passport';
|
||||||
import uploadsCtrl from '../controllers/uploads.controller';
|
import { upload, update } from '../controllers/media.controller';
|
||||||
import { query } from '../requestHandlers';
|
import { query } from '../requestHandlers';
|
||||||
import bindModel from '../middleware/bindModel';
|
import bindModel from '../middleware/bindModel';
|
||||||
import Media from '../models/Media.model';
|
import mediaModelLoader from '../models/Media.model';
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const mediaRoutes = config => {
|
const mediaRoutes = config => {
|
||||||
|
|
||||||
router.all('*', bindModel(Media));
|
const mediaModel = mediaModelLoader(config); // Needs config for intl
|
||||||
|
router.all('*', bindModel(mediaModel));
|
||||||
|
|
||||||
router
|
router
|
||||||
.route('')
|
.route('')
|
||||||
.post(
|
.post(
|
||||||
passport.authenticate('jwt', { session: false }),
|
passport.authenticate('jwt', { session: false }),
|
||||||
(req, res, next) => uploadsCtrl.upload(req, res, next, config)
|
(req, res, next) => upload(req, res, next, config)
|
||||||
|
);
|
||||||
|
|
||||||
|
router
|
||||||
|
.route('/:_id')
|
||||||
|
.put(
|
||||||
|
passport.authenticate('jwt', { session: false }),
|
||||||
|
(req, res, next) => update(req, res, next, config)
|
||||||
);
|
);
|
||||||
|
|
||||||
router.route('')
|
router.route('')
|
||||||
.get(
|
.get(
|
||||||
passport.authenticate('jwt', { session: false }),
|
|
||||||
query
|
query
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import sharp from 'sharp';
|
import sharp from 'sharp';
|
||||||
import sizeOf from 'image-size';
|
const { promisify } = require('util');
|
||||||
|
const sizeOf = promisify(require('image-size'));
|
||||||
|
|
||||||
function getOutputImageName(sourceImage, size) {
|
function getOutputImageName(sourceImage, size) {
|
||||||
let extension = sourceImage.split('.').pop();
|
let extension = sourceImage.split('.').pop();
|
||||||
@@ -7,25 +8,27 @@ function getOutputImageName(sourceImage, size) {
|
|||||||
return `${filenameWithoutExtension}-${size.width}x${size.height}.${extension}`;
|
return `${filenameWithoutExtension}-${size.width}x${size.height}.${extension}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resize(config, file) {
|
export async function resizeAndSave(config, file) {
|
||||||
let sourceImage = `${config.staticDir}/${file.name}`;
|
let sourceImage = `${config.staticDir}/${file.name}`;
|
||||||
|
|
||||||
sizeOf(sourceImage, (err, dimensions) => {
|
let outputSizes = [];
|
||||||
for (let size of config.imageSizes) {
|
try {
|
||||||
if (size.width > dimensions.width) {
|
const dimensions = await sizeOf(sourceImage);
|
||||||
console.log(`${size.width} is greater than actual width ${dimensions.width}`);
|
for (let desiredSize of config.imageSizes) {
|
||||||
|
if (desiredSize.width > dimensions.width) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let outputImageName = getOutputImageName(sourceImage, size);
|
let outputImageName = getOutputImageName(sourceImage, desiredSize);
|
||||||
sharp(sourceImage)
|
await sharp(sourceImage)
|
||||||
.resize(size.width, size.height, {
|
.resize(desiredSize.width, desiredSize.height, {
|
||||||
position: size.crop || 'centre'
|
position: desiredSize.crop || 'centre'
|
||||||
})
|
})
|
||||||
.toFile(outputImageName, (err) => {
|
.toFile(outputImageName);
|
||||||
if (err) console.log('Error writing resized file', err);
|
outputSizes.push({ height: desiredSize.height, width: desiredSize.width });
|
||||||
console.log(`Resized image from ${dimensions.width}x${dimensions.height} to ${size.width}x${size.height}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
} catch (e) {
|
||||||
|
console.log('error in resize and save', e.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return outputSizes;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user