Browse Source

feat: config-manager component

NGPixel 7 years ago
parent
commit
c94e2d5700

+ 0 - 4
client/configure.js

@@ -1,4 +0,0 @@
-'use strict'
-
-require('./scss/configure.scss')
-require('./js/configure.js')

+ 2 - 0
client/js/app.js

@@ -52,6 +52,7 @@ import adminEditUserComponent from './pages/admin-edit-user.component.js'
 import adminProfileComponent from './pages/admin-profile.component.js'
 import adminProfileComponent from './pages/admin-profile.component.js'
 import adminSettingsComponent from './pages/admin-settings.component.js'
 import adminSettingsComponent from './pages/admin-settings.component.js'
 import adminThemeComponent from './pages/admin-theme.component.js'
 import adminThemeComponent from './pages/admin-theme.component.js'
+import configManagerComponent from './components/config-manager.component.js'
 import contentViewComponent from './pages/content-view.component.js'
 import contentViewComponent from './pages/content-view.component.js'
 import editorComponent from './components/editor.component.js'
 import editorComponent from './components/editor.component.js'
 import sourceViewComponent from './pages/source-view.component.js'
 import sourceViewComponent from './pages/source-view.component.js'
@@ -94,6 +95,7 @@ Vue.component('adminSettings', adminSettingsComponent)
 Vue.component('adminTheme', adminThemeComponent)
 Vue.component('adminTheme', adminThemeComponent)
 Vue.component('anchor', anchorComponent)
 Vue.component('anchor', anchorComponent)
 Vue.component('colorPicker', colorPickerComponent)
 Vue.component('colorPicker', colorPickerComponent)
+Vue.component('configManager', configManagerComponent)
 Vue.component('contentView', contentViewComponent)
 Vue.component('contentView', contentViewComponent)
 Vue.component('editor', editorComponent)
 Vue.component('editor', editorComponent)
 Vue.component('editorCodeblock', editorCodeblockComponent)
 Vue.component('editorCodeblock', editorCodeblockComponent)

+ 304 - 0
client/js/components/config-manager.component.js

@@ -0,0 +1,304 @@
+'use strict'
+
+/* global siteConfig */
+
+import VeeValidate from 'vee-validate'
+import axios from 'axios'
+
+Vue.use(VeeValidate, {
+  enableAutoClasses: true,
+  classNames: {
+    touched: 'is-touched', // the control has been blurred
+    untouched: 'is-untouched', // the control hasn't been blurred
+    valid: 'is-valid', // model is valid
+    invalid: 'is-invalid', // model is invalid
+    pristine: 'is-pristine', // control has not been interacted with
+    dirty: 'is-dirty' // control has been interacted with
+  }
+})
+
+export default {
+  name: 'configManager',
+  data() {
+    return {
+      loading: false,
+      state: 'welcome',
+      syscheck: {
+        ok: false,
+        error: '',
+        results: []
+      },
+      dbcheck: {
+        ok: false,
+        error: ''
+      },
+      gitcheck: {
+        ok: false,
+        error: ''
+      },
+      final: {
+        ok: false,
+        error: '',
+        results: []
+      },
+      conf: {
+        title: siteConfig.title || 'Wiki',
+        host: siteConfig.host || 'http://',
+        port: siteConfig.port || 80,
+        lang: siteConfig.lang || 'en',
+        public: (siteConfig.public === true),
+        db: siteConfig.db || 'mongodb://localhost:27017/wiki',
+        pathData: './data',
+        pathRepo: './repo',
+        gitUseRemote: (siteConfig.git !== false),
+        gitUrl: '',
+        gitBranch: 'master',
+        gitAuthType: 'ssh',
+        gitAuthSSHKey: '',
+        gitAuthUser: '',
+        gitAuthPass: '',
+        gitAuthSSL: true,
+        gitShowUserEmail: true,
+        gitServerEmail: '',
+        adminEmail: '',
+        adminPassword: '',
+        adminPasswordConfirm: ''
+      },
+      considerations: {
+        https: false,
+        port: false,
+        localhost: false
+      }
+    }
+  },
+  computed: {
+    currentProgress: function () {
+      let perc = '0%'
+      switch (this.state) {
+        case 'welcome':
+          perc = '0%'
+          break
+        case 'syscheck':
+          perc = (this.syscheck.ok) ? '15%' : '5%'
+          break
+        case 'general':
+          perc = '20%'
+          break
+        case 'considerations':
+          perc = '30%'
+          break
+        case 'db':
+          perc = '35%'
+          break
+        case 'dbcheck':
+          perc = (this.dbcheck.ok) ? '50%' : '40%'
+          break
+        case 'paths':
+          perc = '55%'
+          break
+        case 'git':
+          perc = '60%'
+          break
+        case 'gitcheck':
+          perc = (this.gitcheck.ok) ? '75%' : '65%'
+          break
+        case 'admin':
+          perc = '80%'
+          break
+      }
+      return perc
+    }
+  },
+  mounted: function () {
+    /* if (appconfig.paths) {
+      this.conf.pathData = appconfig.paths.data || './data'
+      this.conf.pathRepo = appconfig.paths.repo || './repo'
+    }
+    if (appconfig.git !== false && _.isPlainObject(appconfig.git)) {
+      this.conf.gitUrl = appconfig.git.url || ''
+      this.conf.gitBranch = appconfig.git.branch || 'master'
+      this.conf.gitShowUserEmail = (appconfig.git.showUserEmail !== false)
+      this.conf.gitServerEmail = appconfig.git.serverEmail || ''
+      if (_.isPlainObject(appconfig.git.auth)) {
+        this.conf.gitAuthType = appconfig.git.auth.type || 'ssh'
+        this.conf.gitAuthSSHKey = appconfig.git.auth.privateKey || ''
+        this.conf.gitAuthUser = appconfig.git.auth.username || ''
+        this.conf.gitAuthPass = appconfig.git.auth.password || ''
+        this.conf.gitAuthSSL = (appconfig.git.auth.sslVerify !== false)
+      }
+    } */
+  },
+  methods: {
+    proceedToWelcome: function (ev) {
+      this.state = 'welcome'
+      this.loading = false
+    },
+    proceedToSyscheck: function (ev) {
+      let self = this
+      this.state = 'syscheck'
+      this.loading = true
+      self.syscheck = {
+        ok: false,
+        error: '',
+        results: []
+      }
+
+      this.$helpers._.delay(() => {
+        axios.post('/syscheck').then(resp => {
+          if (resp.data.ok === true) {
+            self.syscheck.ok = true
+            self.syscheck.results = resp.data.results
+          } else {
+            self.syscheck.ok = false
+            self.syscheck.error = resp.data.error
+          }
+          self.loading = false
+          self.$nextTick()
+        }).catch(err => {
+          window.alert(err.message)
+        })
+      }, 1000)
+    },
+    proceedToGeneral: function (ev) {
+      let self = this
+      self.state = 'general'
+      self.loading = false
+      self.$nextTick(() => {
+        self.$validator.validateAll('general')
+      })
+    },
+    proceedToConsiderations: function (ev) {
+      this.considerations = {
+        https: !this.$helpers._.startsWith(this.conf.host, 'https'),
+        port: false, // TODO
+        localhost: this.$helpers._.includes(this.conf.host, 'localhost')
+      }
+      this.state = 'considerations'
+      this.loading = false
+    },
+    proceedToDb: function (ev) {
+      let self = this
+      self.state = 'db'
+      self.loading = false
+      self.$nextTick(() => {
+        self.$validator.validateAll('db')
+      })
+    },
+    proceedToDbcheck: function (ev) {
+      let self = this
+      this.state = 'dbcheck'
+      this.loading = true
+      self.dbcheck = {
+        ok: false,
+        error: ''
+      }
+
+      this.$helpers._.delay(() => {
+        axios.post('/dbcheck', {
+          db: self.conf.db
+        }).then(resp => {
+          if (resp.data.ok === true) {
+            self.dbcheck.ok = true
+          } else {
+            self.dbcheck.ok = false
+            self.dbcheck.error = resp.data.error
+          }
+          self.loading = false
+          self.$nextTick()
+        }).catch(err => {
+          window.alert(err.message)
+        })
+      }, 1000)
+    },
+    proceedToPaths: function (ev) {
+      let self = this
+      self.state = 'paths'
+      self.loading = false
+      self.$nextTick(() => {
+        self.$validator.validateAll('paths')
+      })
+    },
+    proceedToGit: function (ev) {
+      let self = this
+      self.state = 'git'
+      self.loading = false
+      self.$nextTick(() => {
+        self.$validator.validateAll('git')
+      })
+    },
+    proceedToGitCheck: function (ev) {
+      let self = this
+      this.state = 'gitcheck'
+      this.loading = true
+      self.gitcheck = {
+        ok: false,
+        results: [],
+        error: ''
+      }
+
+      this.$helpers._.delay(() => {
+        axios.post('/gitcheck', self.conf).then(resp => {
+          if (resp.data.ok === true) {
+            self.gitcheck.ok = true
+            self.gitcheck.results = resp.data.results
+          } else {
+            self.gitcheck.ok = false
+            self.gitcheck.error = resp.data.error
+          }
+          self.loading = false
+          self.$nextTick()
+        }).catch(err => {
+          window.alert(err.message)
+        })
+      }, 1000)
+    },
+    proceedToAdmin: function (ev) {
+      let self = this
+      self.state = 'admin'
+      self.loading = false
+      self.$nextTick(() => {
+        self.$validator.validateAll('admin')
+      })
+    },
+    proceedToFinal: function (ev) {
+      let self = this
+      self.state = 'final'
+      self.loading = true
+      self.final = {
+        ok: false,
+        error: '',
+        results: []
+      }
+
+      this.$helpers._.delay(() => {
+        axios.post('/finalize', self.conf).then(resp => {
+          if (resp.data.ok === true) {
+            self.final.ok = true
+            self.final.results = resp.data.results
+          } else {
+            self.final.ok = false
+            self.final.error = resp.data.error
+          }
+          self.loading = false
+          self.$nextTick()
+        }).catch(err => {
+          window.alert(err.message)
+        })
+      }, 1000)
+    },
+    finish: function (ev) {
+      let self = this
+      self.state = 'restart'
+
+      this.$helpers._.delay(() => {
+        axios.post('/restart', {}).then(resp => {
+          this.$helpers._.delay(() => {
+            window.location.assign(self.conf.host)
+          }, 30000)
+        }).catch(err => {
+          window.alert(err.message)
+        })
+      }, 1000)
+    }
+  }
+}

+ 3 - 3
client/js/components/editor-video.vue

@@ -34,9 +34,9 @@
 
 
 <script>
 <script>
   const videoRules = {
   const videoRules = {
-    'youtube': new RegExp(/(?:(?:youtu\.be\/|v\/|vi\/|u\/\w\/|embed\/)|(?:(?:watch)?\?v(?:i)?=|&v(?:i)?=))([^#&?]*).*/, 'i'),
-    'vimeo': new RegExp(/vimeo.com\/(?:channels\/(?:\w+\/)?|groups\/(?:[^/]*)\/videos\/|album\/(?:\d+)\/video\/|)(\d+)(?:$|\/|\?)/, 'i'),
-    'dailymotion': new RegExp(/(?:dailymotion\.com(?:\/embed)?(?:\/video|\/hub)|dai\.ly)\/([0-9a-z]+)(?:[-_0-9a-zA-Z]+(?:#video=)?([a-z0-9]+)?)?/, 'i')
+    'youtube': new RegExp('/(?:(?:youtu\\.be\\/|v\\/|vi\\/|u\\/\\w\\/|embed\\/)|(?:(?:watch)?\\?v(?:i)?=|&v(?:i)?=))([^#&?]*).*/', 'i'),
+    'vimeo': new RegExp('/vimeo.com\\/(?:channels\\/(?:\\w+\\/)?|groups\\/(?:[^/]*)\\/videos\\/|album\\/(?:\\d+)\\/video\\/|)(\\d+)(?:$|\\/|\\?)/', 'i'),
+    'dailymotion': new RegExp('/(?:dailymotion\\.com(?:\\/embed)?(?:\\/video|\\/hub)|dai\\.ly)\\/([0-9a-z]+)(?:[-_0-9a-zA-Z]+(?:#video=)?([a-z0-9]+)?)?/', 'i')
   }
   }
 
 
   export default {
   export default {

+ 1 - 0
client/scss/app.scss

@@ -15,6 +15,7 @@ $primary: 'indigo';
 @import 'components/button';
 @import 'components/button';
 @import 'components/collapsable-nav';
 @import 'components/collapsable-nav';
 @import 'components/color-picker';
 @import 'components/color-picker';
+@import 'components/config-manager';
 @import 'components/footer';
 @import 'components/footer';
 @import 'components/form';
 @import 'components/form';
 @import 'components/grid';
 @import 'components/grid';

+ 5 - 1
client/scss/components/button.scss

@@ -97,7 +97,11 @@
       background-color: mc('grey', '300') !important;
       background-color: mc('grey', '300') !important;
       color: mc('grey', '500') !important;
       color: mc('grey', '500') !important;
     }
     }
-	}
+  }
+
+  &.is-small {
+    height: 30px;
+  }
 
 
 }
 }
 
 

+ 61 - 0
client/scss/components/config-manager.scss

@@ -0,0 +1,61 @@
+.config-manager {
+  .welcome {
+    text-align: center;
+    padding: 50px 0 15px 0;
+    color: mc('grey', '700');
+
+    h2 {
+      margin: 0;
+    }
+
+  }
+
+  i.icon-loader {
+    display: inline-block;
+    color: mc('indigo', '500')
+  }
+  i.icon-check {
+    color: mc('green', '500')
+  }
+  i.icon-square-cross {
+    color: mc('red', '500')
+  }
+  i.icon-warning-outline {
+    color: mc('orange', '500')
+  }
+
+  .tst-welcome-leave-active, .tst-welcome-enter-active {
+    transition: all .5s;
+    overflow-y: hidden;
+  }
+  .tst-welcome-leave, .tst-welcome-enter-to {
+    opacity: 1;
+    max-height: 200px;
+  }
+  .tst-welcome-leave-to, .tst-welcome-enter {
+    opacity: 0;
+    max-height: 0;
+    padding-top: 0;
+  }
+
+  .progress-bar {
+    width: 150px;
+    height: 10px;
+    background-color: mc('indigo', '50');
+    border:1px solid mc('indigo', '100');
+    border-radius: 3px;
+    position: absolute;
+    left: 15px;
+    top: 21px;
+    padding: 1px;
+
+    > div {
+      width: 5px;
+      height: 6px;
+      background-color: mc('indigo', '200');
+      border-radius: 2px;
+      transition: all 1s ease;
+    }
+
+  }
+}

+ 11 - 0
server/app/data.yml

@@ -24,6 +24,17 @@ defaults:
     ha:
     ha:
       nodeuid: primary
       nodeuid: primary
       readonly: false
       readonly: false
+    site:
+      path: ''
+    title: Wiki.js
+configNamespaces:
+  - auth
+  - features
+  - git
+  - logging
+  - site
+  - theme
+  - uploads
 queues:
 queues:
   - gitSync
   - gitSync
   - uplClearTemp
   - uplClearTemp

+ 33 - 50
server/configure.js

@@ -1,12 +1,8 @@
-'use strict'
+const path = require('path')
 
 
-module.exports = (port, spinner) => {
-  const path = require('path')
-
-  const ROOTPATH = process.cwd()
-  const SERVERPATH = path.join(ROOTPATH, 'server')
-  const IS_DEBUG = process.env.NODE_ENV === 'development'
+/* global wiki */
 
 
+module.exports = () => {
   // ----------------------------------------
   // ----------------------------------------
   // Load modules
   // Load modules
   // ----------------------------------------
   // ----------------------------------------
@@ -26,28 +22,30 @@ module.exports = (port, spinner) => {
   // Define Express App
   // Define Express App
   // ----------------------------------------
   // ----------------------------------------
 
 
-  var app = express()
+  let app = express()
   app.use(compression())
   app.use(compression())
 
 
-  var server
+  let server
 
 
   // ----------------------------------------
   // ----------------------------------------
   // Public Assets
   // Public Assets
   // ----------------------------------------
   // ----------------------------------------
 
 
-  app.use(favicon(path.join(ROOTPATH, 'assets', 'favicon.ico')))
-  app.use(express.static(path.join(ROOTPATH, 'assets')))
+  app.use(favicon(path.join(wiki.ROOTPATH, 'assets', 'favicon.ico')))
+  app.use(express.static(path.join(wiki.ROOTPATH, 'assets')))
 
 
   // ----------------------------------------
   // ----------------------------------------
   // View Engine Setup
   // View Engine Setup
   // ----------------------------------------
   // ----------------------------------------
 
 
-  app.set('views', path.join(SERVERPATH, 'views'))
+  app.set('views', path.join(wiki.SERVERPATH, 'views'))
   app.set('view engine', 'pug')
   app.set('view engine', 'pug')
 
 
   app.use(bodyParser.json())
   app.use(bodyParser.json())
   app.use(bodyParser.urlencoded({ extended: false }))
   app.use(bodyParser.urlencoded({ extended: false }))
 
 
+  app.locals.config = wiki.config
+  app.locals.data = wiki.data
   app.locals._ = require('lodash')
   app.locals._ = require('lodash')
 
 
   // ----------------------------------------
   // ----------------------------------------
@@ -55,22 +53,7 @@ module.exports = (port, spinner) => {
   // ----------------------------------------
   // ----------------------------------------
 
 
   app.get('*', (req, res) => {
   app.get('*', (req, res) => {
-    let langs = []
-    let conf = {}
-    try {
-      langs = yaml.safeLoad(fs.readFileSync(path.join(SERVERPATH, 'app/data.yml'), 'utf8')).langs
-      conf = yaml.safeLoad(fs.readFileSync(path.join(ROOTPATH, 'config.yml'), 'utf8'))
-    } catch (err) {
-      console.error(err)
-    }
-    res.render('configure/index', {
-      langs,
-      conf,
-      runmode: {
-        staticPort: (process.env.WIKI_JS_HEROKU || process.env.WIKI_JS_DOCKER),
-        staticMongo: (!_.isNil(process.env.WIKI_JS_HEROKU))
-      }
-    })
+    res.render('configure/index')
   })
   })
 
 
   /**
   /**
@@ -81,14 +64,14 @@ module.exports = (port, spinner) => {
       () => {
       () => {
         const semver = require('semver')
         const semver = require('semver')
         if (!semver.satisfies(semver.clean(process.version), '>=6.9.0')) {
         if (!semver.satisfies(semver.clean(process.version), '>=6.9.0')) {
-          throw new Error('Node.js version is too old. Minimum is v6.11.1.')
+          throw new Error('Node.js version is too old. Minimum is 6.11.1.')
         }
         }
-        return 'Node.js ' + process.version + ' detected.'
+        return 'Node.js ' + process.version + ' detected. Minimum is 6.11.1.'
       },
       },
       () => {
       () => {
         return Promise.try(() => {
         return Promise.try(() => {
           require('crypto')
           require('crypto')
-        }).catch(err => { // eslint-disable-line handle-callback-err
+        }).catch(err => {
           throw new Error('Crypto Node.js module is not available.')
           throw new Error('Crypto Node.js module is not available.')
         }).return('Node.js Crypto module is available.')
         }).return('Node.js Crypto module is available.')
       },
       },
@@ -102,9 +85,9 @@ module.exports = (port, spinner) => {
             }
             }
             let gitver = _.head(stdout.match(/[\d]+\.[\d]+(\.[\d]+)?/gi))
             let gitver = _.head(stdout.match(/[\d]+\.[\d]+(\.[\d]+)?/gi))
             if (!gitver || !semver.satisfies(semver.clean(gitver), '>=2.7.4')) {
             if (!gitver || !semver.satisfies(semver.clean(gitver), '>=2.7.4')) {
-              reject(new Error('Git version is too old. Minimum is v2.7.4.'))
+              reject(new Error('Git version is too old. Minimum is 2.7.4.'))
             }
             }
-            resolve('Git v' + gitver + ' detected. Minimum is v2.7.4.')
+            resolve('Git ' + gitver + ' detected. Minimum is 2.7.4.')
           })
           })
         })
         })
       },
       },
@@ -118,8 +101,8 @@ module.exports = (port, spinner) => {
       () => {
       () => {
         let fs = require('fs')
         let fs = require('fs')
         return Promise.try(() => {
         return Promise.try(() => {
-          fs.accessSync(path.join(ROOTPATH, 'config.yml'), (fs.constants || fs).W_OK)
-        }).catch(err => { // eslint-disable-line handle-callback-err
+          fs.accessSync(path.join(wiki.ROOTPATH, 'config.yml'), (fs.constants || fs).W_OK)
+        }).catch(err => {
           throw new Error('config.yml file is not writable by Node.js process or was not created properly.')
           throw new Error('config.yml file is not writable by Node.js process or was not created properly.')
         }).return('config.yml is writable by the setup process.')
         }).return('config.yml is writable by the setup process.')
       }
       }
@@ -174,8 +157,8 @@ module.exports = (port, spinner) => {
     const exec = require('execa')
     const exec = require('execa')
     const url = require('url')
     const url = require('url')
 
 
-    const dataDir = path.resolve(ROOTPATH, cfgHelper.parseConfigValue(req.body.pathData))
-    const gitDir = path.resolve(ROOTPATH, cfgHelper.parseConfigValue(req.body.pathRepo))
+    const dataDir = path.resolve(wiki.ROOTPATH, cfgHelper.parseConfigValue(req.body.pathData))
+    const gitDir = path.resolve(wiki.ROOTPATH, cfgHelper.parseConfigValue(req.body.pathRepo))
 
 
     let gitRemoteUrl = ''
     let gitRemoteUrl = ''
 
 
@@ -315,7 +298,7 @@ module.exports = (port, spinner) => {
           }
           }
         })
         })
       }),
       }),
-      fs.readFileAsync(path.join(ROOTPATH, 'config.yml'), 'utf8').then(confRaw => {
+      fs.readFileAsync(path.join(wiki.ROOTPATH, 'config.yml'), 'utf8').then(confRaw => {
         let conf = yaml.safeLoad(confRaw)
         let conf = yaml.safeLoad(confRaw)
         conf.title = req.body.title
         conf.title = req.body.title
         conf.host = req.body.host
         conf.host = req.body.host
@@ -356,12 +339,12 @@ module.exports = (port, spinner) => {
         return crypto.randomBytesAsync(32).then(buf => {
         return crypto.randomBytesAsync(32).then(buf => {
           conf.sessionSecret = buf.toString('hex')
           conf.sessionSecret = buf.toString('hex')
           confRaw = yaml.safeDump(conf)
           confRaw = yaml.safeDump(conf)
-          return fs.writeFileAsync(path.join(ROOTPATH, 'config.yml'), confRaw)
+          return fs.writeFileAsync(path.join(wiki.ROOTPATH, 'config.yml'), confRaw)
         })
         })
       })
       })
     ).then(() => {
     ).then(() => {
       if (process.env.IS_HEROKU) {
       if (process.env.IS_HEROKU) {
-        return fs.outputJsonAsync(path.join(SERVERPATH, 'app/heroku.json'), { configured: true })
+        return fs.outputJsonAsync(path.join(wiki.SERVERPATH, 'app/heroku.json'), { configured: true })
       } else {
       } else {
         return true
         return true
       }
       }
@@ -377,7 +360,7 @@ module.exports = (port, spinner) => {
    */
    */
   app.post('/restart', (req, res) => {
   app.post('/restart', (req, res) => {
     res.status(204).end()
     res.status(204).end()
-    server.destroy(() => {
+    /* server.destroy(() => {
       spinner.text = 'Setup wizard terminated. Restarting in normal mode...'
       spinner.text = 'Setup wizard terminated. Restarting in normal mode...'
       _.delay(() => {
       _.delay(() => {
         const exec = require('execa')
         const exec = require('execa')
@@ -386,7 +369,7 @@ module.exports = (port, spinner) => {
           process.exit(0)
           process.exit(0)
         })
         })
       }, 1000)
       }, 1000)
-    })
+    }) */
   })
   })
 
 
   // ----------------------------------------
   // ----------------------------------------
@@ -403,9 +386,9 @@ module.exports = (port, spinner) => {
     res.status(err.status || 500)
     res.status(err.status || 500)
     res.send({
     res.send({
       message: err.message,
       message: err.message,
-      error: IS_DEBUG ? err : {}
+      error: wiki.IS_DEBUG ? err : {}
     })
     })
-    spinner.fail(err.message)
+    wiki.logger.error(err.message)
     process.exit(1)
     process.exit(1)
   })
   })
 
 
@@ -413,11 +396,11 @@ module.exports = (port, spinner) => {
   // Start HTTP server
   // Start HTTP server
   // ----------------------------------------
   // ----------------------------------------
 
 
-  spinner.text = 'Starting HTTP server...'
+  wiki.logger.info(`HTTP Server on port: ${wiki.config.port}`)
 
 
-  app.set('port', port)
+  app.set('port', wiki.config.port)
   server = http.createServer(app)
   server = http.createServer(app)
-  server.listen(port)
+  server.listen(wiki.config.port)
 
 
   var openConnections = []
   var openConnections = []
 
 
@@ -443,10 +426,10 @@ module.exports = (port, spinner) => {
 
 
     switch (error.code) {
     switch (error.code) {
       case 'EACCES':
       case 'EACCES':
-        spinner.fail('Listening on port ' + port + ' requires elevated privileges!')
+        wiki.logger.error('Listening on port ' + wiki.config.port + ' requires elevated privileges!')
         return process.exit(1)
         return process.exit(1)
       case 'EADDRINUSE':
       case 'EADDRINUSE':
-        spinner.fail('Port ' + port + ' is already in use!')
+        wiki.logger.error('Port ' + wiki.config.port + ' is already in use!')
         return process.exit(1)
         return process.exit(1)
       default:
       default:
         throw error
         throw error
@@ -454,6 +437,6 @@ module.exports = (port, spinner) => {
   })
   })
 
 
   server.on('listening', () => {
   server.on('listening', () => {
-    spinner.text = 'Browse to http://localhost:' + port + ' to configure Wiki.js!'
+    wiki.logger.info('HTTP Server: RUNNING')
   })
   })
 }
 }

+ 0 - 2
server/models/_relations.js

@@ -1,5 +1,3 @@
-'use strict'
-
 /**
 /**
  * Associate DB Model relations
  * Associate DB Model relations
  */
  */

+ 0 - 2
server/models/comment.js

@@ -1,5 +1,3 @@
-'use strict'
-
 /**
 /**
  * Comment schema
  * Comment schema
  */
  */

+ 0 - 2
server/models/document.js

@@ -1,5 +1,3 @@
-'use strict'
-
 /**
 /**
  * Document schema
  * Document schema
  */
  */

+ 0 - 2
server/models/file.js

@@ -1,5 +1,3 @@
-'use strict'
-
 /**
 /**
  * File schema
  * File schema
  */
  */

+ 0 - 2
server/models/folder.js

@@ -1,5 +1,3 @@
-'use strict'
-
 /**
 /**
  * Folder schema
  * Folder schema
  */
  */

+ 0 - 2
server/models/group.js

@@ -1,5 +1,3 @@
-'use strict'
-
 /**
 /**
  * Group schema
  * Group schema
  */
  */

+ 0 - 2
server/models/right.js

@@ -1,5 +1,3 @@
-'use strict'
-
 /**
 /**
  * Right schema
  * Right schema
  */
  */

+ 0 - 2
server/models/setting.js

@@ -1,5 +1,3 @@
-'use strict'
-
 /**
 /**
  * Settings schema
  * Settings schema
  */
  */

+ 0 - 2
server/models/tag.js

@@ -1,5 +1,3 @@
-'use strict'
-
 /**
 /**
  * Tags schema
  * Tags schema
  */
  */

+ 0 - 2
server/models/user.js

@@ -1,5 +1,3 @@
-'use strict'
-
 /* global wiki */
 /* global wiki */
 
 
 const Promise = require('bluebird')
 const Promise = require('bluebird')

+ 0 - 2
server/modules/auth.js

@@ -1,5 +1,3 @@
-'use strict'
-
 /* global wiki */
 /* global wiki */
 
 
 const _ = require('lodash')
 const _ = require('lodash')

+ 1 - 5
server/modules/config.js

@@ -1,5 +1,3 @@
-'use strict'
-
 /* global wiki */
 /* global wiki */
 
 
 const fs = require('fs')
 const fs = require('fs')
@@ -9,8 +7,6 @@ const path = require('path')
 const cfgHelper = require('../helpers/config')
 const cfgHelper = require('../helpers/config')
 
 
 module.exports = {
 module.exports = {
-  SUBSETS: ['auth', 'features', 'git', 'logging', 'site', 'theme', 'uploads'],
-
   /**
   /**
    * Load root config from disk
    * Load root config from disk
    */
    */
@@ -64,7 +60,7 @@ module.exports = {
    */
    */
   loadFromDb(subsets) {
   loadFromDb(subsets) {
     if (!_.isArray(subsets) || subsets.length === 0) {
     if (!_.isArray(subsets) || subsets.length === 0) {
-      subsets = this.SUBSETS
+      subsets = wiki.data.configNamespaces
     }
     }
 
 
     return wiki.db.Setting.findAll({
     return wiki.db.Setting.findAll({

+ 1 - 1
server/modules/db.js

@@ -110,7 +110,7 @@ module.exports = {
       // -> Sync DB Schemas
       // -> Sync DB Schemas
       syncSchemas() {
       syncSchemas() {
         return self.inst.sync({
         return self.inst.sync({
-          force: true,
+          force: false,
           logging: log => { wiki.logger.log('verbose', log) }
           logging: log => { wiki.logger.log('verbose', log) }
         })
         })
       },
       },

+ 38 - 68
server/views/configure/index.pug

@@ -1,31 +1,9 @@
-doctype html
-html(data-logic='configure')
-  head
-    meta(http-equiv='X-UA-Compatible', content='IE=edge')
-    meta(charset='UTF-8')
-    title Wiki.js | Configure
-
-    // Favicon
-    each favsize in [32, 96, 16]
-      link(rel='icon', type='image/png', sizes=favsize + 'x' + favsize, href='/favicons/favicon-' + favsize + 'x' + favsize + '.png')
-
-    // JS / CSS
-    script(type='text/javascript').
-      var appconfig = !{JSON.stringify(conf)};
-      var runmode = !{JSON.stringify(runmode)};
-    script(type='text/javascript', src='/js/vendor.js')
-    script(type='text/javascript', src='/js/configure.js')
+extends ../master.pug
 
 
+block body
   body
   body
-    #root
-      #header-container
-        nav.nav#header
-          .nav-left
-            a.nav-item
-              h1
-                i.icon-layers
-                | Wiki.js
-      main
+    #app.config-manager
+      config-manager(inline-template)
         .container
         .container
           transition(name='tst-welcome')
           transition(name='tst-welcome')
             .welcome(v-if='state === "welcome" || state === "restart"')
             .welcome(v-if='state === "welcome" || state === "restart"')
@@ -47,7 +25,7 @@ html(data-logic='configure')
                   p Detailed information about installation and usage can be found on the #[a(href='https://docs.wiki.requarks.io/') official documentation site]. #[br] Should you have any question or would like to report something that doesn't look right, feel free to create a new issue on the #[a(href='https://github.com/Requarks/wiki/issues') GitHub project].
                   p Detailed information about installation and usage can be found on the #[a(href='https://docs.wiki.requarks.io/') official documentation site]. #[br] Should you have any question or would like to report something that doesn't look right, feel free to create a new issue on the #[a(href='https://github.com/Requarks/wiki/issues') GitHub project].
                 .panel-footer
                 .panel-footer
                   .progress-bar: div(v-bind:style='{width: currentProgress}')
                   .progress-bar: div(v-bind:style='{width: currentProgress}')
-                  button.button.is-light-blue(v-on:click='proceedToSyscheck', v-bind:disabled='loading') Start
+                  button.button.is-small.is-light-blue(v-on:click='proceedToSyscheck', v-bind:disabled='loading') Start
 
 
             //- ==============================================
             //- ==============================================
             //- SYSTEM CHECK
             //- SYSTEM CHECK
@@ -69,9 +47,9 @@ html(data-logic='configure')
                   p(v-if='!loading && !syscheck.ok') #[i.icon-square-cross] Error: {{ syscheck.error }}
                   p(v-if='!loading && !syscheck.ok') #[i.icon-square-cross] Error: {{ syscheck.error }}
                 .panel-footer
                 .panel-footer
                   .progress-bar: div(v-bind:style='{width: currentProgress}')
                   .progress-bar: div(v-bind:style='{width: currentProgress}')
-                  button.button.is-light-blue.is-outlined(v-on:click='proceedToWelcome', v-bind:disabled='loading') Back
-                  button.button.is-teal(v-on:click='proceedToSyscheck', v-if='!loading && !syscheck.ok') Check Again
-                  button.button.is-light-blue(v-on:click='proceedToGeneral', v-if='loading || syscheck.ok', v-bind:disabled='loading') Continue
+                  button.button.is-small.is-light-blue.is-outlined(v-on:click='proceedToWelcome', v-bind:disabled='loading') Back
+                  button.button.is-small.is-teal(v-on:click='proceedToSyscheck', v-if='!loading && !syscheck.ok') Check Again
+                  button.button.is-small.is-light-blue(v-on:click='proceedToGeneral', v-if='loading || syscheck.ok', v-bind:disabled='loading') Continue
 
 
             //- ==============================================
             //- ==============================================
             //- GENERAL
             //- GENERAL
@@ -93,17 +71,16 @@ html(data-logic='configure')
                       label.label Host
                       label.label Host
                       input(type='text', placeholder='http://', v-model='conf.host', data-vv-scope='general', name='ipt-host', v-validate='{ required: true, min: 4 }')
                       input(type='text', placeholder='http://', v-model='conf.host', data-vv-scope='general', name='ipt-host', v-validate='{ required: true, min: 4 }')
                       span.desc The full URL to your wiki, without the trailing slash. E.g.: http://wiki.domain.com. Note that sub-folders are #[u not supported].
                       span.desc The full URL to your wiki, without the trailing slash. E.g.: http://wiki.domain.com. Note that sub-folders are #[u not supported].
-                  if !runmode.staticPort
-                    section
-                      p.control
-                        label.label Port
-                        input(type='text', placeholder='e.g. 80', v-model.number='conf.port', data-vv-scope='general', name='ipt-port', v-validate='{ required: true }')
-                        span.desc The port on which Wiki.js will listen to. Usually port 80 if connecting directly, or a random port (e.g. 3000) if using a web server in front of it.<br>Set <strong>$(PORT)</strong> to use PORT environment variable.
+                  section
+                    p.control
+                      label.label Port
+                      input(type='text', placeholder='e.g. 80', v-model.number='conf.port', data-vv-scope='general', name='ipt-port', v-validate='{ required: true }')
+                      span.desc The port on which Wiki.js will listen to. Usually port 80 if connecting directly, or a random port (e.g. 3000) if using a web server in front of it.<br>Set <strong>$(PORT)</strong> to use PORT environment variable.
                   section
                   section
                     p.control
                     p.control
                       label.label Site UI Language
                       label.label Site UI Language
-                      select(v-model='conf.lang')
-                        each lg in langs
+                      select(v-model='conf.site.lang')
+                        each lg in data.langs
                           option(value=lg.id)= lg.name
                           option(value=lg.id)= lg.name
                       span.desc The language in which navigation, help and other UI elements will be displayed.
                       span.desc The language in which navigation, help and other UI elements will be displayed.
                   section
                   section
@@ -113,8 +90,8 @@ html(data-logic='configure')
                       span.desc Should the site be accessible (read only) without login.
                       span.desc Should the site be accessible (read only) without login.
                 .panel-footer
                 .panel-footer
                   .progress-bar: div(v-bind:style='{width: currentProgress}')
                   .progress-bar: div(v-bind:style='{width: currentProgress}')
-                  button.button.is-light-blue.is-outlined(v-on:click='proceedToSyscheck', v-bind:disabled='loading') Back
-                  button.button.is-light-blue(v-on:click='proceedToConsiderations', v-bind:disabled='loading || errors.any("general")') Continue
+                  button.button.is-small.is-light-blue.is-outlined(v-on:click='proceedToSyscheck', v-bind:disabled='loading') Back
+                  button.button.is-small.is-light-blue(v-on:click='proceedToConsiderations', v-bind:disabled='loading || errors.any("general")') Continue
 
 
             //- ==============================================
             //- ==============================================
             //- CONSIDERATIONS
             //- CONSIDERATIONS
@@ -144,8 +121,8 @@ html(data-logic='configure')
                     p The host URL you specified is localhost. Unless you are a developer running Wiki.js locally on your machine, this is not recommended!
                     p The host URL you specified is localhost. Unless you are a developer running Wiki.js locally on your machine, this is not recommended!
                 .panel-footer
                 .panel-footer
                   .progress-bar: div(v-bind:style='{width: currentProgress}')
                   .progress-bar: div(v-bind:style='{width: currentProgress}')
-                  button.button.is-light-blue.is-outlined(v-on:click='proceedToGeneral', v-bind:disabled='loading') Back
-                  button.button.is-light-blue(v-on:click='proceedToDb', v-bind:disabled='loading') Continue
+                  button.button.is-small.is-light-blue.is-outlined(v-on:click='proceedToGeneral', v-bind:disabled='loading') Back
+                  button.button.is-small.is-light-blue(v-on:click='proceedToDb', v-bind:disabled='loading') Continue
 
 
             //- ==============================================
             //- ==============================================
             //- DATABASE
             //- DATABASE
@@ -166,8 +143,8 @@ html(data-logic='configure')
                       span.desc The connection string to your MongoDB server. Leave the default localhost value if MongoDB is installed on the same server.<br />You can also specify an environment variable as the connection string, e.g. $(MONGO_URI).
                       span.desc The connection string to your MongoDB server. Leave the default localhost value if MongoDB is installed on the same server.<br />You can also specify an environment variable as the connection string, e.g. $(MONGO_URI).
                 .panel-footer
                 .panel-footer
                   .progress-bar: div(v-bind:style='{width: currentProgress}')
                   .progress-bar: div(v-bind:style='{width: currentProgress}')
-                  button.button.is-light-blue.is-outlined(v-on:click='proceedToConsiderations', v-bind:disabled='loading') Back
-                  button.button.is-light-blue(v-on:click='proceedToDbcheck', v-bind:disabled='loading || errors.any("db")') Connect
+                  button.button.is-small.is-light-blue.is-outlined(v-on:click='proceedToConsiderations', v-bind:disabled='loading') Back
+                  button.button.is-small.is-light-blue(v-on:click='proceedToDbcheck', v-bind:disabled='loading || errors.any("db")') Connect
 
 
             //- ==============================================
             //- ==============================================
             //- DATABASE CHECK
             //- DATABASE CHECK
@@ -186,9 +163,9 @@ html(data-logic='configure')
                   p(v-if='!loading && !dbcheck.ok') #[i.icon-square-cross] Error: {{ dbcheck.error }}
                   p(v-if='!loading && !dbcheck.ok') #[i.icon-square-cross] Error: {{ dbcheck.error }}
                 .panel-footer
                 .panel-footer
                   .progress-bar: div(v-bind:style='{width: currentProgress}')
                   .progress-bar: div(v-bind:style='{width: currentProgress}')
-                  button.button.is-light-blue.is-outlined(v-on:click='proceedToDb', v-bind:disabled='loading') Back
-                  button.button.is-teal(v-on:click='proceedToDbcheck', v-if='!loading && !dbcheck.ok') Try Again
-                  button.button.is-light-blue(v-on:click='proceedToPaths', v-if='loading || dbcheck.ok', v-bind:disabled='loading') Continue
+                  button.button.is-small.is-light-blue.is-outlined(v-on:click='proceedToDb', v-bind:disabled='loading') Back
+                  button.button.is-small.is-teal(v-on:click='proceedToDbcheck', v-if='!loading && !dbcheck.ok') Try Again
+                  button.button.is-small.is-light-blue(v-on:click='proceedToPaths', v-if='loading || dbcheck.ok', v-bind:disabled='loading') Continue
 
 
             //- ==============================================
             //- ==============================================
             //- PATHS
             //- PATHS
@@ -214,8 +191,8 @@ html(data-logic='configure')
                       span.desc The path where the local git repository will be created, used to store content in markdown files and uploads.
                       span.desc The path where the local git repository will be created, used to store content in markdown files and uploads.
                 .panel-footer
                 .panel-footer
                   .progress-bar: div(v-bind:style='{width: currentProgress}')
                   .progress-bar: div(v-bind:style='{width: currentProgress}')
-                  button.button.is-light-blue.is-outlined(v-on:click='proceedToDb', v-bind:disabled='loading') Back
-                  button.button.is-light-blue(v-on:click='proceedToGit', v-bind:disabled='loading || errors.any("paths")') Continue
+                  button.button.is-small.is-light-blue.is-outlined(v-on:click='proceedToDb', v-bind:disabled='loading') Back
+                  button.button.is-small.is-light-blue(v-on:click='proceedToGit', v-bind:disabled='loading || errors.any("paths")') Continue
 
 
             //- ==============================================
             //- ==============================================
             //- GIT
             //- GIT
@@ -279,9 +256,9 @@ html(data-logic='configure')
                         span.desc The default/fallback email to use when creating commits to the git repository.
                         span.desc The default/fallback email to use when creating commits to the git repository.
                 .panel-footer
                 .panel-footer
                   .progress-bar: div(v-bind:style='{width: currentProgress}')
                   .progress-bar: div(v-bind:style='{width: currentProgress}')
-                  button.button.is-light-blue.is-outlined(v-on:click='proceedToPaths', v-bind:disabled='loading') Back
-                  button.button.is-light-blue.is-outlined(v-on:click='conf.gitUseRemote = false; proceedToGitCheck()', v-bind:disabled='loading') Skip this step
-                  button.button.is-light-blue(v-on:click='conf.gitUseRemote = true; proceedToGitCheck()', v-bind:disabled='loading || errors.any("git")') Continue
+                  button.button.is-small.is-light-blue.is-outlined(v-on:click='proceedToPaths', v-bind:disabled='loading') Back
+                  button.button.is-small.is-light-blue.is-outlined(v-on:click='conf.gitUseRemote = false; proceedToGitCheck()', v-bind:disabled='loading') Skip this step
+                  button.button.is-small.is-light-blue(v-on:click='conf.gitUseRemote = true; proceedToGitCheck()', v-bind:disabled='loading || errors.any("git")') Continue
             
             
             //- ==============================================
             //- ==============================================
             //- GIT CHECK
             //- GIT CHECK
@@ -303,9 +280,9 @@ html(data-logic='configure')
                   p(v-if='!loading && !gitcheck.ok') #[i.icon-square-cross] Error: {{ gitcheck.error }}
                   p(v-if='!loading && !gitcheck.ok') #[i.icon-square-cross] Error: {{ gitcheck.error }}
                 .panel-footer
                 .panel-footer
                   .progress-bar: div(v-bind:style='{width: currentProgress}')
                   .progress-bar: div(v-bind:style='{width: currentProgress}')
-                  button.button.is-light-blue.is-outlined(v-on:click='proceedToGit', v-bind:disabled='loading') Back
-                  button.button.is-teal(v-on:click='proceedToGitCheck', v-if='!loading && !gitcheck.ok') Try Again
-                  button.button.is-light-blue(v-on:click='proceedToAdmin', v-if='loading || gitcheck.ok', v-bind:disabled='loading') Continue
+                  button.button.is-small.is-light-blue.is-outlined(v-on:click='proceedToGit', v-bind:disabled='loading') Back
+                  button.button.is-small.is-teal(v-on:click='proceedToGitCheck', v-if='!loading && !gitcheck.ok') Try Again
+                  button.button.is-small.is-light-blue(v-on:click='proceedToAdmin', v-if='loading || gitcheck.ok', v-bind:disabled='loading') Continue
 
 
             //- ==============================================
             //- ==============================================
             //- ADMINISTRATOR ACCOUNT
             //- ADMINISTRATOR ACCOUNT
@@ -337,8 +314,8 @@ html(data-logic='configure')
                         span.desc Verify your password again.
                         span.desc Verify your password again.
                 .panel-footer
                 .panel-footer
                   .progress-bar: div(v-bind:style='{width: currentProgress}')
                   .progress-bar: div(v-bind:style='{width: currentProgress}')
-                  button.button.is-light-blue.is-outlined(v-on:click='proceedToGit', v-bind:disabled='loading') Back
-                  button.button.is-light-blue(v-on:click='proceedToFinal', v-bind:disabled='loading || errors.any("admin")') Continue
+                  button.button.is-small.is-light-blue.is-outlined(v-on:click='proceedToGit', v-bind:disabled='loading') Back
+                  button.button.is-small.is-light-blue(v-on:click='proceedToFinal', v-bind:disabled='loading || errors.any("admin")') Continue
 
 
             //- ==============================================
             //- ==============================================
             //- FINAL
             //- FINAL
@@ -359,9 +336,9 @@ html(data-logic='configure')
                   p(v-if='!loading && !final.ok') #[i.icon-square-cross] Error: {{ final.error }}
                   p(v-if='!loading && !final.ok') #[i.icon-square-cross] Error: {{ final.error }}
                 .panel-footer
                 .panel-footer
                   .progress-bar: div(v-bind:style='{width: currentProgress}')
                   .progress-bar: div(v-bind:style='{width: currentProgress}')
-                  button.button.is-light-blue.is-outlined(v-on:click='proceedToAdmin', v-bind:disabled='loading') Back
-                  button.button.is-teal(v-on:click='proceedToFinal', v-if='!loading && !final.ok') Try Again
-                  button.button.is-green(v-on:click='finish', v-if='loading || final.ok', v-bind:disabled='loading') Start
+                  button.button.is-small.is-light-blue.is-outlined(v-on:click='proceedToAdmin', v-bind:disabled='loading') Back
+                  button.button.is-small.is-teal(v-on:click='proceedToFinal', v-if='!loading && !final.ok') Try Again
+                  button.button.is-small.is-green(v-on:click='finish', v-if='loading || final.ok', v-bind:disabled='loading') Start
 
 
             //- ==============================================
             //- ==============================================
             //- RESTART
             //- RESTART
@@ -376,11 +353,4 @@ html(data-logic='configure')
                   p #[i.icon-loader.animated.rotateIn.infinite] Restarting Wiki.js in normal mode...
                   p #[i.icon-loader.animated.rotateIn.infinite] Restarting Wiki.js in normal mode...
                   p You'll automatically be redirected to the homepage when ready. This usually takes about 30 seconds.
                   p You'll automatically be redirected to the homepage when ready. This usually takes about 30 seconds.
                 .panel-footer
                 .panel-footer
-                  button.button.is-green(disabled='disabled') Start
-
-      footer.footer
-        span
-          | Powered by 
-          a(href='https://github.com/Requarks/wiki') Wiki.js
-          | .
-    block outside
+                  button.button.is-small.is-green(disabled='disabled') Start

+ 1 - 1
server/views/master.pug

@@ -7,7 +7,7 @@ html
     meta(name='theme-color', content='#009688')
     meta(name='theme-color', content='#009688')
     meta(name='msapplication-TileColor', content='#009688')
     meta(name='msapplication-TileColor', content='#009688')
     meta(name='msapplication-TileImage', content=config.site.path + '/favicons/ms-icon-144x144.png')
     meta(name='msapplication-TileImage', content=config.site.path + '/favicons/ms-icon-144x144.png')
-    title= config.title
+    title= config.site.title
 
 
     //- Favicon
     //- Favicon
     each favsize in [57, 60, 72, 76, 114, 120, 144, 152, 180]
     each favsize in [57, 60, 72, 76, 114, 120, 144, 152, 180]