attachment.js 3.3 KB

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