refactor: remove config namespaces
This commit is contained in:
parent
b1499d1d64
commit
416755f17a
@ -58,7 +58,7 @@
|
|||||||
color='blue'
|
color='blue'
|
||||||
)
|
)
|
||||||
v-spacer
|
v-spacer
|
||||||
v-progress-circular.mr-3(indeterminate, color='blue', v-show='isLoading')
|
v-progress-circular.mr-3(indeterminate, color='blue', :size='22', :width='2' v-show='isLoading')
|
||||||
slot(name='actions')
|
slot(name='actions')
|
||||||
transition(name='navHeaderSearch')
|
transition(name='navHeaderSearch')
|
||||||
v-btn(icon, @click='searchToggle', v-if='!searchIsShown')
|
v-btn(icon, @click='searchToggle', v-if='!searchIsShown')
|
||||||
|
@ -41,6 +41,8 @@
|
|||||||
import VueRouter from 'vue-router'
|
import VueRouter from 'vue-router'
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from 'vuex'
|
||||||
|
|
||||||
|
/* global WIKI */
|
||||||
|
|
||||||
const router = new VueRouter({
|
const router = new VueRouter({
|
||||||
mode: 'history',
|
mode: 'history',
|
||||||
base: '/p',
|
base: '/p',
|
||||||
@ -53,6 +55,15 @@ const router = new VueRouter({
|
|||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
router.beforeEach((to, from, next) => {
|
||||||
|
WIKI.$store.commit('loadingStart', 'profile')
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
|
||||||
|
router.afterEach((to, from) => {
|
||||||
|
WIKI.$store.commit('loadingStop', 'profile')
|
||||||
|
})
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -12,13 +12,32 @@
|
|||||||
v-toolbar(color='primary', dark, dense, flat)
|
v-toolbar(color='primary', dark, dense, flat)
|
||||||
v-toolbar-title
|
v-toolbar-title
|
||||||
.subheading Display
|
.subheading Display
|
||||||
v-subheader Locale
|
v-card-text
|
||||||
|
v-subheader.pl-0 Locale
|
||||||
|
v-select.grey.lighten-5(solo, flat)
|
||||||
|
v-divider
|
||||||
|
v-subheader.pl-0 Timezone
|
||||||
|
v-select.grey.lighten-5(solo, flat)
|
||||||
|
v-divider.my-0
|
||||||
|
v-card-actions.grey.lighten-4
|
||||||
|
v-spacer
|
||||||
|
v-btn(color='primary')
|
||||||
|
v-icon(left) chevron_right
|
||||||
|
span Save
|
||||||
v-flex(lg6 xs12)
|
v-flex(lg6 xs12)
|
||||||
v-card
|
v-card
|
||||||
v-toolbar(color='primary', dark, dense, flat)
|
v-toolbar(color='primary', dark, dense, flat)
|
||||||
v-toolbar-title
|
v-toolbar-title
|
||||||
.subheading ---
|
.subheading Editing
|
||||||
v-card-text ---
|
v-card-text
|
||||||
|
v-subheader.pl-0 Default Editor
|
||||||
|
v-select.grey.lighten-5(solo, flat)
|
||||||
|
v-divider.my-0
|
||||||
|
v-card-actions.grey.lighten-4
|
||||||
|
v-spacer
|
||||||
|
v-btn(color='primary')
|
||||||
|
v-icon(left) chevron_right
|
||||||
|
span Save
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -1,40 +1,74 @@
|
|||||||
<template lang='pug'>
|
<template lang='pug'>
|
||||||
v-container(fluid, fill-height, grid-list-lg)
|
v-container(fluid, grid-list-lg)
|
||||||
v-layout(row wrap)
|
v-layout(row wrap)
|
||||||
v-flex(xs12)
|
v-flex(xs6)
|
||||||
.headline.primary--text Profile
|
.headline.primary--text Profile
|
||||||
.subheading.grey--text Personal profile
|
.subheading.grey--text Personal profile
|
||||||
v-form.pt-3
|
v-flex(xs6).text-xs-right
|
||||||
v-layout(row wrap)
|
v-btn(outline, color='primary').mr-0
|
||||||
v-flex(lg6 xs12)
|
v-icon(left) public
|
||||||
v-form
|
span View Public Profile
|
||||||
v-card
|
v-flex(lg6 xs12)
|
||||||
v-toolbar(color='primary', dark, dense, flat)
|
v-card
|
||||||
v-toolbar-title
|
v-toolbar(color='primary', dark, dense, flat)
|
||||||
.subheading User Details
|
v-toolbar-title
|
||||||
v-card-text
|
.subheading User Details
|
||||||
v-text-field(label='Name', :counter='255', v-model='name', prepend-icon='person')
|
v-card-text
|
||||||
v-divider
|
v-text-field(label='Name', :counter='255', v-model='name', prepend-icon='person')
|
||||||
v-text-field(label='Email', :counter='255', prepend-icon='email')
|
v-text-field(label='Job Title', :counter='255', prepend-icon='accessibility')
|
||||||
v-divider.my-0
|
v-text-field(label='Location / Office', :counter='255', prepend-icon='location_on')
|
||||||
v-card-actions.grey.lighten-4
|
v-divider.my-0
|
||||||
v-spacer
|
v-card-actions.grey.lighten-4
|
||||||
v-btn(color='primary')
|
v-spacer
|
||||||
v-icon(left) chevron_right
|
v-btn(color='primary')
|
||||||
span Save
|
v-icon(left) chevron_right
|
||||||
v-flex(lg6 xs12)
|
span Save
|
||||||
v-card
|
v-card.mt-3
|
||||||
v-toolbar(color='primary', dark, dense, flat)
|
v-toolbar(color='purple darken-4', dark, dense, flat)
|
||||||
v-toolbar-title
|
v-toolbar-title
|
||||||
.subheading Picture
|
.subheading Authentication
|
||||||
v-card-text ---
|
v-card-text
|
||||||
v-card.mt-3
|
v-subheader.pl-0 Provider
|
||||||
v-toolbar(color='teal', dark, dense, flat)
|
v-toolbar(flat, color='purple lighten-5', dense).purple--text.text--darken-4
|
||||||
v-toolbar-title
|
v-icon(color='purple darken-4') supervised_user_circle
|
||||||
.subheading Activity
|
.subheading.ml-3 Local
|
||||||
v-card-text.grey--text.text--darken-2
|
v-divider
|
||||||
.body-1 Joined #[strong January 1st, 2010]
|
v-subheader.pl-0 Two-Factor Authentication (2FA)
|
||||||
.body-1 Last login on #[strong January 2nd, 2010]
|
.caption.mb-2 2FA adds an extra layer of security by requiring a unique code generated on your smartphone when signing in.
|
||||||
|
v-btn(color='purple darken-4', dark, depressed).ml-0 Enable 2FA
|
||||||
|
v-btn(color='purple darken-4', dark, depressed, disabled).ml-0 Disable 2FA
|
||||||
|
v-divider
|
||||||
|
v-subheader.pl-0 Change Password
|
||||||
|
v-text-field(label='Current Password', prepend-icon='last_page')
|
||||||
|
v-text-field(label='New Password', prepend-icon='last_page')
|
||||||
|
v-text-field(label='Confirm New Password', prepend-icon='last_page')
|
||||||
|
v-btn(color='purple darken-4', dark, depressed).ml-0 Change Password
|
||||||
|
v-flex(lg6 xs12)
|
||||||
|
v-card
|
||||||
|
v-toolbar(color='primary', dark, dense, flat)
|
||||||
|
v-toolbar-title
|
||||||
|
.subheading Picture
|
||||||
|
v-card-title
|
||||||
|
v-avatar(size='64', color='grey')
|
||||||
|
v-icon(size='64', color='grey lighten-2') account_circle
|
||||||
|
v-btn(depressed).ml-4.elevation-1 Upload Picture
|
||||||
|
v-btn(depressed, disabled).elevation-1 Remove Picture
|
||||||
|
v-card.mt-3
|
||||||
|
v-toolbar(color='teal', dark, dense, flat)
|
||||||
|
v-toolbar-title
|
||||||
|
.subheading Activity
|
||||||
|
v-card-text.grey--text.text--darken-2
|
||||||
|
.body-2.grey--text Joined on
|
||||||
|
.body-1: strong January 1st, 2018 at 12:00 AM
|
||||||
|
.body-2.grey--text.mt-3 Profile last updated on
|
||||||
|
.body-1: strong January 1st, 2018 at 12:00 AM
|
||||||
|
.body-2.grey--text.mt-3 Last login on
|
||||||
|
.body-1: strong January 1st, 2018 at 12:00 AM
|
||||||
|
v-divider
|
||||||
|
.body-2.grey--text.mt-3 Pages created
|
||||||
|
.body-1: strong 0
|
||||||
|
.body-2.grey--text.mt-3 Comments posted
|
||||||
|
.body-1: strong 0
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@ -209,8 +209,12 @@
|
|||||||
v-flex.pr-3(xs6)
|
v-flex.pr-3(xs6)
|
||||||
v-text-field(
|
v-text-field(
|
||||||
ref='adminPassword',
|
ref='adminPassword',
|
||||||
|
counter='255'
|
||||||
v-model='conf.adminPassword',
|
v-model='conf.adminPassword',
|
||||||
label='Password',
|
label='Password',
|
||||||
|
:append-icon="pwdMode ? 'visibility' : 'visibility_off'"
|
||||||
|
:append-icon-cb="() => (pwdMode = !pwdMode)"
|
||||||
|
:type="pwdMode ? 'password' : 'text'"
|
||||||
hint='At least 8 characters long.',
|
hint='At least 8 characters long.',
|
||||||
v-validate='{ required: true, min: 8 }',
|
v-validate='{ required: true, min: 8 }',
|
||||||
data-vv-name='adminPassword',
|
data-vv-name='adminPassword',
|
||||||
@ -221,8 +225,12 @@
|
|||||||
v-flex(xs6)
|
v-flex(xs6)
|
||||||
v-text-field(
|
v-text-field(
|
||||||
ref='adminPasswordConfirm',
|
ref='adminPasswordConfirm',
|
||||||
|
counter='255'
|
||||||
v-model='conf.adminPasswordConfirm',
|
v-model='conf.adminPasswordConfirm',
|
||||||
label='Confirm Password',
|
label='Confirm Password',
|
||||||
|
:append-icon="pwdConfirmMode ? 'visibility' : 'visibility_off'"
|
||||||
|
:append-icon-cb="() => (pwdConfirmMode = !pwdConfirmMode)"
|
||||||
|
:type="pwdConfirmMode ? 'password' : 'text'"
|
||||||
hint='Verify your password again.',
|
hint='Verify your password again.',
|
||||||
v-validate='{ required: true, min: 8 }',
|
v-validate='{ required: true, min: 8 }',
|
||||||
data-vv-name='adminPasswordConfirm',
|
data-vv-name='adminPasswordConfirm',
|
||||||
@ -339,7 +347,9 @@ export default {
|
|||||||
title: siteConfig.title || 'Wiki',
|
title: siteConfig.title || 'Wiki',
|
||||||
upgrade: false,
|
upgrade: false,
|
||||||
upgMongo: 'mongodb://'
|
upgMongo: 'mongodb://'
|
||||||
}
|
},
|
||||||
|
pwdMode: true,
|
||||||
|
pwdConfirmMode: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
// @import 'node_modules/diff2html/dist/diff2html.min';
|
// @import 'node_modules/diff2html/dist/diff2html.min';
|
||||||
|
|
||||||
@import 'pages/welcome';
|
@import 'pages/welcome';
|
||||||
|
@import 'pages/error';
|
||||||
|
|
||||||
@import 'layout/_rtl';
|
@import 'layout/_rtl';
|
||||||
|
|
||||||
|
64
client/scss/pages/_error.scss
Normal file
64
client/scss/pages/_error.scss
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
.app-error {
|
||||||
|
background: linear-gradient(to bottom, mc('grey', '900') 0%, mc('grey', '800') 100%);
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
color: mc('grey', '50');
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 250px;
|
||||||
|
filter: grayscale(50%) brightness(120%);
|
||||||
|
animation: errorlogo 5s linear infinite;
|
||||||
|
margin-bottom: 3rem;
|
||||||
|
|
||||||
|
@include until($tablet) {
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes errorlogo {
|
||||||
|
0% {
|
||||||
|
filter: blur(0) grayscale(50%) brightness(200%) hue-rotate(110deg);
|
||||||
|
}
|
||||||
|
10% {
|
||||||
|
filter: blur(0) grayscale(50%) brightness(200%) hue-rotate(110deg) invert(100%);
|
||||||
|
}
|
||||||
|
15% {
|
||||||
|
filter: blur(0) grayscale(50%) brightness(200%) hue-rotate(110deg) invert(0%);
|
||||||
|
}
|
||||||
|
30% {
|
||||||
|
filter: blur(0) grayscale(50%) brightness(200%) hue-rotate(110deg);
|
||||||
|
}
|
||||||
|
32% {
|
||||||
|
filter: blur(0) grayscale(50%) brightness(200%) hue-rotate(2700deg) invert(100%);
|
||||||
|
}
|
||||||
|
34% {
|
||||||
|
filter: blur(0) grayscale(100%) brightness(50%) hue-rotate(110deg);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
filter: blur(0) grayscale(100%) brightness(200%) hue-rotate(110deg) sepia(0%);
|
||||||
|
}
|
||||||
|
55% {
|
||||||
|
filter: blur(0) grayscale(100%) brightness(100%) hue-rotate(110deg) sepia(100%);
|
||||||
|
}
|
||||||
|
60% {
|
||||||
|
filter: blur(0) grayscale(50%) brightness(200%) hue-rotate(110deg) sepia(0%);
|
||||||
|
}
|
||||||
|
90% {
|
||||||
|
filter: blur(0) grayscale(50%) brightness(200%) hue-rotate(110deg);
|
||||||
|
}
|
||||||
|
95% {
|
||||||
|
filter: blur(5px) grayscale(50%) brightness(200%) hue-rotate(720deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
filter: blur(0) grayscale(50%) brightness(200%) hue-rotate(110deg) invert(100%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
color: mc('grey', '500');
|
||||||
|
font-size: .8rem;
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,7 @@
|
|||||||
# https://docs.requarks.io/wiki/install
|
# https://docs.requarks.io/wiki/install
|
||||||
|
|
||||||
# ---------------------------------------------------------------------
|
# ---------------------------------------------------------------------
|
||||||
# Port the main server should listen to
|
# Port the server should listen to
|
||||||
# ---------------------------------------------------------------------
|
# ---------------------------------------------------------------------
|
||||||
|
|
||||||
port: 80
|
port: 80
|
||||||
@ -55,27 +55,3 @@ redis:
|
|||||||
# Possible values: error, warn, info (default), verbose, debug, silly
|
# Possible values: error, warn, info (default), verbose, debug, silly
|
||||||
|
|
||||||
logLevel: info
|
logLevel: info
|
||||||
|
|
||||||
# ---------------------------------------------------------------------
|
|
||||||
# Configuration Mode
|
|
||||||
# ---------------------------------------------------------------------
|
|
||||||
# Possible values: auto (default), file, setup
|
|
||||||
|
|
||||||
configMode: auto
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------
|
|
||||||
# Background Workers
|
|
||||||
# ---------------------------------------------------------------------
|
|
||||||
# Leave 0 for auto based on CPU cores
|
|
||||||
|
|
||||||
workers: 0
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------
|
|
||||||
# High Availability
|
|
||||||
# ---------------------------------------------------------------------
|
|
||||||
# Read the docs BEFORE changing these settings!
|
|
||||||
|
|
||||||
ha:
|
|
||||||
node: primary
|
|
||||||
uid: master
|
|
||||||
readonly: false
|
|
||||||
|
@ -23,12 +23,6 @@ defaults:
|
|||||||
port: 6379
|
port: 6379
|
||||||
db: 0
|
db: 0
|
||||||
password: null
|
password: null
|
||||||
configMode: auto
|
|
||||||
workers: 0
|
|
||||||
ha:
|
|
||||||
node: primary
|
|
||||||
uid: master
|
|
||||||
readonly: false
|
|
||||||
# DB defaults
|
# DB defaults
|
||||||
auth:
|
auth:
|
||||||
public: false
|
public: false
|
||||||
@ -36,8 +30,6 @@ defaults:
|
|||||||
local:
|
local:
|
||||||
isEnabled: true
|
isEnabled: true
|
||||||
allowSelfRegister: false
|
allowSelfRegister: false
|
||||||
git:
|
|
||||||
enabled: false
|
|
||||||
logging:
|
logging:
|
||||||
telemetry: false
|
telemetry: false
|
||||||
loggers:
|
loggers:
|
||||||
@ -48,6 +40,7 @@ defaults:
|
|||||||
rtl: false
|
rtl: false
|
||||||
title: Wiki.js
|
title: Wiki.js
|
||||||
# System defaults
|
# System defaults
|
||||||
|
setup: false
|
||||||
cors:
|
cors:
|
||||||
credentials: true
|
credentials: true
|
||||||
maxAge: 600
|
maxAge: 600
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
/* global WIKI */
|
|
||||||
|
|
||||||
const _ = require('lodash')
|
|
||||||
const passport = require('passport')
|
const passport = require('passport')
|
||||||
const fs = require('fs-extra')
|
const fs = require('fs-extra')
|
||||||
|
const _ = require('lodash')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const autoload = require('auto-load')
|
|
||||||
|
/* global WIKI */
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
strategies: {},
|
strategies: {},
|
||||||
@ -30,34 +29,39 @@ module.exports = {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// Load authentication strategies
|
|
||||||
|
|
||||||
const modules = _.values(autoload(path.join(WIKI.SERVERPATH, 'modules/authentication')))
|
|
||||||
_.forEach(modules, (strategy) => {
|
|
||||||
const strategyConfig = _.get(WIKI.config.auth.strategies, strategy.key, { isEnabled: false })
|
|
||||||
strategyConfig.callbackURL = `${WIKI.config.site.host}${WIKI.config.site.path}login/${strategy.key}/callback`
|
|
||||||
strategy.config = strategyConfig
|
|
||||||
if (strategyConfig.isEnabled) {
|
|
||||||
try {
|
|
||||||
strategy.init(passport, strategyConfig)
|
|
||||||
} catch (err) {
|
|
||||||
WIKI.logger.error(`Authentication Provider ${strategy.title}: [ FAILED ]`)
|
|
||||||
WIKI.logger.error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fs.readFile(path.join(WIKI.ROOTPATH, `assets/svg/auth-icon-${strategy.key}.svg`), 'utf8').then(iconData => {
|
|
||||||
strategy.icon = iconData
|
|
||||||
}).catch(err => {
|
|
||||||
if (err.code === 'ENOENT') {
|
|
||||||
strategy.icon = '[missing icon]'
|
|
||||||
} else {
|
|
||||||
WIKI.logger.warn(err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
this.strategies[strategy.key] = strategy
|
|
||||||
WIKI.logger.info(`Authentication Provider ${strategy.title}: [ OK ]`)
|
|
||||||
})
|
|
||||||
|
|
||||||
return this
|
return this
|
||||||
|
},
|
||||||
|
async activateStrategies() {
|
||||||
|
try {
|
||||||
|
// Unload any active strategies
|
||||||
|
WIKI.auth.strategies = []
|
||||||
|
const currentStrategies = _.keys(passport._strategies)
|
||||||
|
_.pull(currentStrategies, 'session')
|
||||||
|
_.forEach(currentStrategies, stg => { passport.unuse(stg) })
|
||||||
|
|
||||||
|
// Load enable strategies
|
||||||
|
const enabledStrategies = await WIKI.db.authentication.getEnabledStrategies()
|
||||||
|
for (let idx in enabledStrategies) {
|
||||||
|
const stg = enabledStrategies[idx]
|
||||||
|
const strategy = require(`../modules/authentication/${stg.key}`)
|
||||||
|
stg.config.callbackURL = `${WIKI.config.site.host}/login/${stg.key}/callback`
|
||||||
|
strategy.init(passport, stg.config)
|
||||||
|
|
||||||
|
fs.readFile(path.join(WIKI.ROOTPATH, `assets/svg/auth-icon-${strategy.key}.svg`), 'utf8').then(iconData => {
|
||||||
|
strategy.icon = iconData
|
||||||
|
}).catch(err => {
|
||||||
|
if (err.code === 'ENOENT') {
|
||||||
|
strategy.icon = '[missing icon]'
|
||||||
|
} else {
|
||||||
|
WIKI.logger.warn(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
WIKI.auth.strategies[stg.key] = strategy
|
||||||
|
WIKI.logger.info(`Authentication Strategy ${stg.title}: [ OK ]`)
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
WIKI.logger.error(`Authentication Strategy: [ FAILED ]`)
|
||||||
|
WIKI.logger.error(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,45 +50,32 @@ module.exports = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Load config from DB
|
* Load config from DB
|
||||||
*
|
|
||||||
* @param {Array} subsets Array of subsets to load
|
|
||||||
* @returns Promise
|
|
||||||
*/
|
*/
|
||||||
async loadFromDb(subsets) {
|
async loadFromDb() {
|
||||||
if (!_.isArray(subsets) || subsets.length === 0) {
|
let conf = await WIKI.db.settings.getConfig()
|
||||||
subsets = WIKI.data.configNamespaces
|
if (conf) {
|
||||||
}
|
WIKI.config = _.defaultsDeep(conf, WIKI.config)
|
||||||
|
|
||||||
let results = await WIKI.db.settings.query().select(['key', 'value']).whereIn('key', subsets)
|
|
||||||
if (_.isArray(results) && results.length === subsets.length) {
|
|
||||||
results.forEach(result => {
|
|
||||||
WIKI.config[result.key] = result.value
|
|
||||||
})
|
|
||||||
return true
|
|
||||||
} else {
|
} else {
|
||||||
WIKI.logger.warn('DB Configuration is empty or incomplete.')
|
WIKI.logger.warn('DB Configuration is empty or incomplete. Switching to Setup mode...')
|
||||||
return false
|
WIKI.config.setup = true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Save config to DB
|
* Save config to DB
|
||||||
*
|
*
|
||||||
* @param {Array} subsets Array of subsets to save
|
* @param {Array} keys Array of keys to save
|
||||||
* @returns Promise
|
* @returns Promise
|
||||||
*/
|
*/
|
||||||
async saveToDb(subsets) {
|
async saveToDb(keys) {
|
||||||
if (!_.isArray(subsets) || subsets.length === 0) {
|
|
||||||
subsets = WIKI.data.configNamespaces
|
|
||||||
}
|
|
||||||
|
|
||||||
let trx = await WIKI.db.Objection.transaction.start(WIKI.db.knex)
|
let trx = await WIKI.db.Objection.transaction.start(WIKI.db.knex)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (let set of subsets) {
|
for (let key of keys) {
|
||||||
console.info(set)
|
const value = _.get(WIKI.config, key, null)
|
||||||
await WIKI.db.settings.query(trx).patch({
|
let affectedRows = await WIKI.db.settings.query(trx).patch({ value }).where('key', key)
|
||||||
value: _.get(WIKI.config, set, {})
|
if (affectedRows === 0 && value) {
|
||||||
}).where('key', set)
|
await WIKI.db.settings.query(trx).insert({ key, value })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
await trx.commit()
|
await trx.commit()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -53,6 +53,20 @@ module.exports = {
|
|||||||
client: dbClient,
|
client: dbClient,
|
||||||
useNullAsDefault: true,
|
useNullAsDefault: true,
|
||||||
connection: dbConfig,
|
connection: dbConfig,
|
||||||
|
pool: {
|
||||||
|
async afterCreate(conn, done) {
|
||||||
|
// -> Set Connection App Name
|
||||||
|
switch (WIKI.config.db.type) {
|
||||||
|
case 'postgres':
|
||||||
|
await conn.query(`set application_name = 'Wiki.js'`)
|
||||||
|
done()
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
done()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
debug: WIKI.IS_DEBUG
|
debug: WIKI.IS_DEBUG
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -71,21 +85,13 @@ module.exports = {
|
|||||||
directory: path.join(WIKI.SERVERPATH, 'db/migrations'),
|
directory: path.join(WIKI.SERVERPATH, 'db/migrations'),
|
||||||
tableName: 'migrations'
|
tableName: 'migrations'
|
||||||
})
|
})
|
||||||
},
|
|
||||||
// -> Set Connection App Name
|
|
||||||
async setAppName() {
|
|
||||||
switch (WIKI.config.db.type) {
|
|
||||||
case 'postgres':
|
|
||||||
return self.knex.raw(`set application_name = 'Wiki.js'`)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let initTasksQueue = (WIKI.IS_MASTER) ? [
|
let initTasksQueue = (WIKI.IS_MASTER) ? [
|
||||||
initTasks.syncSchemas,
|
initTasks.syncSchemas
|
||||||
initTasks.setAppName
|
|
||||||
] : [
|
] : [
|
||||||
initTasks.setAppName
|
() => { return Promise.resolve() }
|
||||||
]
|
]
|
||||||
|
|
||||||
// Perform init tasks
|
// Perform init tasks
|
||||||
|
@ -1,89 +1,53 @@
|
|||||||
const _ = require('lodash')
|
|
||||||
const cluster = require('cluster')
|
|
||||||
const Promise = require('bluebird')
|
|
||||||
|
|
||||||
/* global WIKI */
|
/* global WIKI */
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
numWorkers: 1,
|
async init() {
|
||||||
workers: [],
|
WIKI.logger.info('=======================================')
|
||||||
init() {
|
WIKI.logger.info('= Wiki.js =============================')
|
||||||
if (cluster.isMaster) {
|
WIKI.logger.info('=======================================')
|
||||||
WIKI.logger.info('=======================================')
|
|
||||||
WIKI.logger.info('= Wiki.js =============================')
|
|
||||||
WIKI.logger.info('=======================================')
|
|
||||||
|
|
||||||
WIKI.redis = require('./redis').init()
|
WIKI.db = require('./db').init()
|
||||||
WIKI.queue = require('./queue').init()
|
WIKI.redis = require('./redis').init()
|
||||||
|
WIKI.queue = require('./queue').init()
|
||||||
|
|
||||||
this.setWorkerLimit()
|
await this.preBootMaster()
|
||||||
this.bootMaster()
|
this.bootMaster()
|
||||||
} else {
|
|
||||||
this.bootWorker()
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Pre-Master Boot Sequence
|
* Pre-Master Boot Sequence
|
||||||
*/
|
*/
|
||||||
preBootMaster() {
|
async preBootMaster() {
|
||||||
return Promise.mapSeries([
|
try {
|
||||||
() => { return WIKI.db.onReady },
|
await WIKI.db.onReady
|
||||||
() => { return WIKI.configSvc.loadFromDb() },
|
await WIKI.configSvc.loadFromDb()
|
||||||
() => { return WIKI.queue.clean() }
|
await WIKI.queue.clean()
|
||||||
], fn => { return fn() })
|
} catch (err) {
|
||||||
|
WIKI.logger.error(err)
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Boot Master Process
|
* Boot Master Process
|
||||||
*/
|
*/
|
||||||
bootMaster() {
|
async bootMaster() {
|
||||||
this.preBootMaster().then(sequenceResults => {
|
try {
|
||||||
if (_.every(sequenceResults, rs => rs === true) && WIKI.config.configMode !== 'setup') {
|
if (WIKI.config.setup) {
|
||||||
this.postBootMaster()
|
WIKI.logger.info('Starting setup wizard...')
|
||||||
} else {
|
|
||||||
WIKI.logger.info('Starting configuration manager...')
|
|
||||||
require('../setup')()
|
require('../setup')()
|
||||||
|
} else {
|
||||||
|
await require('../master')()
|
||||||
|
this.postBootMaster()
|
||||||
}
|
}
|
||||||
return true
|
} catch (err) {
|
||||||
}).catch(err => {
|
|
||||||
WIKI.logger.error(err)
|
WIKI.logger.error(err)
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
})
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Post-Master Boot Sequence
|
* Post-Master Boot Sequence
|
||||||
*/
|
*/
|
||||||
async postBootMaster() {
|
async postBootMaster() {
|
||||||
await require('../master')()
|
await WIKI.auth.activateStrategies()
|
||||||
|
await WIKI.queue.start()
|
||||||
WIKI.queue.start()
|
|
||||||
|
|
||||||
cluster.on('exit', (worker, code, signal) => {
|
|
||||||
if (!global.DEV) {
|
|
||||||
WIKI.logger.info(`Background Worker #${worker.id} was terminated.`)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Boot Worker Process
|
|
||||||
*/
|
|
||||||
bootWorker() {
|
|
||||||
WIKI.logger.info(`Background Worker #${cluster.worker.id} is initializing...`)
|
|
||||||
require('../worker')
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Spawn new Worker process
|
|
||||||
*/
|
|
||||||
spawnWorker() {
|
|
||||||
this.workers.push(cluster.fork())
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Set Worker count based on config + system capabilities
|
|
||||||
*/
|
|
||||||
setWorkerLimit() {
|
|
||||||
const numCPUs = require('os').cpus().length
|
|
||||||
this.numWorkers = (WIKI.config.workers > 0) ? WIKI.config.workers : numCPUs
|
|
||||||
if (this.numWorkers > numCPUs) {
|
|
||||||
this.numWorkers = numCPUs
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ module.exports = {
|
|||||||
ns: this.namespaces,
|
ns: this.namespaces,
|
||||||
defaultNS: 'common',
|
defaultNS: 'common',
|
||||||
saveMissing: false,
|
saveMissing: false,
|
||||||
lng: WIKI.config.site.lang,
|
lng: WIKI.config.lang,
|
||||||
fallbackLng: 'en'
|
fallbackLng: 'en'
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load current language
|
// Load current language
|
||||||
this.loadLocale(WIKI.config.site.lang, { silent: true })
|
this.loadLocale(WIKI.config.lang, { silent: true })
|
||||||
|
|
||||||
return this
|
return this
|
||||||
},
|
},
|
||||||
@ -55,6 +55,7 @@ module.exports = {
|
|||||||
const res = await WIKI.db.locales.query().findOne('code', locale)
|
const res = await WIKI.db.locales.query().findOne('code', locale)
|
||||||
if (res) {
|
if (res) {
|
||||||
if (_.isPlainObject(res.strings)) {
|
if (_.isPlainObject(res.strings)) {
|
||||||
|
console.info(res.strings)
|
||||||
_.forOwn(res.strings, (data, ns) => {
|
_.forOwn(res.strings, (data, ns) => {
|
||||||
this.namespaces.push(ns)
|
this.namespaces.push(ns)
|
||||||
this.engine.addResourceBundle(locale, ns, data, true, true)
|
this.engine.addResourceBundle(locale, ns, data, true, true)
|
||||||
|
@ -23,6 +23,15 @@ exports.up = knex => {
|
|||||||
table.string('slug').notNullable()
|
table.string('slug').notNullable()
|
||||||
table.integer('parentId').unsigned().references('id').inTable('assetFolders')
|
table.integer('parentId').unsigned().references('id').inTable('assetFolders')
|
||||||
})
|
})
|
||||||
|
// AUTHENTICATION ----------------------
|
||||||
|
.createTable('authentication', table => {
|
||||||
|
table.increments('id').primary()
|
||||||
|
table.string('key').notNullable().unique()
|
||||||
|
table.string('title').notNullable()
|
||||||
|
table.boolean('isEnabled').notNullable().defaultTo(false)
|
||||||
|
table.boolean('useForm').notNullable().defaultTo(false)
|
||||||
|
table.jsonb('config').notNullable()
|
||||||
|
})
|
||||||
// COMMENTS ----------------------------
|
// COMMENTS ----------------------------
|
||||||
.createTable('comments', table => {
|
.createTable('comments', table => {
|
||||||
table.increments('id').primary()
|
table.increments('id').primary()
|
||||||
@ -30,6 +39,14 @@ exports.up = knex => {
|
|||||||
table.string('createdAt').notNullable()
|
table.string('createdAt').notNullable()
|
||||||
table.string('updatedAt').notNullable()
|
table.string('updatedAt').notNullable()
|
||||||
})
|
})
|
||||||
|
// EDITORS -----------------------------
|
||||||
|
.createTable('editors', table => {
|
||||||
|
table.increments('id').primary()
|
||||||
|
table.string('key').notNullable().unique()
|
||||||
|
table.string('title').notNullable()
|
||||||
|
table.boolean('isEnabled').notNullable().defaultTo(false)
|
||||||
|
table.jsonb('config')
|
||||||
|
})
|
||||||
// GROUPS ------------------------------
|
// GROUPS ------------------------------
|
||||||
.createTable('groups', table => {
|
.createTable('groups', table => {
|
||||||
table.increments('id').primary()
|
table.increments('id').primary()
|
||||||
@ -54,6 +71,7 @@ exports.up = knex => {
|
|||||||
table.string('path').notNullable()
|
table.string('path').notNullable()
|
||||||
table.string('title').notNullable()
|
table.string('title').notNullable()
|
||||||
table.string('description')
|
table.string('description')
|
||||||
|
table.boolean('isPrivate').notNullable().defaultTo(false)
|
||||||
table.boolean('isPublished').notNullable().defaultTo(false)
|
table.boolean('isPublished').notNullable().defaultTo(false)
|
||||||
table.string('publishStartDate')
|
table.string('publishStartDate')
|
||||||
table.string('publishEndDate')
|
table.string('publishEndDate')
|
||||||
@ -66,9 +84,16 @@ exports.up = knex => {
|
|||||||
table.increments('id').primary()
|
table.increments('id').primary()
|
||||||
table.string('key').notNullable().unique()
|
table.string('key').notNullable().unique()
|
||||||
table.jsonb('value')
|
table.jsonb('value')
|
||||||
table.string('createdAt').notNullable()
|
|
||||||
table.string('updatedAt').notNullable()
|
table.string('updatedAt').notNullable()
|
||||||
})
|
})
|
||||||
|
// STORAGE -----------------------------
|
||||||
|
.createTable('storage', table => {
|
||||||
|
table.increments('id').primary()
|
||||||
|
table.string('key').notNullable().unique()
|
||||||
|
table.string('title').notNullable()
|
||||||
|
table.boolean('isEnabled').notNullable().defaultTo(false)
|
||||||
|
table.jsonb('config')
|
||||||
|
})
|
||||||
// TAGS --------------------------------
|
// TAGS --------------------------------
|
||||||
.createTable('tags', table => {
|
.createTable('tags', table => {
|
||||||
table.increments('id').primary()
|
table.increments('id').primary()
|
||||||
@ -82,16 +107,17 @@ exports.up = knex => {
|
|||||||
table.increments('id').primary()
|
table.increments('id').primary()
|
||||||
table.string('email').notNullable()
|
table.string('email').notNullable()
|
||||||
table.string('name').notNullable()
|
table.string('name').notNullable()
|
||||||
table.string('provider').notNullable().defaultTo('local')
|
|
||||||
table.string('providerId')
|
table.string('providerId')
|
||||||
table.string('password')
|
table.string('password')
|
||||||
table.boolean('tfaIsActive').notNullable().defaultTo(false)
|
table.boolean('tfaIsActive').notNullable().defaultTo(false)
|
||||||
table.string('tfaSecret')
|
table.string('tfaSecret')
|
||||||
table.enum('role', ['admin', 'guest', 'user']).notNullable().defaultTo('guest')
|
table.enum('role', ['admin', 'guest', 'user']).notNullable().defaultTo('guest')
|
||||||
|
table.string('jobTitle').defaultTo('')
|
||||||
|
table.string('location').defaultTo('')
|
||||||
|
table.string('pictureUrl')
|
||||||
|
table.string('timezone').notNullable().defaultTo('America/New_York')
|
||||||
table.string('createdAt').notNullable()
|
table.string('createdAt').notNullable()
|
||||||
table.string('updatedAt').notNullable()
|
table.string('updatedAt').notNullable()
|
||||||
|
|
||||||
table.unique(['provider', 'email'])
|
|
||||||
})
|
})
|
||||||
// =====================================
|
// =====================================
|
||||||
// RELATION TABLES
|
// RELATION TABLES
|
||||||
@ -120,11 +146,16 @@ exports.up = knex => {
|
|||||||
table.integer('authorId').unsigned().references('id').inTable('users')
|
table.integer('authorId').unsigned().references('id').inTable('users')
|
||||||
})
|
})
|
||||||
.table('pages', table => {
|
.table('pages', table => {
|
||||||
|
table.string('editor').references('key').inTable('editors')
|
||||||
table.string('locale', 2).references('code').inTable('locales')
|
table.string('locale', 2).references('code').inTable('locales')
|
||||||
table.integer('authorId').unsigned().references('id').inTable('users')
|
table.integer('authorId').unsigned().references('id').inTable('users')
|
||||||
})
|
})
|
||||||
.table('users', table => {
|
.table('users', table => {
|
||||||
table.string('locale', 2).references('code').inTable('locales')
|
table.string('provider').references('key').inTable('authentication').notNullable().defaultTo('local')
|
||||||
|
table.string('locale', 2).references('code').inTable('locales').notNullable().defaultTo('en')
|
||||||
|
table.string('defaultEditor').references('key').inTable('editors').notNullable().defaultTo('markdown')
|
||||||
|
|
||||||
|
table.unique(['provider', 'email'])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
64
server/db/models/authentication.js
Normal file
64
server/db/models/authentication.js
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
const Model = require('objection').Model
|
||||||
|
const autoload = require('auto-load')
|
||||||
|
const path = require('path')
|
||||||
|
const _ = require('lodash')
|
||||||
|
|
||||||
|
/* global WIKI */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authentication model
|
||||||
|
*/
|
||||||
|
module.exports = class Authentication extends Model {
|
||||||
|
static get tableName() { return 'authentication' }
|
||||||
|
|
||||||
|
static get jsonSchema () {
|
||||||
|
return {
|
||||||
|
type: 'object',
|
||||||
|
required: ['key', 'title', 'isEnabled', 'useForm'],
|
||||||
|
|
||||||
|
properties: {
|
||||||
|
id: {type: 'integer'},
|
||||||
|
key: {type: 'string'},
|
||||||
|
title: {type: 'string'},
|
||||||
|
isEnabled: {type: 'boolean'},
|
||||||
|
useForm: {type: 'boolean'},
|
||||||
|
config: {type: 'object'}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async getEnabledStrategies() {
|
||||||
|
return WIKI.db.authentication.query().where({ isEnabled: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
static async refreshStrategiesFromDisk() {
|
||||||
|
try {
|
||||||
|
const dbStrategies = await WIKI.db.authentication.query()
|
||||||
|
const diskStrategies = autoload(path.join(WIKI.SERVERPATH, 'modules/authentication'))
|
||||||
|
let newStrategies = []
|
||||||
|
_.forOwn(diskStrategies, (strategy, strategyKey) => {
|
||||||
|
if (!_.some(dbStrategies, ['key', strategy.key])) {
|
||||||
|
newStrategies.push({
|
||||||
|
key: strategy.key,
|
||||||
|
title: strategy.title,
|
||||||
|
isEnabled: false,
|
||||||
|
useForm: strategy.useForm,
|
||||||
|
config: _.reduce(strategy.props, (result, value, key) => {
|
||||||
|
_.set(result, value, '')
|
||||||
|
return result
|
||||||
|
}, {})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (newStrategies.length > 0) {
|
||||||
|
await WIKI.db.authentication.query().insert(newStrategies)
|
||||||
|
WIKI.logger.info(`Loaded ${newStrategies.length} new authentication strategies: [ OK ]`)
|
||||||
|
} else {
|
||||||
|
WIKI.logger.info(`No new authentication strategies found: [ SKIPPED ]`)
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
WIKI.logger.error(`Failed to scan or load new authentication providers: [ FAILED ]`)
|
||||||
|
WIKI.logger.error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
62
server/db/models/editors.js
Normal file
62
server/db/models/editors.js
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
const Model = require('objection').Model
|
||||||
|
const autoload = require('auto-load')
|
||||||
|
const path = require('path')
|
||||||
|
const _ = require('lodash')
|
||||||
|
|
||||||
|
/* global WIKI */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Editor model
|
||||||
|
*/
|
||||||
|
module.exports = class Editor extends Model {
|
||||||
|
static get tableName() { return 'editors' }
|
||||||
|
|
||||||
|
static get jsonSchema () {
|
||||||
|
return {
|
||||||
|
type: 'object',
|
||||||
|
required: ['key', 'title', 'isEnabled'],
|
||||||
|
|
||||||
|
properties: {
|
||||||
|
id: {type: 'integer'},
|
||||||
|
key: {type: 'string'},
|
||||||
|
title: {type: 'string'},
|
||||||
|
isEnabled: {type: 'boolean'},
|
||||||
|
config: {type: 'object'}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async getEnabledEditors() {
|
||||||
|
return WIKI.db.editors.query().where({ isEnabled: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
static async refreshEditorsFromDisk() {
|
||||||
|
try {
|
||||||
|
const dbEditors = await WIKI.db.editors.query()
|
||||||
|
const diskEditors = autoload(path.join(WIKI.SERVERPATH, 'modules/editor'))
|
||||||
|
let newEditors = []
|
||||||
|
_.forOwn(diskEditors, (strategy, strategyKey) => {
|
||||||
|
if (!_.some(dbEditors, ['key', strategy.key])) {
|
||||||
|
newEditors.push({
|
||||||
|
key: strategy.key,
|
||||||
|
title: strategy.title,
|
||||||
|
isEnabled: false,
|
||||||
|
config: _.reduce(strategy.props, (result, value, key) => {
|
||||||
|
_.set(result, value, '')
|
||||||
|
return result
|
||||||
|
}, {})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (newEditors.length > 0) {
|
||||||
|
await WIKI.db.editors.query().insert(newEditors)
|
||||||
|
WIKI.logger.info(`Loaded ${newEditors.length} new editors: [ OK ]`)
|
||||||
|
} else {
|
||||||
|
WIKI.logger.info(`No new editors found: [ SKIPPED ]`)
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
WIKI.logger.error(`Failed to scan or load new editors: [ FAILED ]`)
|
||||||
|
WIKI.logger.error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,12 @@
|
|||||||
const Model = require('objection').Model
|
const Model = require('objection').Model
|
||||||
|
const _ = require('lodash')
|
||||||
|
|
||||||
|
/* global WIKI */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Settings model
|
* Settings model
|
||||||
*/
|
*/
|
||||||
module.exports = class User extends Model {
|
module.exports = class Setting extends Model {
|
||||||
static get tableName() { return 'settings' }
|
static get tableName() { return 'settings' }
|
||||||
|
|
||||||
static get jsonSchema () {
|
static get jsonSchema () {
|
||||||
@ -25,7 +28,18 @@ module.exports = class User extends Model {
|
|||||||
this.updatedAt = new Date().toISOString()
|
this.updatedAt = new Date().toISOString()
|
||||||
}
|
}
|
||||||
$beforeInsert() {
|
$beforeInsert() {
|
||||||
this.createdAt = new Date().toISOString()
|
|
||||||
this.updatedAt = new Date().toISOString()
|
this.updatedAt = new Date().toISOString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async getConfig() {
|
||||||
|
const settings = await WIKI.db.settings.query()
|
||||||
|
if (settings.length > 0) {
|
||||||
|
return _.reduce(settings, (res, val, key) => {
|
||||||
|
_.set(res, val.key, (val.value.v) ? val.value.v : val.value)
|
||||||
|
return res
|
||||||
|
}, {})
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,9 @@ module.exports = class User extends Model {
|
|||||||
tfaIsActive: {type: 'boolean', default: false},
|
tfaIsActive: {type: 'boolean', default: false},
|
||||||
tfaSecret: {type: 'string'},
|
tfaSecret: {type: 'string'},
|
||||||
locale: {type: 'string'},
|
locale: {type: 'string'},
|
||||||
|
jobTitle: {type: 'string'},
|
||||||
|
location: {type: 'string'},
|
||||||
|
pictureUrl: {type: 'string'},
|
||||||
createdAt: {type: 'string'},
|
createdAt: {type: 'string'},
|
||||||
updatedAt: {type: 'string'}
|
updatedAt: {type: 'string'}
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,10 @@
|
|||||||
// ===========================================
|
// ===========================================
|
||||||
|
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const cluster = require('cluster')
|
|
||||||
|
|
||||||
let WIKI = {
|
let WIKI = {
|
||||||
IS_DEBUG: process.env.NODE_ENV === 'development',
|
IS_DEBUG: process.env.NODE_ENV === 'development',
|
||||||
IS_MASTER: cluster.isMaster,
|
IS_MASTER: true,
|
||||||
ROOTPATH: process.cwd(),
|
ROOTPATH: process.cwd(),
|
||||||
SERVERPATH: path.join(process.cwd(), 'server'),
|
SERVERPATH: path.join(process.cwd(), 'server'),
|
||||||
Error: require('./helpers/error'),
|
Error: require('./helpers/error'),
|
||||||
@ -32,18 +31,14 @@ WIKI.logger = require('./core/logger').init('MASTER')
|
|||||||
WIKI.telemetry = require('./core/telemetry').init()
|
WIKI.telemetry = require('./core/telemetry').init()
|
||||||
|
|
||||||
process.on('unhandledRejection', (err) => {
|
process.on('unhandledRejection', (err) => {
|
||||||
|
WIKI.logger.warn(err)
|
||||||
WIKI.telemetry.sendError(err)
|
WIKI.telemetry.sendError(err)
|
||||||
})
|
})
|
||||||
process.on('uncaughtException', (err) => {
|
process.on('uncaughtException', (err) => {
|
||||||
|
WIKI.logger.warn(err)
|
||||||
WIKI.telemetry.sendError(err)
|
WIKI.telemetry.sendError(err)
|
||||||
})
|
})
|
||||||
|
|
||||||
// ----------------------------------------
|
|
||||||
// Init DB
|
|
||||||
// ----------------------------------------
|
|
||||||
|
|
||||||
WIKI.db = require('./core/db').init()
|
|
||||||
|
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
// Start Kernel
|
// Start Kernel
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
|
@ -7,14 +7,15 @@ const { createApolloFetch } = require('apollo-fetch')
|
|||||||
WIKI.redis = require('../core/redis').init()
|
WIKI.redis = require('../core/redis').init()
|
||||||
WIKI.db = require('../core/db').init()
|
WIKI.db = require('../core/db').init()
|
||||||
|
|
||||||
const apollo = createApolloFetch({
|
|
||||||
uri: 'https://graph.requarks.io'
|
|
||||||
})
|
|
||||||
|
|
||||||
module.exports = async (job) => {
|
module.exports = async (job) => {
|
||||||
WIKI.logger.info(`Fetching locale ${job.data.locale} from Graph endpoint...`)
|
WIKI.logger.info(`Fetching locale ${job.data.locale} from Graph endpoint...`)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
await WIKI.configSvc.loadFromDb()
|
||||||
|
const apollo = createApolloFetch({
|
||||||
|
uri: WIKI.config.graphEndpoint
|
||||||
|
})
|
||||||
|
|
||||||
const respStrings = await apollo({
|
const respStrings = await apollo({
|
||||||
query: `query ($code: String!) {
|
query: `query ($code: String!) {
|
||||||
localization {
|
localization {
|
||||||
|
@ -7,15 +7,14 @@ const { createApolloFetch } = require('apollo-fetch')
|
|||||||
WIKI.redis = require('../core/redis').init()
|
WIKI.redis = require('../core/redis').init()
|
||||||
WIKI.db = require('../core/db').init()
|
WIKI.db = require('../core/db').init()
|
||||||
|
|
||||||
const apollo = createApolloFetch({
|
|
||||||
uri: 'https://graph.requarks.io'
|
|
||||||
})
|
|
||||||
|
|
||||||
module.exports = async (job) => {
|
module.exports = async (job) => {
|
||||||
WIKI.logger.info('Syncing locales with Graph endpoint...')
|
WIKI.logger.info('Syncing locales with Graph endpoint...')
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await WIKI.configSvc.loadFromDb(['site'])
|
await WIKI.configSvc.loadFromDb()
|
||||||
|
const apollo = createApolloFetch({
|
||||||
|
uri: WIKI.config.graphEndpoint
|
||||||
|
})
|
||||||
|
|
||||||
// -> Fetch locales list
|
// -> Fetch locales list
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ module.exports = async () => {
|
|||||||
app.use(session({
|
app.use(session({
|
||||||
name: 'wikijs.sid',
|
name: 'wikijs.sid',
|
||||||
store: sessionStore,
|
store: sessionStore,
|
||||||
secret: WIKI.config.site.sessionSecret,
|
secret: WIKI.config.sessionSecret,
|
||||||
resave: false,
|
resave: false,
|
||||||
saveUninitialized: false
|
saveUninitialized: false
|
||||||
}))
|
}))
|
||||||
|
10
server/modules/editor/markdown.js
Normal file
10
server/modules/editor/markdown.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// ------------------------------------
|
||||||
|
// Markdown Editor (default)
|
||||||
|
// ------------------------------------
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
key: 'markdown',
|
||||||
|
title: 'Markdown (default)',
|
||||||
|
props: [],
|
||||||
|
init (conf) {}
|
||||||
|
}
|
@ -250,8 +250,6 @@ module.exports = () => {
|
|||||||
app.post('/finalize', async (req, res) => {
|
app.post('/finalize', async (req, res) => {
|
||||||
WIKI.telemetry.sendEvent('setup', 'finalize')
|
WIKI.telemetry.sendEvent('setup', 'finalize')
|
||||||
|
|
||||||
console.error('DUDE')
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Upgrade from WIKI.js 1.x?
|
// Upgrade from WIKI.js 1.x?
|
||||||
if (req.body.upgrade) {
|
if (req.body.upgrade) {
|
||||||
@ -272,41 +270,31 @@ module.exports = () => {
|
|||||||
confRaw = yaml.safeDump(conf)
|
confRaw = yaml.safeDump(conf)
|
||||||
await fs.writeFileAsync(path.join(WIKI.ROOTPATH, 'config.yml'), confRaw)
|
await fs.writeFileAsync(path.join(WIKI.ROOTPATH, 'config.yml'), confRaw)
|
||||||
|
|
||||||
_.set(WIKI.config, 'port', req.body.port)
|
// Set config
|
||||||
|
_.set(WIKI.config, 'defaultEditor', true)
|
||||||
|
_.set(WIKI.config, 'graphEndpoint', 'https://graph.requarks.io')
|
||||||
|
_.set(WIKI.config, 'lang', 'en')
|
||||||
|
_.set(WIKI.config, 'langAutoUpdate', true)
|
||||||
|
_.set(WIKI.config, 'langRTL', false)
|
||||||
_.set(WIKI.config, 'paths.content', req.body.pathContent)
|
_.set(WIKI.config, 'paths.content', req.body.pathContent)
|
||||||
|
_.set(WIKI.config, 'port', req.body.port)
|
||||||
// Populate config namespaces
|
_.set(WIKI.config, 'public', req.body.public === 'true')
|
||||||
WIKI.config.auth = WIKI.config.auth || {}
|
_.set(WIKI.config, 'sessionSecret', (await crypto.randomBytesAsync(32)).toString('hex'))
|
||||||
WIKI.config.features = WIKI.config.features || {}
|
_.set(WIKI.config, 'telemetry', req.body.telemetry === 'true')
|
||||||
WIKI.config.logging = WIKI.config.logging || {}
|
_.set(WIKI.config, 'title', req.body.title)
|
||||||
WIKI.config.site = WIKI.config.site || {}
|
|
||||||
WIKI.config.theme = WIKI.config.theme || {}
|
|
||||||
WIKI.config.uploads = WIKI.config.uploads || {}
|
|
||||||
|
|
||||||
// Site namespace
|
|
||||||
_.set(WIKI.config.site, 'title', req.body.title)
|
|
||||||
_.set(WIKI.config.site, 'lang', 'en')
|
|
||||||
_.set(WIKI.config.site, 'langAutoUpdate', true)
|
|
||||||
_.set(WIKI.config.site, 'rtl', false)
|
|
||||||
_.set(WIKI.config.site, 'sessionSecret', (await crypto.randomBytesAsync(32)).toString('hex'))
|
|
||||||
|
|
||||||
// Auth namespace
|
|
||||||
_.set(WIKI.config.auth, 'public', req.body.public === 'true')
|
|
||||||
_.set(WIKI.config.auth, 'strategies.local.isEnabled', true)
|
|
||||||
_.set(WIKI.config.auth, 'strategies.local.allowSelfRegister', req.body.selfRegister === 'true')
|
|
||||||
|
|
||||||
// Logging namespace
|
|
||||||
WIKI.config.logging.telemetry = (req.body.telemetry === 'true')
|
|
||||||
|
|
||||||
// Save config to DB
|
// Save config to DB
|
||||||
WIKI.logger.info('Persisting config to DB...')
|
WIKI.logger.info('Persisting config to DB...')
|
||||||
await WIKI.db.settings.query().insert([
|
await WIKI.db.settings.query().insert([
|
||||||
{ key: 'auth', value: WIKI.config.auth },
|
{ key: 'defaultEditor', value: { v: WIKI.config.defaultEditor } },
|
||||||
{ key: 'features', value: WIKI.config.features },
|
{ key: 'graphEndpoint', value: { v: WIKI.config.graphEndpoint } },
|
||||||
{ key: 'logging', value: WIKI.config.logging },
|
{ key: 'lang', value: { v: WIKI.config.lang } },
|
||||||
{ key: 'site', value: WIKI.config.site },
|
{ key: 'langAutoUpdate', value: { v: WIKI.config.langAutoUpdate } },
|
||||||
{ key: 'theme', value: WIKI.config.theme },
|
{ key: 'langRTL', value: { v: WIKI.config.langRTL } },
|
||||||
{ key: 'uploads', value: WIKI.config.uploads }
|
{ key: 'public', value: { v: WIKI.config.public } },
|
||||||
|
{ key: 'sessionSecret', value: { v: WIKI.config.sessionSecret } },
|
||||||
|
{ key: 'telemetry', value: { v: WIKI.config.telemetry } },
|
||||||
|
{ key: 'title', value: { v: WIKI.config.title } }
|
||||||
])
|
])
|
||||||
|
|
||||||
// Create default locale
|
// Create default locale
|
||||||
@ -319,8 +307,20 @@ module.exports = () => {
|
|||||||
nativeName: 'English'
|
nativeName: 'English'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Load authentication strategies + enable local
|
||||||
|
await WIKI.db.authentication.refreshStrategiesFromDisk()
|
||||||
|
await WIKI.db.authentication.query().patch({ isEnabled: true }).where('key', 'local')
|
||||||
|
|
||||||
|
// Load editors + enable default
|
||||||
|
await WIKI.db.editors.refreshEditorsFromDisk()
|
||||||
|
await WIKI.db.editors.query().patch({ isEnabled: true }).where('key', 'markdown')
|
||||||
|
|
||||||
// Create root administrator
|
// Create root administrator
|
||||||
WIKI.logger.info('Creating root administrator...')
|
WIKI.logger.info('Creating root administrator...')
|
||||||
|
await WIKI.db.users.query().delete().where({
|
||||||
|
provider: 'local',
|
||||||
|
email: req.body.adminEmail
|
||||||
|
})
|
||||||
await WIKI.db.users.query().insert({
|
await WIKI.db.users.query().insert({
|
||||||
email: req.body.adminEmail,
|
email: req.body.adminEmail,
|
||||||
provider: 'local',
|
provider: 'local',
|
||||||
@ -328,11 +328,12 @@ module.exports = () => {
|
|||||||
name: 'Administrator',
|
name: 'Administrator',
|
||||||
role: 'admin',
|
role: 'admin',
|
||||||
locale: 'en',
|
locale: 'en',
|
||||||
|
defaultEditor: 'markdown',
|
||||||
tfaIsActive: false
|
tfaIsActive: false
|
||||||
})
|
})
|
||||||
|
|
||||||
// Create Guest account
|
// Create Guest account
|
||||||
WIKI.logger.info('Creating root administrator...')
|
WIKI.logger.info('Creating guest account...')
|
||||||
const guestUsr = await WIKI.db.users.query().findOne({
|
const guestUsr = await WIKI.db.users.query().findOne({
|
||||||
provider: 'local',
|
provider: 'local',
|
||||||
email: 'guest@example.com'
|
email: 'guest@example.com'
|
||||||
@ -345,6 +346,7 @@ module.exports = () => {
|
|||||||
password: '',
|
password: '',
|
||||||
role: 'guest',
|
role: 'guest',
|
||||||
locale: 'en',
|
locale: 'en',
|
||||||
|
defaultEditor: 'markdown',
|
||||||
tfaIsActive: false
|
tfaIsActive: false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -356,6 +358,8 @@ module.exports = () => {
|
|||||||
redirectPort: WIKI.config.port
|
redirectPort: WIKI.config.port
|
||||||
}).end()
|
}).end()
|
||||||
|
|
||||||
|
WIKI.config.setup = false
|
||||||
|
|
||||||
WIKI.logger.info('Stopping Setup...')
|
WIKI.logger.info('Stopping Setup...')
|
||||||
WIKI.server.destroy(() => {
|
WIKI.server.destroy(() => {
|
||||||
WIKI.logger.info('Setup stopped. Starting Wiki.js...')
|
WIKI.logger.info('Setup stopped. Starting Wiki.js...')
|
||||||
@ -392,7 +396,7 @@ module.exports = () => {
|
|||||||
// Start HTTP server
|
// Start HTTP server
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
|
|
||||||
WIKI.logger.info(`HTTP Server on port: ${WIKI.config.port}`)
|
WIKI.logger.info(`HTTP Server on port: [ ${WIKI.config.port} ]`)
|
||||||
|
|
||||||
app.set('port', WIKI.config.port)
|
app.set('port', WIKI.config.port)
|
||||||
WIKI.server = http.createServer(app)
|
WIKI.server = http.createServer(app)
|
||||||
@ -433,6 +437,6 @@ module.exports = () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
WIKI.server.on('listening', () => {
|
WIKI.server.on('listening', () => {
|
||||||
WIKI.logger.info('HTTP Server: RUNNING')
|
WIKI.logger.info('HTTP Server: [ RUNNING ]')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,26 @@
|
|||||||
extends ./master.pug
|
extends ./master.pug
|
||||||
|
|
||||||
block body
|
block body
|
||||||
body(class='is-error')
|
#app.is-fullscreen
|
||||||
.container
|
v-app(dark)
|
||||||
a(href='/'): img(src=config.site.path + '/images/logo.png')
|
.app-error
|
||||||
h1= message
|
v-container
|
||||||
h2= t('errors:generic')
|
.pt-5
|
||||||
a.button.is-amber.is-inverted.is-featured(href=config.site.path+ '/')= t('errors:actions.gohome')
|
v-layout(row)
|
||||||
|
v-flex(xs10)
|
||||||
if error.stack
|
a(href='/'): img(src='/svg/logo-wikijs.svg')
|
||||||
h3= t('errors:debugmsg')
|
v-flex(xs2).text-xs-right
|
||||||
pre: code #{error.stack}
|
v-btn(href='/', depressed, color='red darken-3')
|
||||||
|
v-icon(left) home
|
||||||
|
span Home
|
||||||
|
v-alert(color='grey', outline, :value='true', icon='error')
|
||||||
|
strong.red--text.text--lighten-3 Oops, something went wrong...
|
||||||
|
.body-1.red--text.text--lighten-2= message
|
||||||
|
|
||||||
|
if error.stack
|
||||||
|
v-expansion-panel.mt-5
|
||||||
|
v-expansion-panel-content.red.darken-3(:value='true')
|
||||||
|
div(slot='header') View Debug Trace
|
||||||
|
v-card(color='grey darken-4')
|
||||||
|
v-card-text
|
||||||
|
pre: code #{error.stack}
|
||||||
|
19
wiki.js
19
wiki.js
@ -87,19 +87,26 @@ const init = {
|
|||||||
const devWatcher = chokidar.watch([
|
const devWatcher = chokidar.watch([
|
||||||
'./server',
|
'./server',
|
||||||
'!./server/views/master.pug'
|
'!./server/views/master.pug'
|
||||||
])
|
], {
|
||||||
|
ignoreInitial: true,
|
||||||
|
atomic: 400
|
||||||
|
})
|
||||||
devWatcher.on('ready', () => {
|
devWatcher.on('ready', () => {
|
||||||
devWatcher.on('all', () => {
|
devWatcher.on('all', async () => {
|
||||||
console.warn('--- >>>>>>>>>>>>>>>>>>>>>>>>>>>> ---')
|
console.warn('--- >>>>>>>>>>>>>>>>>>>>>>>>>>>> ---')
|
||||||
console.warn('--- Changes detected: Restarting ---')
|
console.warn('--- Changes detected: Restarting ---')
|
||||||
console.warn('--- <<<<<<<<<<<<<<<<<<<<<<<<<<<< ---')
|
console.warn('--- <<<<<<<<<<<<<<<<<<<<<<<<<<<< ---')
|
||||||
|
console.warn('--- Closing DB connections...')
|
||||||
|
await global.WIKI.db.knex.destroy()
|
||||||
|
console.warn('--- Closing Redis connections...')
|
||||||
|
await global.WIKI.redis.quit()
|
||||||
|
console.warn('--- Closing Server connections...')
|
||||||
global.WIKI.server.destroy(() => {
|
global.WIKI.server.destroy(() => {
|
||||||
global.WIKI = {}
|
global.WIKI = {}
|
||||||
for (const workerId in cluster.workers) {
|
|
||||||
cluster.workers[workerId].kill()
|
|
||||||
}
|
|
||||||
Object.keys(require.cache).forEach(function(id) {
|
Object.keys(require.cache).forEach(function(id) {
|
||||||
if (/[/\\]server[/\\]/.test(id)) delete require.cache[id]
|
if (/[/\\]server[/\\]/.test(id)) {
|
||||||
|
delete require.cache[id]
|
||||||
|
}
|
||||||
})
|
})
|
||||||
require('./server')
|
require('./server')
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user