asset.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. const _ = require('lodash')
  2. const sanitize = require('sanitize-filename')
  3. const graphHelper = require('../../helpers/graph')
  4. const assetHelper = require('../../helpers/asset')
  5. /* global WIKI */
  6. module.exports = {
  7. Query: {
  8. async assets(obj, args, context) {
  9. let cond = {
  10. folderId: args.folderId === 0 ? null : args.folderId
  11. }
  12. if (args.kind !== 'ALL') {
  13. cond.kind = args.kind.toLowerCase()
  14. }
  15. const folderHierarchy = await WIKI.models.assetFolders.getHierarchy(args.folderId)
  16. const folderPath = folderHierarchy.map(h => h.slug).join('/')
  17. const results = await WIKI.models.assets.query().where(cond)
  18. return _.filter(results, r => {
  19. const path = folderPath ? `${folderPath}/${r.filename}` : r.filename
  20. return WIKI.auth.checkAccess(context.req.user, ['read:assets'], { path })
  21. }).map(a => ({
  22. ...a,
  23. kind: a.kind.toUpperCase()
  24. }))
  25. },
  26. async assetsFolders(obj, args, context) {
  27. const results = await WIKI.models.assetFolders.query().where({
  28. parentId: args.parentFolderId === 0 ? null : args.parentFolderId
  29. })
  30. const parentHierarchy = await WIKI.models.assetFolders.getHierarchy(args.parentFolderId)
  31. const parentPath = parentHierarchy.map(h => h.slug).join('/')
  32. return _.filter(results, r => {
  33. const path = parentPath ? `${parentPath}/${r.slug}` : r.slug
  34. return WIKI.auth.checkAccess(context.req.user, ['read:assets'], { path })
  35. })
  36. }
  37. },
  38. Mutation: {
  39. /**
  40. * Create New Asset Folder
  41. */
  42. async createAssetsFolder(obj, args, context) {
  43. try {
  44. const folderSlug = sanitize(args.slug).toLowerCase()
  45. const parentFolderId = args.parentFolderId === 0 ? null : args.parentFolderId
  46. const result = await WIKI.models.assetFolders.query().where({
  47. parentId: parentFolderId,
  48. slug: folderSlug
  49. }).first()
  50. if (!result) {
  51. await WIKI.models.assetFolders.query().insert({
  52. slug: folderSlug,
  53. name: folderSlug,
  54. parentId: parentFolderId
  55. })
  56. return {
  57. responseResult: graphHelper.generateSuccess('Asset Folder has been created successfully.')
  58. }
  59. } else {
  60. throw new WIKI.Error.AssetFolderExists()
  61. }
  62. } catch (err) {
  63. return graphHelper.generateError(err)
  64. }
  65. },
  66. /**
  67. * Rename an Asset
  68. */
  69. async renameAsset(obj, args, context) {
  70. try {
  71. const filename = sanitize(args.filename).toLowerCase()
  72. const asset = await WIKI.models.assets.query().findById(args.id)
  73. if (asset) {
  74. // Check for extension mismatch
  75. if (!_.endsWith(filename, asset.ext)) {
  76. throw new WIKI.Error.AssetRenameInvalidExt()
  77. }
  78. // Check for non-dot files changing to dotfile
  79. if (asset.ext.length > 0 && filename.length - asset.ext.length < 1) {
  80. throw new WIKI.Error.AssetRenameInvalid()
  81. }
  82. // Check for collision
  83. const assetCollision = await WIKI.models.assets.query().where({
  84. filename,
  85. folderId: asset.folderId
  86. }).first()
  87. if (assetCollision) {
  88. throw new WIKI.Error.AssetRenameCollision()
  89. }
  90. // Get asset folder path
  91. let hierarchy = []
  92. if (asset.folderId) {
  93. hierarchy = await WIKI.models.assetFolders.getHierarchy(asset.folderId)
  94. }
  95. // Check source asset permissions
  96. const assetSourcePath = (asset.folderId) ? hierarchy.map(h => h.slug).join('/') + `/${asset.filename}` : asset.filename
  97. if (!WIKI.auth.checkAccess(context.req.user, ['manage:assets'], { path: assetSourcePath })) {
  98. throw new WIKI.Error.AssetRenameForbidden()
  99. }
  100. // Check target asset permissions
  101. const assetTargetPath = (asset.folderId) ? hierarchy.map(h => h.slug).join('/') + `/${filename}` : filename
  102. if (!WIKI.auth.checkAccess(context.req.user, ['write:assets'], { path: assetTargetPath })) {
  103. throw new WIKI.Error.AssetRenameTargetForbidden()
  104. }
  105. // Update filename + hash
  106. const fileHash = assetHelper.generateHash(assetTargetPath)
  107. await WIKI.models.assets.query().patch({
  108. filename: filename,
  109. hash: fileHash
  110. }).findById(args.id)
  111. // Delete old asset cache
  112. await asset.deleteAssetCache()
  113. // Rename in Storage
  114. await WIKI.models.storage.assetEvent({
  115. event: 'renamed',
  116. asset: {
  117. ...asset,
  118. path: assetSourcePath,
  119. destinationPath: assetTargetPath,
  120. moveAuthorId: context.req.user.id,
  121. moveAuthorName: context.req.user.name,
  122. moveAuthorEmail: context.req.user.email
  123. }
  124. })
  125. return {
  126. responseResult: graphHelper.generateSuccess('Asset has been renamed successfully.')
  127. }
  128. } else {
  129. throw new WIKI.Error.AssetInvalid()
  130. }
  131. } catch (err) {
  132. return graphHelper.generateError(err)
  133. }
  134. },
  135. /**
  136. * Delete an Asset
  137. */
  138. async deleteAsset(obj, args, context) {
  139. try {
  140. const asset = await WIKI.models.assets.query().findById(args.id)
  141. if (asset) {
  142. // Check permissions
  143. const assetPath = await asset.getAssetPath()
  144. if (!WIKI.auth.checkAccess(context.req.user, ['manage:assets'], { path: assetPath })) {
  145. throw new WIKI.Error.AssetDeleteForbidden()
  146. }
  147. await WIKI.models.knex('assetData').where('id', args.id).del()
  148. await WIKI.models.assets.query().deleteById(args.id)
  149. await asset.deleteAssetCache()
  150. // Delete from Storage
  151. await WIKI.models.storage.assetEvent({
  152. event: 'deleted',
  153. asset: {
  154. ...asset,
  155. path: assetPath,
  156. authorId: context.req.user.id,
  157. authorName: context.req.user.name,
  158. authorEmail: context.req.user.email
  159. }
  160. })
  161. return {
  162. responseResult: graphHelper.generateSuccess('Asset has been deleted successfully.')
  163. }
  164. } else {
  165. throw new WIKI.Error.AssetInvalid()
  166. }
  167. } catch (err) {
  168. return graphHelper.generateError(err)
  169. }
  170. },
  171. /**
  172. * Flush Temporary Uploads
  173. */
  174. async flushTempUploads(obj, args, context) {
  175. try {
  176. await WIKI.models.assets.flushTempUploads()
  177. return {
  178. responseResult: graphHelper.generateSuccess('Temporary Uploads have been flushed successfully.')
  179. }
  180. } catch (err) {
  181. return graphHelper.generateError(err)
  182. }
  183. }
  184. }
  185. // File: {
  186. // folder(fl) {
  187. // return fl.getFolder()
  188. // }
  189. // }
  190. }