disk.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. 'use strict'
  2. /* global wiki */
  3. const path = require('path')
  4. const Promise = require('bluebird')
  5. const fs = Promise.promisifyAll(require('fs-extra'))
  6. const multer = require('multer')
  7. const os = require('os')
  8. const _ = require('lodash')
  9. /**
  10. * Local Disk Storage
  11. */
  12. module.exports = {
  13. _uploadsPath: './repo/uploads',
  14. _uploadsThumbsPath: './data/thumbs',
  15. uploadImgHandler: null,
  16. /**
  17. * Initialize Local Data Storage model
  18. */
  19. init () {
  20. this._uploadsPath = path.resolve(wiki.ROOTPATH, wiki.config.paths.repo, 'uploads')
  21. this._uploadsThumbsPath = path.resolve(wiki.ROOTPATH, wiki.config.paths.data, 'thumbs')
  22. this.createBaseDirectories()
  23. this.initMulter()
  24. return this
  25. },
  26. /**
  27. * Init Multer upload handlers
  28. */
  29. initMulter () {
  30. let maxFileSizes = {
  31. img: wiki.config.uploads.maxImageFileSize * 1024 * 1024,
  32. file: wiki.config.uploads.maxOtherFileSize * 1024 * 1024
  33. }
  34. // -> IMAGES
  35. this.uploadImgHandler = multer({
  36. storage: multer.diskStorage({
  37. destination: (req, f, cb) => {
  38. cb(null, path.resolve(wiki.ROOTPATH, wiki.config.paths.data, 'temp-upload'))
  39. }
  40. }),
  41. fileFilter: (req, f, cb) => {
  42. // -> Check filesize
  43. if (f.size > maxFileSizes.img) {
  44. return cb(null, false)
  45. }
  46. // -> Check MIME type (quick check only)
  47. if (!_.includes(['image/png', 'image/jpeg', 'image/gif', 'image/webp'], f.mimetype)) {
  48. return cb(null, false)
  49. }
  50. cb(null, true)
  51. }
  52. }).array('imgfile', 20)
  53. // -> FILES
  54. this.uploadFileHandler = multer({
  55. storage: multer.diskStorage({
  56. destination: (req, f, cb) => {
  57. cb(null, path.resolve(wiki.ROOTPATH, wiki.config.paths.data, 'temp-upload'))
  58. }
  59. }),
  60. fileFilter: (req, f, cb) => {
  61. // -> Check filesize
  62. if (f.size > maxFileSizes.file) {
  63. return cb(null, false)
  64. }
  65. cb(null, true)
  66. }
  67. }).array('binfile', 20)
  68. return true
  69. },
  70. /**
  71. * Creates a base directories (Synchronous).
  72. */
  73. createBaseDirectories () {
  74. wiki.logger.info('Checking data directories...')
  75. try {
  76. fs.ensureDirSync(path.resolve(wiki.ROOTPATH, wiki.config.paths.data))
  77. fs.emptyDirSync(path.resolve(wiki.ROOTPATH, wiki.config.paths.data))
  78. fs.ensureDirSync(path.resolve(wiki.ROOTPATH, wiki.config.paths.data, './cache'))
  79. fs.ensureDirSync(path.resolve(wiki.ROOTPATH, wiki.config.paths.data, './thumbs'))
  80. fs.ensureDirSync(path.resolve(wiki.ROOTPATH, wiki.config.paths.data, './temp-upload'))
  81. if (os.type() !== 'Windows_NT') {
  82. fs.chmodSync(path.resolve(wiki.ROOTPATH, wiki.config.paths.data, './temp-upload'), '755')
  83. }
  84. fs.ensureDirSync(path.resolve(wiki.ROOTPATH, wiki.config.paths.repo))
  85. fs.ensureDirSync(path.resolve(wiki.ROOTPATH, wiki.config.paths.repo, './uploads'))
  86. if (os.type() !== 'Windows_NT') {
  87. fs.chmodSync(path.resolve(wiki.ROOTPATH, wiki.config.paths.repo, './uploads'), '755')
  88. }
  89. } catch (err) {
  90. wiki.logger.error(err)
  91. }
  92. wiki.logger.info('Data and Repository directories are OK.')
  93. },
  94. /**
  95. * Gets the uploads path.
  96. *
  97. * @return {String} The uploads path.
  98. */
  99. getUploadsPath () {
  100. return this._uploadsPath
  101. },
  102. /**
  103. * Gets the thumbnails folder path.
  104. *
  105. * @return {String} The thumbs path.
  106. */
  107. getThumbsPath () {
  108. return this._uploadsThumbsPath
  109. },
  110. /**
  111. * Check if filename is valid and unique
  112. *
  113. * @param {String} f The filename
  114. * @param {String} fld The containing folder
  115. * @param {boolean} isImage Indicates if image
  116. * @return {Promise<String>} Promise of the accepted filename
  117. */
  118. validateUploadsFilename (f, fld, isImage) {
  119. let fObj = path.parse(f)
  120. let fname = _.chain(fObj.name).trim().toLower().kebabCase().value().replace(new RegExp('[^a-z0-9-' + wiki.data.regex.cjk + wiki.data.regex.arabic + ']', 'g'), '')
  121. let fext = _.toLower(fObj.ext)
  122. if (isImage && !_.includes(['.jpg', '.jpeg', '.png', '.gif', '.webp'], fext)) {
  123. fext = '.png'
  124. }
  125. f = fname + fext
  126. let fpath = path.resolve(this._uploadsPath, fld, f)
  127. return fs.statAsync(fpath).then((s) => {
  128. throw new Error(wiki.lang.t('errors:fileexists', { path: f }))
  129. }).catch((err) => {
  130. if (err.code === 'ENOENT') {
  131. return f
  132. }
  133. throw err
  134. })
  135. }
  136. }