You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

175 lines
6.4 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. const fs = require('fs-extra')
  2. const path = require('path')
  3. const tar = require('tar-fs')
  4. const zlib = require('zlib')
  5. const stream = require('stream')
  6. const _ = require('lodash')
  7. const Promise = require('bluebird')
  8. const pipeline = Promise.promisify(stream.pipeline)
  9. const moment = require('moment')
  10. const pageHelper = require('../../../helpers/page')
  11. const commonDisk = require('./common')
  12. /* global WIKI */
  13. module.exports = {
  14. async activated() {
  15. // not used
  16. },
  17. async deactivated() {
  18. // not used
  19. },
  20. async init() {
  21. WIKI.logger.info('(STORAGE/DISK) Initializing...')
  22. await fs.ensureDir(this.config.path)
  23. WIKI.logger.info('(STORAGE/DISK) Initialization completed.')
  24. },
  25. async sync({ manual } = { manual: false }) {
  26. if (this.config.createDailyBackups || manual) {
  27. const dirPath = path.join(this.config.path, manual ? '_manual' : '_daily')
  28. await fs.ensureDir(dirPath)
  29. const dateFilename = moment().format(manual ? 'YYYYMMDD-HHmmss' : 'DD')
  30. WIKI.logger.info(`(STORAGE/DISK) Creating backup archive...`)
  31. await pipeline(
  32. tar.pack(this.config.path, {
  33. ignore: (filePath) => {
  34. return filePath.indexOf('_daily') >= 0 || filePath.indexOf('_manual') >= 0
  35. }
  36. }),
  37. zlib.createGzip(),
  38. fs.createWriteStream(path.join(dirPath, `wiki-${dateFilename}.tar.gz`))
  39. )
  40. WIKI.logger.info('(STORAGE/DISK) Backup archive created successfully.')
  41. }
  42. },
  43. async created(page) {
  44. WIKI.logger.info(`(STORAGE/DISK) Creating file [${page.localeCode}] ${page.path}...`)
  45. let fileName = `${page.path}.${pageHelper.getFileExtension(page.contentType)}`
  46. if (WIKI.config.lang.code !== page.localeCode) {
  47. fileName = `${page.localeCode}/${fileName}`
  48. }
  49. const filePath = path.join(this.config.path, fileName)
  50. await fs.outputFile(filePath, page.injectMetadata(), 'utf8')
  51. },
  52. async updated(page) {
  53. WIKI.logger.info(`(STORAGE/DISK) Updating file [${page.localeCode}] ${page.path}...`)
  54. let fileName = `${page.path}.${pageHelper.getFileExtension(page.contentType)}`
  55. if (WIKI.config.lang.code !== page.localeCode) {
  56. fileName = `${page.localeCode}/${fileName}`
  57. }
  58. const filePath = path.join(this.config.path, fileName)
  59. await fs.outputFile(filePath, page.injectMetadata(), 'utf8')
  60. },
  61. async deleted(page) {
  62. WIKI.logger.info(`(STORAGE/DISK) Deleting file [${page.localeCode}] ${page.path}...`)
  63. let fileName = `${page.path}.${pageHelper.getFileExtension(page.contentType)}`
  64. if (WIKI.config.lang.code !== page.localeCode) {
  65. fileName = `${page.localeCode}/${fileName}`
  66. }
  67. const filePath = path.join(this.config.path, fileName)
  68. await fs.unlink(filePath)
  69. },
  70. async renamed(page) {
  71. WIKI.logger.info(`(STORAGE/DISK) Renaming file [${page.localeCode}] ${page.path} to [${page.destinationLocaleCode}] ${page.destinationPath}...`)
  72. let sourceFilePath = `${page.path}.${pageHelper.getFileExtension(page.contentType)}`
  73. let destinationFilePath = `${page.destinationPath}.${pageHelper.getFileExtension(page.contentType)}`
  74. if (WIKI.config.lang.namespacing) {
  75. if (WIKI.config.lang.code !== page.localeCode) {
  76. sourceFilePath = `${page.localeCode}/${sourceFilePath}`
  77. }
  78. if (WIKI.config.lang.code !== page.destinationLocaleCode) {
  79. destinationFilePath = `${page.destinationLocaleCode}/${destinationFilePath}`
  80. }
  81. }
  82. await fs.move(path.join(this.config.path, sourceFilePath), path.join(this.config.path, destinationFilePath), { overwrite: true })
  83. },
  84. /**
  85. * ASSET UPLOAD
  86. *
  87. * @param {Object} asset Asset to upload
  88. */
  89. async assetUploaded (asset) {
  90. WIKI.logger.info(`(STORAGE/DISK) Creating new file ${asset.path}...`)
  91. await fs.outputFile(path.join(this.config.path, asset.path), asset.data)
  92. },
  93. /**
  94. * ASSET DELETE
  95. *
  96. * @param {Object} asset Asset to delete
  97. */
  98. async assetDeleted (asset) {
  99. WIKI.logger.info(`(STORAGE/DISK) Deleting file ${asset.path}...`)
  100. await fs.remove(path.join(this.config.path, asset.path))
  101. },
  102. /**
  103. * ASSET RENAME
  104. *
  105. * @param {Object} asset Asset to rename
  106. */
  107. async assetRenamed (asset) {
  108. WIKI.logger.info(`(STORAGE/DISK) Renaming file from ${asset.path} to ${asset.destinationPath}...`)
  109. await fs.move(path.join(this.config.path, asset.path), path.join(this.config.path, asset.destinationPath), { overwrite: true })
  110. },
  111. /**
  112. * HANDLERS
  113. */
  114. async dump() {
  115. WIKI.logger.info(`(STORAGE/DISK) Dumping all content to disk...`)
  116. // -> Pages
  117. await pipeline(
  118. WIKI.models.knex.column('path', 'localeCode', 'title', 'description', 'contentType', 'content', 'isPublished', 'updatedAt').select().from('pages').where({
  119. isPrivate: false
  120. }).stream(),
  121. new stream.Transform({
  122. objectMode: true,
  123. transform: async (page, enc, cb) => {
  124. let fileName = `${page.path}.${pageHelper.getFileExtension(page.contentType)}`
  125. if (WIKI.config.lang.code !== page.localeCode) {
  126. fileName = `${page.localeCode}/${fileName}`
  127. }
  128. WIKI.logger.info(`(STORAGE/DISK) Dumping page ${fileName}...`)
  129. const filePath = path.join(this.config.path, fileName)
  130. await fs.outputFile(filePath, pageHelper.injectPageMetadata(page), 'utf8')
  131. cb()
  132. }
  133. })
  134. )
  135. // -> Assets
  136. const assetFolders = await WIKI.models.assetFolders.getAllPaths()
  137. await pipeline(
  138. WIKI.models.knex.column('filename', 'folderId', 'data').select().from('assets').join('assetData', 'assets.id', '=', 'assetData.id').stream(),
  139. new stream.Transform({
  140. objectMode: true,
  141. transform: async (asset, enc, cb) => {
  142. const filename = (asset.folderId && asset.folderId > 0) ? `${_.get(assetFolders, asset.folderId)}/${asset.filename}` : asset.filename
  143. WIKI.logger.info(`(STORAGE/DISK) Dumping asset ${filename}...`)
  144. await fs.outputFile(path.join(this.config.path, filename), asset.data)
  145. cb()
  146. }
  147. })
  148. )
  149. WIKI.logger.info('(STORAGE/DISK) All content was dumped to disk successfully.')
  150. },
  151. async backup() {
  152. return this.sync({ manual: true })
  153. },
  154. async importAll() {
  155. WIKI.logger.info(`(STORAGE/DISK) Importing all content from local disk folder to the DB...`)
  156. await commonDisk.importFromDisk({
  157. fullPath: this.config.path,
  158. moduleName: 'DISK'
  159. })
  160. WIKI.logger.info('(STORAGE/DISK) Import completed.')
  161. }
  162. }