storage.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. const fs = require('fs-extra')
  2. const _ = require('lodash')
  3. const path = require('path')
  4. const tar = require('tar-fs')
  5. const zlib = require('zlib')
  6. const stream = require('stream')
  7. const Promise = require('bluebird')
  8. const pipeline = Promise.promisify(stream.pipeline)
  9. const pageHelper = require('../../../helpers/page.js')
  10. const moment = require('moment')
  11. /* global WIKI */
  12. /**
  13. * Get file extension based on content type
  14. */
  15. const getFileExtension = (contentType) => {
  16. switch (contentType) {
  17. case 'markdown':
  18. return 'md'
  19. case 'html':
  20. return 'html'
  21. default:
  22. return 'txt'
  23. }
  24. }
  25. module.exports = {
  26. async activated() {
  27. // not used
  28. },
  29. async deactivated() {
  30. // not used
  31. },
  32. async init() {
  33. WIKI.logger.info('(STORAGE/DISK) Initializing...')
  34. await fs.ensureDir(this.config.path)
  35. WIKI.logger.info('(STORAGE/DISK) Initialization completed.')
  36. },
  37. async sync({ manual } = { manual: false }) {
  38. if (this.config.createDailyBackups || manual) {
  39. const dirPath = path.join(this.config.path, manual ? '_manual' : '_daily')
  40. await fs.ensureDir(dirPath)
  41. const dateFilename = moment().format(manual ? 'YYYYMMDD-HHmmss' : 'DD')
  42. WIKI.logger.info(`(STORAGE/DISK) Creating backup archive...`)
  43. await pipeline(
  44. tar.pack(this.config.path, {
  45. ignore: (filePath) => {
  46. return filePath.indexOf('_daily') >= 0 || filePath.indexOf('_manual') >= 0
  47. }
  48. }),
  49. zlib.createGzip(),
  50. fs.createWriteStream(path.join(dirPath, `wiki-${dateFilename}.tar.gz`))
  51. )
  52. WIKI.logger.info('(STORAGE/DISK) Backup archive created successfully.')
  53. }
  54. },
  55. async created(page) {
  56. WIKI.logger.info(`(STORAGE/DISK) Creating file ${page.path}...`)
  57. let fileName = `${page.path}.${getFileExtension(page.contentType)}`
  58. if (WIKI.config.lang.namespacing && WIKI.config.lang.code !== page.localeCode) {
  59. fileName = `${page.localeCode}/${fileName}`
  60. }
  61. const filePath = path.join(this.config.path, fileName)
  62. await fs.outputFile(filePath, page.injectMetadata(), 'utf8')
  63. },
  64. async updated(page) {
  65. WIKI.logger.info(`(STORAGE/DISK) Updating file ${page.path}...`)
  66. let fileName = `${page.path}.${getFileExtension(page.contentType)}`
  67. if (WIKI.config.lang.namespacing && WIKI.config.lang.code !== page.localeCode) {
  68. fileName = `${page.localeCode}/${fileName}`
  69. }
  70. const filePath = path.join(this.config.path, fileName)
  71. await fs.outputFile(filePath, page.injectMetadata(), 'utf8')
  72. },
  73. async deleted(page) {
  74. WIKI.logger.info(`(STORAGE/DISK) Deleting file ${page.path}...`)
  75. let fileName = `${page.path}.${getFileExtension(page.contentType)}`
  76. if (WIKI.config.lang.namespacing && WIKI.config.lang.code !== page.localeCode) {
  77. fileName = `${page.localeCode}/${fileName}`
  78. }
  79. const filePath = path.join(this.config.path, fileName)
  80. await fs.unlink(filePath)
  81. },
  82. async renamed(page) {
  83. WIKI.logger.info(`(STORAGE/DISK) Renaming file ${page.sourcePath} to ${page.destinationPath}...`)
  84. let sourceFilePath = `${page.sourcePath}.${getFileExtension(page.contentType)}`
  85. let destinationFilePath = `${page.destinationPath}.${getFileExtension(page.contentType)}`
  86. if (WIKI.config.lang.namespacing && WIKI.config.lang.code !== page.localeCode) {
  87. sourceFilePath = `${page.localeCode}/${sourceFilePath}`
  88. destinationFilePath = `${page.localeCode}/${destinationFilePath}`
  89. }
  90. await fs.move(path.join(this.config.path, sourceFilePath), path.join(this.config.path, destinationFilePath), { overwrite: true })
  91. },
  92. /**
  93. * HANDLERS
  94. */
  95. async dump() {
  96. WIKI.logger.info(`(STORAGE/DISK) Dumping all content to disk...`)
  97. await pipeline(
  98. WIKI.models.knex.column('path', 'localeCode', 'title', 'description', 'contentType', 'content', 'isPublished', 'updatedAt').select().from('pages').where({
  99. isPrivate: false
  100. }).stream(),
  101. new stream.Transform({
  102. objectMode: true,
  103. transform: async (page, enc, cb) => {
  104. let fileName = `${page.path}.${getFileExtension(page.contentType)}`
  105. if (WIKI.config.lang.namespacing && WIKI.config.lang.code !== page.localeCode) {
  106. fileName = `${page.localeCode}/${fileName}`
  107. }
  108. WIKI.logger.info(`(STORAGE/DISK) Dumping ${fileName}...`)
  109. const filePath = path.join(this.config.path, fileName)
  110. await fs.outputFile(filePath, pageHelper.injectPageMetadata(page), 'utf8')
  111. cb()
  112. }
  113. })
  114. )
  115. WIKI.logger.info('(STORAGE/DISK) All content was dumped to disk successfully.')
  116. },
  117. async backup() {
  118. return this.sync({ manual: true })
  119. }
  120. }