attachment.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. module.exports = function(crowi) {
  2. var debug = require('debug')('growi:models:attachment')
  3. , mongoose = require('mongoose')
  4. , ObjectId = mongoose.Schema.Types.ObjectId
  5. , fileUploader = require('../service/file-uploader')(crowi)
  6. , attachmentSchema
  7. ;
  8. function generateFileHash(fileName) {
  9. var hasher = require('crypto').createHash('md5');
  10. hasher.update(fileName);
  11. return hasher.digest('hex');
  12. }
  13. attachmentSchema = new mongoose.Schema({
  14. page: { type: ObjectId, ref: 'Page', index: true },
  15. creator: { type: ObjectId, ref: 'User', index: true },
  16. filePath: { type: String, required: true },
  17. fileName: { type: String, required: true },
  18. originalName: { type: String },
  19. fileFormat: { type: String, required: true },
  20. fileSize: { type: Number, default: 0 },
  21. createdAt: { type: Date, default: Date.now }
  22. }, {
  23. toJSON: {
  24. virtuals: true
  25. },
  26. });
  27. attachmentSchema.virtual('fileUrl').get(function() {
  28. // NOTE: use original generated Url directly (not proxy) -- 2017.05.08 Yuki Takei
  29. // reason:
  30. // 1. this is buggy (doesn't work on Win)
  31. // 2. ensure backward compatibility of data
  32. // return `/files/${this._id}`;
  33. return fileUploader.generateUrl(this.filePath);
  34. });
  35. attachmentSchema.statics.findById = function(id) {
  36. var Attachment = this;
  37. return new Promise(function(resolve, reject) {
  38. Attachment.findOne({_id: id}, function(err, data) {
  39. if (err) {
  40. return reject(err);
  41. }
  42. if (data === null) {
  43. return reject(new Error('Attachment not found'));
  44. }
  45. return resolve(data);
  46. });
  47. });
  48. };
  49. attachmentSchema.statics.getListByPageId = function(id) {
  50. var self = this;
  51. return new Promise(function(resolve, reject) {
  52. self
  53. .find({page: id})
  54. .sort({'updatedAt': 1})
  55. .populate('creator')
  56. .exec(function(err, data) {
  57. if (err) {
  58. return reject(err);
  59. }
  60. if (data.length < 1) {
  61. return resolve([]);
  62. }
  63. debug(data);
  64. return resolve(data);
  65. });
  66. });
  67. };
  68. attachmentSchema.statics.create = function(pageId, creator, filePath, originalName, fileName, fileFormat, fileSize) {
  69. var Attachment = this;
  70. return new Promise(function(resolve, reject) {
  71. var newAttachment = new Attachment();
  72. newAttachment.page = pageId;
  73. newAttachment.creator = creator._id;
  74. newAttachment.filePath = filePath;
  75. newAttachment.originalName = originalName;
  76. newAttachment.fileName = fileName;
  77. newAttachment.fileFormat = fileFormat;
  78. newAttachment.fileSize = fileSize;
  79. newAttachment.createdAt = Date.now();
  80. newAttachment.save(function(err, data) {
  81. if (err) {
  82. debug('Error on saving attachment.', err);
  83. return reject(err);
  84. }
  85. debug('Attachment saved.', data);
  86. return resolve(data);
  87. });
  88. });
  89. };
  90. attachmentSchema.statics.guessExtByFileType = function(fileType) {
  91. let ext = '';
  92. const isImage = fileType.match(/^image\/(.+)/i);
  93. if (isImage) {
  94. ext = isImage[1].toLowerCase();
  95. }
  96. return ext;
  97. };
  98. attachmentSchema.statics.createAttachmentFilePath = function(pageId, fileName, fileType) {
  99. const Attachment = this;
  100. let ext = '';
  101. const fnExt = fileName.match(/(.*)(?:\.([^.]+$))/);
  102. if (fnExt) {
  103. ext = '.' + fnExt[2];
  104. }
  105. else {
  106. ext = Attachment.guessExtByFileType(fileType);
  107. if (ext !== '') {
  108. ext = '.' + ext;
  109. }
  110. }
  111. return 'attachment/' + pageId + '/' + generateFileHash(fileName) + ext;
  112. };
  113. attachmentSchema.statics.removeAttachmentsByPageId = function(pageId) {
  114. var Attachment = this;
  115. return new Promise((resolve, reject) => {
  116. Attachment.getListByPageId(pageId)
  117. .then((attachments) => {
  118. for (let attachment of attachments) {
  119. Attachment.removeAttachment(attachment).then((res) => {
  120. // do nothing
  121. }).catch((err) => {
  122. debug('Attachment remove error', err);
  123. });
  124. }
  125. resolve(attachments);
  126. }).catch((err) => {
  127. reject(err);
  128. });
  129. });
  130. };
  131. attachmentSchema.statics.findDeliveryFile = function(attachment, forceUpdate) {
  132. // TODO force update
  133. // var forceUpdate = forceUpdate || false;
  134. return fileUploader.findDeliveryFile(attachment._id, attachment.filePath);
  135. };
  136. attachmentSchema.statics.removeAttachment = function(attachment) {
  137. const Attachment = this;
  138. const filePath = attachment.filePath;
  139. return new Promise((resolve, reject) => {
  140. Attachment.remove({_id: attachment._id}, (err, data) => {
  141. if (err) {
  142. return reject(err);
  143. }
  144. fileUploader.deleteFile(attachment._id, filePath)
  145. .then(data => {
  146. resolve(data); // this may null
  147. }).catch(err => {
  148. reject(err);
  149. });
  150. });
  151. });
  152. };
  153. return mongoose.model('Attachment', attachmentSchema);
  154. };