uploader.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import { randomUUID } from 'crypto';
  2. import loggerFactory from '~/utils/logger';
  3. const logger = loggerFactory('growi:service:fileUploader');
  4. // file uploader virtual class
  5. // 各アップローダーで共通のメソッドはここで定義する
  6. class Uploader {
  7. constructor(crowi) {
  8. this.crowi = crowi;
  9. this.configManager = crowi.configManager;
  10. }
  11. getIsUploadable() {
  12. return !this.configManager.getConfig('crowi', 'app:fileUploadDisabled') && this.isValidUploadSettings();
  13. }
  14. /**
  15. * Returns whether write opration to the storage is permitted
  16. * @returns Whether write opration to the storage is permitted
  17. */
  18. async isWritable() {
  19. const filePath = `${randomUUID()}.growi`;
  20. const data = 'This file was created during g2g transfer to check write permission. You can safely remove this file.';
  21. try {
  22. await this.saveFile({
  23. filePath,
  24. contentType: 'text/plain',
  25. data,
  26. });
  27. // TODO: delete tmp file in background
  28. return true;
  29. }
  30. catch (err) {
  31. logger.error(err);
  32. return false;
  33. }
  34. }
  35. // File reading is possible even if uploading is disabled
  36. getIsReadable() {
  37. return this.isValidUploadSettings();
  38. }
  39. isValidUploadSettings() {
  40. throw new Error('Implement this');
  41. }
  42. getFileUploadEnabled() {
  43. if (!this.getIsUploadable()) {
  44. return false;
  45. }
  46. return !!this.configManager.getConfig('crowi', 'app:fileUpload');
  47. }
  48. deleteFiles() {
  49. throw new Error('Implemnt this');
  50. }
  51. /**
  52. * Get total file size
  53. * @returns Total file size
  54. */
  55. async getTotalFileSize() {
  56. const Attachment = this.crowi.model('Attachment');
  57. // Get attachment total file size
  58. const res = await Attachment.aggregate().group({
  59. _id: null,
  60. total: { $sum: '$fileSize' },
  61. });
  62. // res is [] if not using
  63. return res.length === 0 ? 0 : res[0].total;
  64. }
  65. /**
  66. * Check files size limits for all uploaders
  67. *
  68. * @param {*} uploadFileSize
  69. * @param {*} maxFileSize
  70. * @param {*} totalLimit
  71. * @returns
  72. * @memberof Uploader
  73. */
  74. async doCheckLimit(uploadFileSize, maxFileSize, totalLimit) {
  75. if (uploadFileSize > maxFileSize) {
  76. return { isUploadable: false, errorMessage: 'File size exceeds the size limit per file' };
  77. }
  78. const usingFilesSize = await this.getTotalFileSize();
  79. if (usingFilesSize + uploadFileSize > totalLimit) {
  80. return { isUploadable: false, errorMessage: 'Uploading files reaches limit' };
  81. }
  82. return { isUploadable: true };
  83. }
  84. /**
  85. * Checks if Uploader can respond to the HTTP request.
  86. */
  87. canRespond() {
  88. return false;
  89. }
  90. /**
  91. * Respond to the HTTP request.
  92. * @param {Response} res
  93. * @param {Response} attachment
  94. */
  95. respond(res, attachment) {
  96. throw new Error('Implement this');
  97. }
  98. }
  99. module.exports = Uploader;