assets.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. /* global WIKI */
  2. const Model = require('objection').Model
  3. const moment = require('moment')
  4. const path = require('path')
  5. const fs = require('fs-extra')
  6. const _ = require('lodash')
  7. const assetHelper = require('../helpers/asset')
  8. /**
  9. * Users model
  10. */
  11. module.exports = class Asset extends Model {
  12. static get tableName() { return 'assets' }
  13. static get jsonSchema () {
  14. return {
  15. type: 'object',
  16. properties: {
  17. id: {type: 'integer'},
  18. filename: {type: 'string'},
  19. hash: {type: 'string'},
  20. ext: {type: 'string'},
  21. kind: {type: 'string'},
  22. mime: {type: 'string'},
  23. fileSize: {type: 'integer'},
  24. metadata: {type: 'object'},
  25. createdAt: {type: 'string'},
  26. updatedAt: {type: 'string'}
  27. }
  28. }
  29. }
  30. static get relationMappings() {
  31. return {
  32. author: {
  33. relation: Model.BelongsToOneRelation,
  34. modelClass: require('./users'),
  35. join: {
  36. from: 'assets.authorId',
  37. to: 'users.id'
  38. }
  39. },
  40. folder: {
  41. relation: Model.BelongsToOneRelation,
  42. modelClass: require('./assetFolders'),
  43. join: {
  44. from: 'assets.folderId',
  45. to: 'assetFolders.id'
  46. }
  47. }
  48. }
  49. }
  50. async $beforeUpdate(opt, context) {
  51. await super.$beforeUpdate(opt, context)
  52. this.updatedAt = moment.utc().toISOString()
  53. }
  54. async $beforeInsert(context) {
  55. await super.$beforeInsert(context)
  56. this.createdAt = moment.utc().toISOString()
  57. this.updatedAt = moment.utc().toISOString()
  58. }
  59. static async upload(opts) {
  60. const fileInfo = path.parse(opts.originalname)
  61. const fileHash = assetHelper.generateHash(opts.assetPath)
  62. // Check for existing asset
  63. let asset = await WIKI.models.assets.query().where({
  64. hash: fileHash,
  65. folderId: opts.folderId
  66. }).first()
  67. // Build Object
  68. let assetRow = {
  69. filename: opts.originalname,
  70. hash: fileHash,
  71. ext: fileInfo.ext,
  72. kind: _.startsWith(opts.mimetype, 'image/') ? 'image' : 'binary',
  73. mime: opts.mimetype,
  74. fileSize: opts.size,
  75. folderId: opts.folderId,
  76. authorId: opts.userId
  77. }
  78. // Save asset data
  79. try {
  80. const fileBuffer = await fs.readFile(opts.path)
  81. if (asset) {
  82. // Patch existing asset
  83. await WIKI.models.assets.query().patch(assetRow).findById(asset.id)
  84. await WIKI.models.knex('assetData').where({
  85. id: asset.id
  86. }).update({
  87. data: fileBuffer
  88. })
  89. } else {
  90. // Create asset entry
  91. asset = await WIKI.models.assets.query().insert(assetRow)
  92. await WIKI.models.knex('assetData').insert({
  93. id: asset.id,
  94. data: fileBuffer
  95. })
  96. }
  97. } catch (err) {
  98. WIKI.logger.warn(err)
  99. }
  100. // Move temp upload to cache
  101. await fs.move(opts.path, path.join(process.cwd(), `data/cache/${fileHash}.dat`), { overwrite: true })
  102. }
  103. static async getAsset(assetPath, res) {
  104. let assetExists = await WIKI.models.assets.getAssetFromCache(assetPath, res)
  105. if (!assetExists) {
  106. await WIKI.models.assets.getAssetFromDb(assetPath, res)
  107. }
  108. }
  109. static async getAssetFromCache(assetPath, res) {
  110. const fileHash = assetHelper.generateHash(assetPath)
  111. const cachePath = path.join(process.cwd(), `data/cache/${fileHash}.dat`)
  112. return new Promise((resolve, reject) => {
  113. res.type(path.extname(assetPath))
  114. res.sendFile(cachePath, { dotfiles: 'deny' }, err => {
  115. if (err) {
  116. resolve(false)
  117. } else {
  118. resolve(true)
  119. }
  120. })
  121. })
  122. }
  123. static async getAssetFromDb(assetPath, res) {
  124. const fileHash = assetHelper.generateHash(assetPath)
  125. const cachePath = path.join(process.cwd(), `data/cache/${fileHash}.dat`)
  126. const asset = await WIKI.models.assets.query().where('hash', fileHash).first()
  127. if (asset) {
  128. const assetData = await WIKI.models.knex('assetData').where('id', asset.id).first()
  129. res.type(asset.ext)
  130. res.send(assetData.data)
  131. await fs.outputFile(cachePath, assetData.data)
  132. } else {
  133. res.sendStatus(404)
  134. }
  135. }
  136. }