| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309 | 
							- "use strict";
 
- const path = require('path'),
 
- 			Promise = require('bluebird'),
 
- 			fs = Promise.promisifyAll(require('fs-extra')),
 
- 			multer  = require('multer'),
 
- 			request = require('request'),
 
- 			url = require('url'),
 
- 			farmhash = require('farmhash'),
 
- 			_ = require('lodash');
 
- var regFolderName = new RegExp("^[a-z0-9][a-z0-9\-]*[a-z0-9]$");
 
- const maxDownloadFileSize = 3145728; // 3 MB
 
- /**
 
-  * Uploads
 
-  */
 
- module.exports = {
 
- 	_uploadsPath: './repo/uploads',
 
- 	_uploadsThumbsPath: './data/thumbs',
 
- 	/**
 
- 	 * Initialize Local Data Storage model
 
- 	 *
 
- 	 * @param      {Object}  appconfig  The application config
 
- 	 * @return     {Object}  Uploads model instance
 
- 	 */
 
- 	init(appconfig) {
 
- 		this._uploadsPath = path.resolve(ROOTPATH, appconfig.paths.repo, 'uploads');
 
- 		this._uploadsThumbsPath = path.resolve(ROOTPATH, appconfig.paths.data, 'thumbs');
 
- 		return this;
 
- 	},
 
- 	/**
 
- 	 * Gets the thumbnails folder path.
 
- 	 *
 
- 	 * @return     {String}  The thumbs path.
 
- 	 */
 
- 	getThumbsPath() {
 
- 		return this._uploadsThumbsPath;
 
- 	},
 
- 	/**
 
- 	 * Gets the uploads folders.
 
- 	 *
 
- 	 * @return     {Array<String>}  The uploads folders.
 
- 	 */
 
- 	getUploadsFolders() {
 
- 		return db.UplFolder.find({}, 'name').sort('name').exec().then((results) => {
 
- 			return (results) ? _.map(results, 'name') : [{ name: '' }];
 
- 		});
 
- 	},
 
- 	/**
 
- 	 * Creates an uploads folder.
 
- 	 *
 
- 	 * @param      {String}  folderName  The folder name
 
- 	 * @return     {Promise}  Promise of the operation
 
- 	 */
 
- 	createUploadsFolder(folderName) {
 
- 		let self = this;
 
- 		folderName = _.kebabCase(_.trim(folderName));
 
- 		if(_.isEmpty(folderName) || !regFolderName.test(folderName)) {
 
- 			return Promise.resolve(self.getUploadsFolders());
 
- 		}
 
- 		return fs.ensureDirAsync(path.join(self._uploadsPath, folderName)).then(() => {
 
- 			return db.UplFolder.findOneAndUpdate({
 
- 				_id: 'f:' + folderName
 
- 			}, {
 
- 				name: folderName
 
- 			}, {
 
- 				upsert: true
 
- 			});
 
- 		}).then(() => {
 
- 			return self.getUploadsFolders();
 
- 		});
 
- 	},
 
- 	/**
 
- 	 * Check if folder is valid and exists
 
- 	 *
 
- 	 * @param      {String}  folderName  The folder name
 
- 	 * @return     {Boolean}   True if valid
 
- 	 */
 
- 	validateUploadsFolder(folderName) {
 
- 		return db.UplFolder.findOne({ name: folderName }).then((f) => {
 
- 			return (f) ? path.resolve(this._uploadsPath, folderName) : false;
 
- 		});
 
- 	},
 
- 	/**
 
- 	 * Adds one or more uploads files.
 
- 	 *
 
- 	 * @param      {Array<Object>}  arrFiles  The uploads files
 
- 	 * @return     {Void}  Void
 
- 	 */
 
- 	addUploadsFiles(arrFiles) {
 
- 		if(_.isArray(arrFiles) || _.isPlainObject(arrFiles)) {
 
- 			//this._uploadsDb.Files.insert(arrFiles);
 
- 		}
 
- 		return;
 
- 	},
 
- 	/**
 
- 	 * Gets the uploads files.
 
- 	 *
 
- 	 * @param      {String}  cat     Category type
 
- 	 * @param      {String}  fld     Folder
 
- 	 * @return     {Array<Object>}  The files matching the query
 
- 	 */
 
- 	getUploadsFiles(cat, fld) {
 
- 		return db.UplFile.find({
 
- 			category: cat,
 
- 			folder: 'f:' + fld
 
- 		}).sort('filename').exec();
 
- 	},
 
- 	/**
 
- 	 * Deletes an uploads file.
 
- 	 *
 
- 	 * @param      {string}   uid     The file unique ID
 
- 	 * @return     {Promise}  Promise of the operation
 
- 	 */
 
- 	deleteUploadsFile(uid) {
 
- 		let self = this;
 
- 		return db.UplFile.findOneAndRemove({ _id: uid }).then((f) => {
 
- 			if(f) {
 
- 				return self.deleteUploadsFileTry(f, 0);
 
- 			}
 
- 			return true;
 
- 		});
 
- 	},
 
- 	deleteUploadsFileTry(f, attempt) {
 
- 		let self = this;
 
- 		let fFolder = (f.folder && f.folder !== 'f:') ? f.folder.slice(2) : './';
 
- 		return Promise.join(
 
- 			fs.removeAsync(path.join(self._uploadsThumbsPath, f._id + '.png')),
 
- 			fs.removeAsync(path.resolve(self._uploadsPath, fFolder, f.filename))
 
- 		).catch((err) => {
 
- 			if(err.code === 'EBUSY' && attempt < 5) {
 
- 				return Promise.delay(100).then(() => {
 
- 					return self.deleteUploadsFileTry(f, attempt + 1);
 
- 				});
 
- 			} else {
 
- 				winston.warn('Unable to delete uploads file ' + f.filename + '. File is locked by another process and multiple attempts failed.');
 
- 				return true;
 
- 			}
 
- 		});
 
- 	},
 
- 	/**
 
- 	 * Downloads a file from url.
 
- 	 *
 
- 	 * @param      {String}   fFolder  The folder
 
- 	 * @param      {String}   fUrl     The full URL
 
- 	 * @return     {Promise}  Promise of the operation
 
- 	 */
 
- 	downloadFromUrl(fFolder, fUrl) {
 
- 		let self = this;
 
- 		let fUrlObj = url.parse(fUrl);
 
- 		let fUrlFilename = _.last(_.split(fUrlObj.pathname, '/'));
 
- 		let destFolder = _.chain(fFolder).trim().toLower().value();
 
- 		return upl.validateUploadsFolder(destFolder).then((destFolderPath) => {
 
- 			
 
- 			if(!destFolderPath) {
 
- 				return Promise.reject(new Error('Invalid Folder'));
 
- 			}
 
- 			return lcdata.validateUploadsFilename(fUrlFilename, destFolder).then((destFilename) => {
 
- 				
 
- 				let destFilePath = path.resolve(destFolderPath, destFilename);
 
- 				return new Promise((resolve, reject) => {
 
- 					let rq = request({
 
- 						url: fUrl,
 
- 						method: 'GET',
 
- 						followRedirect: true,
 
- 						maxRedirects: 5,
 
- 						timeout: 10000
 
- 					});
 
- 					let destFileStream = fs.createWriteStream(destFilePath);
 
- 					let curFileSize = 0;
 
- 					rq.on('data', (data) => {
 
- 						curFileSize += data.length;
 
- 						if(curFileSize > maxDownloadFileSize) {
 
- 							rq.abort();
 
- 							destFileStream.destroy();
 
- 							fs.remove(destFilePath);
 
- 							reject(new Error('Remote file is too large!'));
 
- 						}
 
- 					}).on('error', (err) => {
 
- 						destFileStream.destroy();
 
- 						fs.remove(destFilePath);
 
- 						reject(err);
 
- 					});
 
- 					destFileStream.on('finish', () => {
 
- 						resolve(true);
 
- 					})
 
- 					rq.pipe(destFileStream);
 
- 				});
 
- 			});
 
- 		});
 
- 	},
 
- 	/**
 
- 	 * Move/Rename a file
 
- 	 *
 
- 	 * @param      {String}   uid        The file ID
 
- 	 * @param      {String}   fld        The destination folder
 
- 	 * @param      {String}   nFilename  The new filename (optional)
 
- 	 * @return     {Promise}  Promise of the operation
 
- 	 */
 
- 	moveUploadsFile(uid, fld, nFilename) {
 
- 		let self = this;
 
- 		return db.UplFolder.findById('f:' + fld).then((folder) => {
 
- 			if(folder) {
 
- 				return db.UplFile.findById(uid).then((originFile) => {
 
- 					//-> Check if rename is valid
 
- 					let nameCheck = null;
 
- 					if(nFilename) {
 
- 						let originFileObj = path.parse(originFile.filename);
 
- 						nameCheck = lcdata.validateUploadsFilename(nFilename + originFileObj.ext, folder.name);
 
- 					} else {
 
- 						nameCheck = Promise.resolve(originFile.filename);
 
- 					}
 
- 					return nameCheck.then((destFilename) => {
 
- 						let originFolder = (originFile.folder && originFile.folder !== 'f:') ? originFile.folder.slice(2) : './';
 
- 						let sourceFilePath = path.resolve(self._uploadsPath, originFolder, originFile.filename);
 
- 						let destFilePath = path.resolve(self._uploadsPath, folder.name, destFilename);
 
- 						let preMoveOps = [];
 
- 						//-> Check for invalid operations
 
- 						if(sourceFilePath === destFilePath) {
 
- 							return Promise.reject(new Error('Invalid Operation!'));
 
- 						}
 
- 						//-> Delete DB entry
 
- 						preMoveOps.push(db.UplFile.findByIdAndRemove(uid));
 
- 						//-> Move thumbnail ahead to avoid re-generation
 
- 						if(originFile.category === 'image') {
 
- 							let fUid = farmhash.fingerprint32(folder.name + '/' + destFilename);
 
- 							let sourceThumbPath = path.resolve(self._uploadsThumbsPath, originFile._id + '.png');
 
- 							let destThumbPath = path.resolve(self._uploadsThumbsPath, fUid + '.png');
 
- 							preMoveOps.push(fs.moveAsync(sourceThumbPath, destThumbPath));
 
- 						} else {
 
- 							preMoveOps.push(Promise.resolve(true));
 
- 						}
 
- 						//-> Proceed to move actual file
 
- 						return Promise.all(preMoveOps).then(() => {
 
- 							return fs.moveAsync(sourceFilePath, destFilePath, {
 
- 								clobber: false
 
- 							});
 
- 						});
 
- 					})
 
- 				});
 
- 			} else {
 
- 				return Promise.reject(new Error('Invalid Destination Folder'));
 
- 			}
 
- 		});
 
- 	}
 
- };
 
 
  |