gridfs.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. const logger = require('@alias/logger')('growi:service:fileUploaderGridfs');
  2. const mongoose = require('mongoose');
  3. const util = require('util');
  4. module.exports = function(crowi) {
  5. const Uploader = require('./uploader');
  6. const lib = new Uploader(crowi.configManager);
  7. const COLLECTION_NAME = 'attachmentFiles';
  8. const CHUNK_COLLECTION_NAME = `${COLLECTION_NAME}.chunks`;
  9. // instantiate mongoose-gridfs
  10. const { createModel } = require('mongoose-gridfs');
  11. const AttachmentFile = createModel({
  12. modelName: COLLECTION_NAME,
  13. bucketName: COLLECTION_NAME,
  14. connection: mongoose.connection,
  15. });
  16. // get Collection instance of chunk
  17. const chunkCollection = mongoose.connection.collection(CHUNK_COLLECTION_NAME);
  18. // create promisified method
  19. AttachmentFile.promisifiedWrite = util.promisify(AttachmentFile.write).bind(AttachmentFile);
  20. AttachmentFile.promisifiedUnlink = util.promisify(AttachmentFile.unlink).bind(AttachmentFile);
  21. lib.getIsUploadable = function() {
  22. return true;
  23. };
  24. lib.deleteFile = async function(attachment) {
  25. let filenameValue = attachment.fileName;
  26. if (attachment.filePath != null) { // backward compatibility for v3.3.x or below
  27. filenameValue = attachment.filePath;
  28. }
  29. const attachmentFile = await AttachmentFile.findOne({ filename: filenameValue });
  30. if (attachmentFile == null) {
  31. logger.warn(`Any AttachmentFile that relate to the Attachment (${attachment._id.toString()}) does not exist in GridFS`);
  32. return;
  33. }
  34. return AttachmentFile.promisifiedUnlink({ _id: attachmentFile._id });
  35. };
  36. /**
  37. * get size of data uploaded files using (Promise wrapper)
  38. */
  39. const getCollectionSize = () => {
  40. return new Promise((resolve, reject) => {
  41. chunkCollection.stats((err, data) => {
  42. if (err) {
  43. // return 0 if not exist
  44. if (err.errmsg.includes('not found')) {
  45. return resolve(0);
  46. }
  47. return reject(err);
  48. }
  49. return resolve(data.size);
  50. });
  51. });
  52. };
  53. /**
  54. * check the file size limit
  55. *
  56. * In detail, the followings are checked.
  57. * - per-file size limit (specified by MAX_FILE_SIZE)
  58. * - mongodb(gridfs) size limit (specified by MONGO_GRIDFS_TOTAL_LIMIT)
  59. */
  60. lib.checkLimit = async(uploadFileSize) => {
  61. const maxFileSize = crowi.configManager.getConfig('crowi', 'app:maxFileSize');
  62. if (uploadFileSize > maxFileSize) {
  63. return { isUploadable: false, errorMessage: 'File size exceeds the size limit per file' };
  64. }
  65. let usingFilesSize;
  66. try {
  67. usingFilesSize = await getCollectionSize();
  68. }
  69. catch (err) {
  70. logger.error(err);
  71. return { isUploadable: false, errorMessage: err.errmsg };
  72. }
  73. // Use app:fileUploadTotalLimit if gridfs:totalLimit is null (default for gridfs:totalLimitd is null)
  74. const gridfsTotalLimit = crowi.configManager.getConfig('crowi', 'gridfs:totalLimit')
  75. || crowi.configManager.getConfig('crowi', 'app:fileUploadTotalLimit');
  76. if (usingFilesSize + uploadFileSize > gridfsTotalLimit) {
  77. return { isUploadable: false, errorMessage: 'MongoDB for uploading files reaches limit' };
  78. }
  79. return { isUploadable: true };
  80. };
  81. lib.uploadFile = async function(fileStream, attachment) {
  82. logger.debug(`File uploading: fileName=${attachment.fileName}`);
  83. return AttachmentFile.promisifiedWrite(
  84. {
  85. filename: attachment.fileName,
  86. contentType: attachment.fileFormat,
  87. },
  88. fileStream,
  89. );
  90. };
  91. /**
  92. * Find data substance
  93. *
  94. * @param {Attachment} attachment
  95. * @return {stream.Readable} readable stream
  96. */
  97. lib.findDeliveryFile = async function(attachment) {
  98. let filenameValue = attachment.fileName;
  99. if (attachment.filePath != null) { // backward compatibility for v3.3.x or below
  100. filenameValue = attachment.filePath;
  101. }
  102. const attachmentFile = await AttachmentFile.findOne({ filename: filenameValue });
  103. if (attachmentFile == null) {
  104. throw new Error(`Any AttachmentFile that relate to the Attachment (${attachment._id.toString()}) does not exist in GridFS`);
  105. }
  106. // return stream.Readable
  107. return AttachmentFile.read({ _id: attachmentFile._id });
  108. };
  109. return lib;
  110. };