| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 | const fs = require('fs-extra')const path = require('path')const stream = require('stream')const Promise = require('bluebird')const pipeline = Promise.promisify(stream.pipeline)const klaw = require('klaw')const mime = require('mime-types').lookupconst _ = require('lodash')const pageHelper = require('../../../helpers/page.js')/* global WIKI */module.exports = {  assetFolders: null,  async importFromDisk ({ fullPath, moduleName }) {    const rootUser = await WIKI.models.users.getRootUser()    await pipeline(      klaw(fullPath, {        filter: (f) => {          return !_.includes(f, '.git')        }      }),      new stream.Transform({        objectMode: true,        transform: async (file, enc, cb) => {          const relPath = file.path.substr(fullPath.length + 1)          if (file.stats.size < 1) {            // Skip directories and zero-byte files            return cb()          } else if (relPath && relPath.length > 3) {            WIKI.logger.info(`(STORAGE/${moduleName}) Processing ${relPath}...`)            const contentType = pageHelper.getContentType(relPath)            if (contentType) {              // -> Page              try {                await this.processPage({                  user: rootUser,                  relPath: relPath,                  fullPath: fullPath,                  contentType: contentType,                  moduleName: moduleName                })              } catch (err) {                WIKI.logger.warn(`(STORAGE/${moduleName}) Failed to process page ${relPath}`)                WIKI.logger.warn(err)              }            } else {              // -> Asset              try {                await this.processAsset({                  user: rootUser,                  relPath: relPath,                  file: file,                  contentType: contentType,                  moduleName: moduleName                })              } catch (err) {                WIKI.logger.warn(`(STORAGE/${moduleName}) Failed to process asset ${relPath}`)                WIKI.logger.warn(err)              }            }          }          cb()        }      })    )    this.clearFolderCache()  },  async processPage ({ user, fullPath, relPath, contentType, moduleName }) {    const normalizedRelPath = relPath.replace(/\\/g, '/')    const contentPath = pageHelper.getPagePath(normalizedRelPath)    const itemContents = await fs.readFile(path.join(fullPath, relPath), 'utf8')    const pageData = WIKI.models.pages.parseMetadata(itemContents, contentType)    const currentPage = await WIKI.models.pages.getPageFromDb({      path: contentPath.path,      locale: contentPath.locale    })    const newTags = !_.isNil(pageData.tags) ? _.get(pageData, 'tags', '').split(', ') : false    if (currentPage) {      // Already in the DB, can mark as modified      WIKI.logger.info(`(STORAGE/${moduleName}) Page marked as modified: ${normalizedRelPath}`)      await WIKI.models.pages.updatePage({        id: currentPage.id,        title: _.get(pageData, 'title', currentPage.title),        description: _.get(pageData, 'description', currentPage.description) || '',        tags: newTags || currentPage.tags.map(t => t.tag),        isPublished: _.get(pageData, 'isPublished', currentPage.isPublished),        isPrivate: false,        content: pageData.content,        user: user,        skipStorage: true      })    } else {      // Not in the DB, can mark as new      WIKI.logger.info(`(STORAGE/${moduleName}) Page marked as new: ${normalizedRelPath}`)      const pageEditor = await WIKI.models.editors.getDefaultEditor(contentType)      await WIKI.models.pages.createPage({        path: contentPath.path,        locale: contentPath.locale,        title: _.get(pageData, 'title', _.last(contentPath.path.split('/'))),        description: _.get(pageData, 'description', '') || '',        tags: newTags || [],        isPublished: _.get(pageData, 'isPublished', true),        isPrivate: false,        content: pageData.content,        user: user,        editor: pageEditor,        skipStorage: true      })    }  },  async processAsset ({ user, relPath, file, moduleName }) {    WIKI.logger.info(`(STORAGE/${moduleName}) Asset marked for import: ${relPath}`)    // -> Get all folder paths    if (!this.assetFolders) {      this.assetFolders = await WIKI.models.assetFolders.getAllPaths()    }    // -> Find existing folder    const filePathInfo = path.parse(file.path)    const folderPath = path.dirname(relPath).replace(/\\/g, '/')    let folderId = _.toInteger(_.findKey(this.assetFolders, fld => { return fld === folderPath })) || null    // -> Create missing folder structure    if (!folderId && folderPath !== '.') {      const folderParts = folderPath.split('/')      let currentFolderPath = []      let currentFolderParentId = null      for (const folderPart of folderParts) {        currentFolderPath.push(folderPart)        const existingFolderId = _.findKey(this.assetFolders, fld => { return fld === currentFolderPath.join('/') })        if (!existingFolderId) {          const newFolderObj = await WIKI.models.assetFolders.query().insert({            slug: folderPart,            name: folderPart,            parentId: currentFolderParentId          })          _.set(this.assetFolders, newFolderObj.id, currentFolderPath.join('/'))          currentFolderParentId = newFolderObj.id        } else {          currentFolderParentId = _.toInteger(existingFolderId)        }      }      folderId = currentFolderParentId    }    // -> Import asset    await WIKI.models.assets.upload({      mode: 'import',      originalname: filePathInfo.base,      ext: filePathInfo.ext,      mimetype: mime(filePathInfo.base) || 'application/octet-stream',      size: file.stats.size,      folderId: folderId,      path: file.path,      assetPath: relPath,      user: user,      skipStorage: true    })  },  clearFolderCache () {    this.assetFolders = null  }}
 |