attachment.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. // disable no-return-await for model functions
  2. /* eslint-disable no-return-await */
  3. const debug = require('debug')('growi:models:attachment');
  4. // eslint-disable-next-line no-unused-vars
  5. const logger = require('@alias/logger')('growi:models:attachment');
  6. const path = require('path');
  7. const mongoose = require('mongoose');
  8. const ObjectId = mongoose.Schema.Types.ObjectId;
  9. module.exports = function(crowi) {
  10. const fileUploader = require('../service/file-uploader')(crowi);
  11. function generateFileHash(fileName) {
  12. const hash = require('crypto').createHash('md5');
  13. hash.update(`${fileName}_${Date.now()}`);
  14. return hash.digest('hex');
  15. }
  16. const attachmentSchema = new mongoose.Schema({
  17. page: { type: ObjectId, ref: 'Page', index: true },
  18. creator: { type: ObjectId, ref: 'User', index: true },
  19. filePath: { type: String }, // DEPRECATED: remains for backward compatibility for v3.3.x or below
  20. fileName: { type: String, required: true },
  21. originalName: { type: String },
  22. fileFormat: { type: String, required: true },
  23. fileSize: { type: Number, default: 0 },
  24. createdAt: { type: Date, default: Date.now },
  25. });
  26. attachmentSchema.virtual('filePathProxied').get(function() {
  27. return `/attachment/${this._id}`;
  28. });
  29. attachmentSchema.virtual('downloadPathProxied').get(function() {
  30. return `/download/${this._id}`;
  31. });
  32. attachmentSchema.set('toObject', { virtuals: true });
  33. attachmentSchema.set('toJSON', { virtuals: true });
  34. attachmentSchema.statics.create = async function(pageId, user, fileStream, originalName, fileFormat, fileSize) {
  35. const Attachment = this;
  36. const extname = path.extname(originalName);
  37. let fileName = generateFileHash(originalName);
  38. if (extname.length > 1) { // ignore if empty or '.' only
  39. fileName = `${fileName}${extname}`;
  40. }
  41. let attachment = new Attachment();
  42. attachment.page = pageId;
  43. attachment.creator = user._id;
  44. attachment.originalName = originalName;
  45. attachment.fileName = fileName;
  46. attachment.fileFormat = fileFormat;
  47. attachment.fileSize = fileSize;
  48. attachment.createdAt = Date.now();
  49. // upload file
  50. await fileUploader.uploadFile(fileStream, attachment);
  51. // save attachment
  52. attachment = await attachment.save();
  53. return attachment;
  54. };
  55. attachmentSchema.statics.removeAttachmentsByPageId = function(pageId) {
  56. const Attachment = this;
  57. return new Promise((resolve, reject) => {
  58. Attachment.find({ page: pageId })
  59. .then((attachments) => {
  60. for (const attachment of attachments) {
  61. Attachment.removeWithSubstanceById(attachment._id)
  62. .then((res) => {
  63. // do nothing
  64. })
  65. .catch((err) => {
  66. debug('Attachment remove error', err);
  67. });
  68. }
  69. resolve(attachments);
  70. })
  71. .catch((err) => {
  72. reject(err);
  73. });
  74. });
  75. };
  76. attachmentSchema.statics.removeWithSubstanceById = async function(id) {
  77. // retrieve data from DB to get a completely populated instance
  78. const attachment = await this.findById(id);
  79. await fileUploader.deleteFile(attachment);
  80. return await attachment.remove();
  81. };
  82. return mongoose.model('Attachment', attachmentSchema);
  83. };