You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

151 lines
3.4 KiB

  1. "use strict";
  2. var path = require('path'),
  3. Promise = require('bluebird'),
  4. fs = Promise.promisifyAll(require('fs-extra')),
  5. multer = require('multer'),
  6. _ = require('lodash');
  7. /**
  8. * Local Data Storage
  9. *
  10. * @param {Object} appconfig The application configuration
  11. */
  12. module.exports = {
  13. _uploadsPath: './repo/uploads',
  14. _uploadsThumbsPath: './data/thumbs',
  15. uploadImgHandler: null,
  16. /**
  17. * Initialize Local Data Storage model
  18. *
  19. * @param {Object} appconfig The application config
  20. * @return {Object} Local Data Storage model instance
  21. */
  22. init(appconfig) {
  23. this._uploadsPath = path.resolve(ROOTPATH, appconfig.paths.repo, 'uploads');
  24. this._uploadsThumbsPath = path.resolve(ROOTPATH, appconfig.paths.data, 'thumbs');
  25. this.createBaseDirectories(appconfig);
  26. this.initMulter(appconfig);
  27. return this;
  28. },
  29. /**
  30. * Init Multer upload handlers
  31. *
  32. * @param {Object} appconfig The application config
  33. * @return {boolean} Void
  34. */
  35. initMulter(appconfig) {
  36. this.uploadImgHandler = multer({
  37. storage: multer.diskStorage({
  38. destination: (req, f, cb) => {
  39. cb(null, path.resolve(ROOTPATH, appconfig.paths.data, 'temp-upload'));
  40. }
  41. }),
  42. fileFilter: (req, f, cb) => {
  43. //-> Check filesize (3 MB max)
  44. if(f.size > 3145728) {
  45. return cb(null, false);
  46. }
  47. //-> Check MIME type (quick check only)
  48. if(!_.includes(['image/png', 'image/jpeg', 'image/gif', 'image/webp'], f.mimetype)) {
  49. return cb(null, false);
  50. }
  51. cb(null, true);
  52. }
  53. }).array('imgfile', 20);
  54. return true;
  55. },
  56. /**
  57. * Creates a base directories (Synchronous).
  58. *
  59. * @param {Object} appconfig The application config
  60. * @return {Void} Void
  61. */
  62. createBaseDirectories(appconfig) {
  63. winston.info('[SERVER] Checking data directories...');
  64. try {
  65. fs.ensureDirSync(path.resolve(ROOTPATH, appconfig.paths.data));
  66. fs.ensureDirSync(path.resolve(ROOTPATH, appconfig.paths.data, './cache'));
  67. fs.ensureDirSync(path.resolve(ROOTPATH, appconfig.paths.data, './thumbs'));
  68. fs.ensureDirSync(path.resolve(ROOTPATH, appconfig.paths.data, './temp-upload'));
  69. fs.ensureDirSync(path.resolve(ROOTPATH, appconfig.paths.repo));
  70. fs.ensureDirSync(path.resolve(ROOTPATH, appconfig.paths.repo, './uploads'));
  71. } catch (err) {
  72. winston.error(err);
  73. }
  74. winston.info('[SERVER] Data and Repository directories are OK.');
  75. return;
  76. },
  77. /**
  78. * Gets the uploads path.
  79. *
  80. * @return {String} The uploads path.
  81. */
  82. getUploadsPath() {
  83. return this._uploadsPath;
  84. },
  85. /**
  86. * Gets the thumbnails folder path.
  87. *
  88. * @return {String} The thumbs path.
  89. */
  90. getThumbsPath() {
  91. return this._uploadsThumbsPath;
  92. },
  93. /**
  94. * Check if filename is valid and unique
  95. *
  96. * @param {String} f The filename
  97. * @param {String} fld The containing folder
  98. * @return {Promise<String>} Promise of the accepted filename
  99. */
  100. validateUploadsFilename(f, fld) {
  101. let fObj = path.parse(f);
  102. let fname = _.chain(fObj.name).trim().toLower().kebabCase().value().replace(/[^a-z0-9\-]+/g, '');
  103. let fext = _.toLower(fObj.ext);
  104. if(!_.includes(['.jpg', '.jpeg', '.png', '.gif', '.webp'], fext)) {
  105. fext = '.png';
  106. }
  107. f = fname + fext;
  108. let fpath = path.resolve(this._uploadsPath, fld, f);
  109. return fs.statAsync(fpath).then((s) => {
  110. throw new Error('File ' + f + ' already exists.');
  111. }).catch((err) => {
  112. if(err.code === 'ENOENT') {
  113. return f;
  114. }
  115. throw err;
  116. });
  117. },
  118. };