| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 | 
							- 'use strict'
 
- const path = require('path')
 
- const Promise = require('bluebird')
 
- const fs = Promise.promisifyAll(require('fs-extra'))
 
- const readChunk = require('read-chunk')
 
- const fileType = require('file-type')
 
- const mime = require('mime-types')
 
- const crypto = require('crypto')
 
- const chokidar = require('chokidar')
 
- const jimp = require('jimp')
 
- const imageSize = Promise.promisify(require('image-size'))
 
- const _ = require('lodash')
 
- /**
 
-  * Uploads - Agent
 
-  */
 
- module.exports = {
 
-   _uploadsPath: './repo/uploads',
 
-   _uploadsThumbsPath: './data/thumbs',
 
-   _watcher: null,
 
-   /**
 
-    * Initialize Uploads model
 
-    *
 
-    * @return     {Object}  Uploads model instance
 
-    */
 
-   init () {
 
-     let self = this
 
-     self._uploadsPath = path.resolve(ROOTPATH, appconfig.paths.repo, 'uploads')
 
-     self._uploadsThumbsPath = path.resolve(ROOTPATH, appconfig.paths.data, 'thumbs')
 
-     return self
 
-   },
 
-   /**
 
-    * Watch the uploads folder for changes
 
-    *
 
-    * @return     {Void}  Void
 
-    */
 
-   watch () {
 
-     let self = this
 
-     self._watcher = chokidar.watch(self._uploadsPath, {
 
-       persistent: true,
 
-       ignoreInitial: true,
 
-       cwd: self._uploadsPath,
 
-       depth: 1,
 
-       awaitWriteFinish: true
 
-     })
 
-     // -> Add new upload file
 
-     self._watcher.on('add', (p) => {
 
-       let pInfo = self.parseUploadsRelPath(p)
 
-       return self.processFile(pInfo.folder, pInfo.filename).then((mData) => {
 
-         return db.UplFile.findByIdAndUpdate(mData._id, mData, { upsert: true })
 
-       }).then(() => {
 
-         return git.commitUploads('Uploaded ' + p)
 
-       })
 
-     })
 
-     // -> Remove upload file
 
-     self._watcher.on('unlink', (p) => {
 
-       return git.commitUploads('Deleted/Renamed ' + p)
 
-     })
 
-   },
 
-   /**
 
-    * Initial Uploads scan
 
-    *
 
-    * @return     {Promise<Void>}  Promise of the scan operation
 
-    */
 
-   initialScan () {
 
-     let self = this
 
-     return fs.readdirAsync(self._uploadsPath).then((ls) => {
 
-       // Get all folders
 
-       return Promise.map(ls, (f) => {
 
-         return fs.statAsync(path.join(self._uploadsPath, f)).then((s) => { return { filename: f, stat: s } })
 
-       }).filter((s) => { return s.stat.isDirectory() }).then((arrDirs) => {
 
-         let folderNames = _.map(arrDirs, 'filename')
 
-         folderNames.unshift('')
 
-         // Add folders to DB
 
-         return db.UplFolder.remove({}).then(() => {
 
-           return db.UplFolder.insertMany(_.map(folderNames, (f) => {
 
-             return {
 
-               _id: 'f:' + f,
 
-               name: f
 
-             }
 
-           }))
 
-         }).then(() => {
 
-           // Travel each directory and scan files
 
-           let allFiles = []
 
-           return Promise.map(folderNames, (fldName) => {
 
-             let fldPath = path.join(self._uploadsPath, fldName)
 
-             return fs.readdirAsync(fldPath).then((fList) => {
 
-               return Promise.map(fList, (f) => {
 
-                 return upl.processFile(fldName, f).then((mData) => {
 
-                   if (mData) {
 
-                     allFiles.push(mData)
 
-                   }
 
-                   return true
 
-                 })
 
-               }, {concurrency: 3})
 
-             })
 
-           }, {concurrency: 1}).finally(() => {
 
-             // Add files to DB
 
-             return db.UplFile.remove({}).then(() => {
 
-               if (_.isArray(allFiles) && allFiles.length > 0) {
 
-                 return db.UplFile.insertMany(allFiles)
 
-               } else {
 
-                 return true
 
-               }
 
-             })
 
-           })
 
-         })
 
-       })
 
-     }).then(() => {
 
-       // Watch for new changes
 
-       return upl.watch()
 
-     })
 
-   },
 
-   /**
 
-    * Parse relative Uploads path
 
-    *
 
-    * @param      {String}  f       Relative Uploads path
 
-    * @return     {Object}  Parsed path (folder and filename)
 
-    */
 
-   parseUploadsRelPath (f) {
 
-     let fObj = path.parse(f)
 
-     return {
 
-       folder: fObj.dir,
 
-       filename: fObj.base
 
-     }
 
-   },
 
-   /**
 
-    * Get metadata from file and generate thumbnails if necessary
 
-    *
 
-    * @param      {String}  fldName  The folder name
 
-    * @param      {String}  f        The filename
 
-    * @return     {Promise<Object>}  Promise of the file metadata
 
-    */
 
-   processFile (fldName, f) {
 
-     let self = this
 
-     let fldPath = path.join(self._uploadsPath, fldName)
 
-     let fPath = path.join(fldPath, f)
 
-     let fPathObj = path.parse(fPath)
 
-     let fUid = crypto.createHash('md5').update(fldName + '/' + f).digest('hex')
 
-     return fs.statAsync(fPath).then((s) => {
 
-       if (!s.isFile()) { return false }
 
-       // Get MIME info
 
-       let mimeInfo = fileType(readChunk.sync(fPath, 0, 262))
 
-       if (_.isNil(mimeInfo)) {
 
-         mimeInfo = {
 
-           mime: mime.lookup(fPathObj.ext) || 'application/octet-stream'
 
-         }
 
-       }
 
-       // Images
 
-       if (s.size < 3145728) { // ignore files larger than 3MB
 
-         if (_.includes(['image/png', 'image/jpeg', 'image/gif', 'image/bmp'], mimeInfo.mime)) {
 
-           return self.getImageSize(fPath).then((mImgSize) => {
 
-             let cacheThumbnailPath = path.parse(path.join(self._uploadsThumbsPath, fUid + '.png'))
 
-             let cacheThumbnailPathStr = path.format(cacheThumbnailPath)
 
-             let mData = {
 
-               _id: fUid,
 
-               category: 'image',
 
-               mime: mimeInfo.mime,
 
-               extra: mImgSize,
 
-               folder: 'f:' + fldName,
 
-               filename: f,
 
-               basename: fPathObj.name,
 
-               filesize: s.size
 
-             }
 
-             // Generate thumbnail
 
-             return fs.statAsync(cacheThumbnailPathStr).then((st) => {
 
-               return st.isFile()
 
-             }).catch((err) => { // eslint-disable-line handle-callback-err
 
-               return false
 
-             }).then((thumbExists) => {
 
-               return (thumbExists) ? mData : fs.ensureDirAsync(cacheThumbnailPath.dir).then(() => {
 
-                 return self.generateThumbnail(fPath, cacheThumbnailPathStr)
 
-               }).return(mData)
 
-             })
 
-           })
 
-         }
 
-       }
 
-       // Other Files
 
-       return {
 
-         _id: fUid,
 
-         category: 'binary',
 
-         mime: mimeInfo.mime,
 
-         folder: 'f:' + fldName,
 
-         filename: f,
 
-         basename: fPathObj.name,
 
-         filesize: s.size
 
-       }
 
-     })
 
-   },
 
-   /**
 
-    * Generate thumbnail of image
 
-    *
 
-    * @param      {String}           sourcePath  The source path
 
-    * @param      {String}           destPath    The destination path
 
-    * @return     {Promise<Object>}  Promise returning the resized image info
 
-    */
 
-   generateThumbnail (sourcePath, destPath) {
 
-     return jimp.read(sourcePath).then(img => {
 
-       return img
 
-               .contain(150, 150)
 
-               .write(destPath)
 
-     })
 
-   },
 
-   /**
 
-    * Gets the image dimensions.
 
-    *
 
-    * @param      {String}  sourcePath  The source path
 
-    * @return     {Object}  The image dimensions.
 
-    */
 
-   getImageSize (sourcePath) {
 
-     return imageSize(sourcePath)
 
-   }
 
- }
 
 
  |