attachment.js 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. // disable no-return-await for model functions
  2. /* eslint-disable no-return-await */
  3. // eslint-disable-next-line no-unused-vars
  4. const logger = require('@alias/logger')('growi:models:attachment');
  5. const path = require('path');
  6. const mongoose = require('mongoose');
  7. const uniqueValidator = require('mongoose-unique-validator');
  8. const mongoosePaginate = require('mongoose-paginate-v2');
  9. const { addSeconds } = require('date-fns');
  10. const ObjectId = mongoose.Schema.Types.ObjectId;
  11. module.exports = function(crowi) {
  12. const SECONDS_OF_CASH_EXPIRATION = 120;
  13. function generateFileHash(fileName) {
  14. const hash = require('crypto').createHash('md5');
  15. hash.update(`${fileName}_${Date.now()}`);
  16. return hash.digest('hex');
  17. }
  18. const attachmentSchema = new mongoose.Schema({
  19. page: { type: ObjectId, ref: 'Page', index: true },
  20. creator: { type: ObjectId, ref: 'User', index: true },
  21. filePath: { type: String }, // DEPRECATED: remains for backward compatibility for v3.3.x or below
  22. fileName: { type: String, required: true, unique: true },
  23. originalName: { type: String },
  24. fileFormat: { type: String, required: true },
  25. fileSize: { type: Number, default: 0 },
  26. createdAt: { type: Date, default: Date.now },
  27. externalUrlCached: { type: String },
  28. externalUrlExpiredAt: { type: Date },
  29. });
  30. attachmentSchema.plugin(uniqueValidator);
  31. attachmentSchema.plugin(mongoosePaginate);
  32. attachmentSchema.virtual('filePathProxied').get(function() {
  33. return `/attachment/${this._id}`;
  34. });
  35. attachmentSchema.virtual('downloadPathProxied').get(function() {
  36. return `/download/${this._id}`;
  37. });
  38. attachmentSchema.set('toObject', { virtuals: true });
  39. attachmentSchema.set('toJSON', { virtuals: true });
  40. attachmentSchema.statics.createWithoutSave = function(pageId, user, fileStream, originalName, fileFormat, fileSize) {
  41. const Attachment = this;
  42. const extname = path.extname(originalName);
  43. let fileName = generateFileHash(originalName);
  44. if (extname.length > 1) { // ignore if empty or '.' only
  45. fileName = `${fileName}${extname}`;
  46. }
  47. const attachment = new Attachment();
  48. attachment.page = pageId;
  49. attachment.creator = user._id;
  50. attachment.originalName = originalName;
  51. attachment.fileName = fileName;
  52. attachment.fileFormat = fileFormat;
  53. attachment.fileSize = fileSize;
  54. attachment.createdAt = Date.now();
  55. return attachment;
  56. };
  57. attachmentSchema.methods.isValidExternalUrl = function() {
  58. if (this.externalUrlExpiredAt == null) {
  59. return false;
  60. }
  61. return this.externalUrlExpiredAt.getTime() > new Date().getTime();
  62. };
  63. attachmentSchema.methods.cashExternalUrl = function(externalUrl) {
  64. if (externalUrl == null) {
  65. throw new Error('url is required.');
  66. }
  67. this.externalUrlCached = externalUrl;
  68. this.externalUrlExpiredAt = addSeconds(new Date(), this.SECONDS_OF_CASH_EXPIRATION);
  69. return this.save();
  70. };
  71. attachmentSchema.statics.SECONDS_OF_CASH_EXPIRATION = SECONDS_OF_CASH_EXPIRATION;
  72. return mongoose.model('Attachment', attachmentSchema);
  73. };