All files / lib/models attachment.ts

30% Statements 12/40
0% Branches 0/8
10% Functions 1/10
30.77% Lines 12/39

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129                                                                    16x 16x                 16x                                   16x       16x             16x                     16x                               16x             16x             16x                   16x   16x    
import Crowi from 'server/crowi'
import { Types, Document, Model, Schema, model } from 'mongoose'
import Debug from 'debug'
import crypto from 'crypto'
import FileUploader from '../util/fileUploader'
 
export interface AttachmentDocument extends Document {
  _id: Types.ObjectId
  page: Types.ObjectId
  creator: Types.ObjectId
  filePath: string
  fileName: string
  originalName: string
  fileFormat: string
  fileSize: number
  createdAt: Date
 
  // virtual
  fileUrl: string
 
  // dynamic field
  url: string
}
 
export interface AttachmentModel extends Model<AttachmentDocument> {
  getListByPageId(id: Types.ObjectId): Promise<AttachmentDocument[]>
  guessExtByFileType(fileType: string): string
  createAttachmentFilePath(pageId: Types.ObjectId, fileName: string, fileType: string): string
  removeAttachmentsByPageId(pageId: Types.ObjectId): any
  findDeliveryFile(attachment: AttachmentDocument, forceUpdate?: boolean): any
  removeAttachment(attachment: AttachmentDocument): any
}
 
export default (crowi: Crowi) => {
  const debug = Debug('crowi:models:attachment')
  const fileUploader = FileUploader(crowi)
 
  function generateFileHash(fileName) {
    var hasher = crypto.createHash('md5')
    hasher.update(fileName)
 
    return hasher.digest('hex')
  }
 
  const attachmentSchema = new Schema<AttachmentDocument, AttachmentModel>(
    {
      page: { type: Schema.Types.ObjectId, ref: 'Page', index: true },
      creator: { type: Schema.Types.ObjectId, ref: 'User', index: true },
      filePath: { type: String, required: true },
      fileName: { type: String, required: true },
      originalName: { type: String },
      fileFormat: { type: String, required: true },
      fileSize: { type: Number, default: 0 },
      createdAt: { type: Date, default: Date.now },
    },
    {
      toJSON: {
        virtuals: true,
      },
    },
  )
 
  attachmentSchema.virtual('fileUrl').get(function(this: AttachmentDocument) {
    return `/files/${this._id}`
  })
 
  attachmentSchema.statics.getListByPageId = function(id) {
    return Attachment.find({ page: id })
      .sort({ updatedAt: 1 })
      .populate('creator')
      .exec()
  }
 
  attachmentSchema.statics.guessExtByFileType = function(fileType) {
    let ext = ''
    const isImage = fileType.match(/^image\/(.+)/i)
 
    if (isImage) {
      ext = isImage[1].toLowerCase()
    }
 
    return ext
  }
 
  attachmentSchema.statics.createAttachmentFilePath = function(pageId, fileName, fileType) {
    let ext = ''
    const fnExt = fileName.match(/(.*)(?:\.([^.]+$))/)
 
    if (fnExt) {
      ext = '.' + fnExt[2]
    } else {
      ext = Attachment.guessExtByFileType(fileType)
      if (ext !== '') {
        ext = '.' + ext
      }
    }
 
    return 'attachment/' + pageId + '/' + generateFileHash(fileName) + ext
  }
 
  attachmentSchema.statics.removeAttachmentsByPageId = async function(pageId) {
    const attachments = await Attachment.getListByPageId(pageId)
    await Promise.all(attachments.map(attachment => Attachment.removeAttachment(attachment)))
 
    return attachments
  }
 
  attachmentSchema.statics.findDeliveryFile = function(attachment, forceUpdate) {
    // TODO
    forceUpdate = forceUpdate || false
 
    return fileUploader.findDeliveryFile(attachment._id, attachment.filePath)
  }
 
  attachmentSchema.statics.removeAttachment = async function(attachment) {
    const filePath = attachment.filePath
 
    await Attachment.deleteOne({ _id: attachment._id })
 
    const data = await fileUploader.deleteFile(attachment._id, filePath)
 
    return data
  }
 
  const Attachment = model<AttachmentDocument, AttachmentModel>('Attachment', attachmentSchema)
 
  return Attachment
}