diff --git a/.editorconfig b/.editorconfig index b9583094..50dbfd02 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,7 +8,7 @@ trim_trailing_whitespace = true end_of_line = lf insert_final_newline = true -[*.{jade,pug,md}] +[*.{pug,md}] trim_trailing_whitespace = false [Makefile] diff --git a/.nvmrc b/.nvmrc deleted file mode 100644 index 0c6886ca..00000000 --- a/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -v12.16.3 diff --git a/client/client-app.js b/client/client-app.js index c70db6dd..6d4c4340 100644 --- a/client/client-app.js +++ b/client/client-app.js @@ -47,7 +47,7 @@ store.commit('user/REFRESH_AUTH') // Initialize Apollo Client (GraphQL) // ==================================== -const graphQLEndpoint = window.location.protocol + '//' + window.location.host + '/graphql' +const graphQLEndpoint = window.location.protocol + '//' + window.location.host + '/_graphql' const graphQLLink = ApolloLink.from([ new ErrorLink(({ graphQLErrors, networkError }) => { diff --git a/client/client-setup.js b/client/client-setup.js deleted file mode 100644 index 2eb68371..00000000 --- a/client/client-setup.js +++ /dev/null @@ -1,21 +0,0 @@ -/* eslint-disable import/first */ -import Vue from 'vue' -import Vuetify from 'vuetify/lib' -import boot from './modules/boot' -/* eslint-enable import/first */ - -window.WIKI = null -window.boot = boot - -Vue.use(Vuetify) - -Vue.component('setup', () => import(/* webpackMode: "eager" */ './components/setup.vue')) - -let bootstrap = () => { - window.WIKI = new Vue({ - el: '#root', - vuetify: new Vuetify() - }) -} - -window.boot.onDOMReady(bootstrap) diff --git a/client/components/login.vue b/client/components/login.vue index f74a4744..e7875ccf 100644 --- a/client/components/login.vue +++ b/client/components/login.vue @@ -662,26 +662,34 @@ export default { apollo: { strategies: { query: gql` - { - authentication { - activeStrategies(enabledOnly: true) { + query loginFetchSiteStrategies( + $siteId: UUID + ) { + authStrategies( + siteId: $siteId + enabledOnly: true + ) { + key + strategy { key - strategy { - key - logo - color - icon - useForm - usernameType - } - displayName - order - selfRegistration + logo + color + icon + useForm + usernameType } + displayName + order + selfRegistration } } `, - update: (data) => _.sortBy(data.authentication.activeStrategies, ['order']), + variables () { + return { + siteId: siteConfig.id + } + }, + update: (data) => _.sortBy(data.authStrategies, ['order']), watchLoading (isLoading) { this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'login-strategies-refresh') } diff --git a/client/index-legacy.js b/client/index-legacy.js deleted file mode 100644 index ac2f6f51..00000000 --- a/client/index-legacy.js +++ /dev/null @@ -1,4 +0,0 @@ -require('./scss/legacy.scss') -require('./scss/fonts/default.scss') - -window.WIKI = null diff --git a/client/index-setup.js b/client/index-setup.js deleted file mode 100644 index 4d398de0..00000000 --- a/client/index-setup.js +++ /dev/null @@ -1,11 +0,0 @@ -require('core-js/stable') -require('regenerator-runtime/runtime') - -/* eslint-disable no-unused-expressions */ - -require('./scss/app.scss') -import(/* webpackChunkName: "mdi" */ '@mdi/font/css/materialdesignicons.css') - -require('./helpers/compatibility.js') - -require('./client-setup.js') diff --git a/dev/index.js b/dev/index.js index f3b719db..9f565e80 100644 --- a/dev/index.js +++ b/dev/index.js @@ -60,7 +60,7 @@ const init = { }, async reload() { console.warn(chalk.yellow('--- Gracefully stopping server...')) - await global.WIKI.kernel.shutdown() + await global.WIKI.kernel.shutdown(true) console.warn(chalk.yellow('--- Purging node modules cache...')) diff --git a/dev/templates/master.pug b/dev/templates/base.pug similarity index 99% rename from dev/templates/master.pug rename to dev/templates/base.pug index 478d2725..fa90ce42 100644 --- a/dev/templates/master.pug +++ b/dev/templates/base.pug @@ -29,6 +29,7 @@ html(lang=siteConfig.lang) //- Site Properties script. + var siteId = "!{siteId}" var siteConfig = !{JSON.stringify(siteConfig)} var siteLangs = !{JSON.stringify(langs)} diff --git a/dev/templates/setup.pug b/dev/templates/setup.pug deleted file mode 100644 index e264901e..00000000 --- a/dev/templates/setup.pug +++ /dev/null @@ -1,48 +0,0 @@ -doctype html -html - head - meta(http-equiv='X-UA-Compatible', content='IE=edge') - meta(charset='UTF-8') - meta(name='viewport', content='user-scalable=yes, width=device-width, initial-scale=1, maximum-scale=5') - meta(name='theme-color', content='#1976d2') - meta(name='msapplication-TileColor', content='#1976d2') - meta(name='msapplication-TileImage', content='/_assets/favicons/mstile-150x150.png') - title Wiki.js Setup - - //- Favicon - link(rel='apple-touch-icon', sizes='180x180', href='/_assets/favicons/apple-touch-icon.png') - link(rel='icon', type='image/png', sizes='192x192', href='/_assets/favicons/android-chrome-192x192.png') - link(rel='icon', type='image/png', sizes='32x32', href='/_assets/favicons/favicon-32x32.png') - link(rel='icon', type='image/png', sizes='16x16', href='/_assets/favicons/favicon-16x16.png') - link(rel='mask-icon', href='/_assets/favicons/safari-pinned-tab.svg', color='#1976d2') - link(rel='manifest', href='/_assets/manifest.json') - - //- Site Lang - script. - var siteConfig = !{JSON.stringify({ title: config.title })} - - //- Dev Mode Warning - if devMode - script. - siteConfig.devMode = true - - //- CSS - <% for (var index in htmlWebpackPlugin.files.css) { %> - link( - type='text/css' - rel='stylesheet' - href='<%= htmlWebpackPlugin.files.css[index] %>' - ) - <% } %> - - //- JS - <% for (var index in htmlWebpackPlugin.files.js) { %> - script( - type='text/javascript' - src='<%= htmlWebpackPlugin.files.js[index] %>' - ) - <% } %> - - body - #root - setup(telemetry-id=telemetryClientID, wiki-version=packageObj.version) diff --git a/dev/webpack/webpack.dev.js b/dev/webpack/webpack.dev.js index ed570944..a15e1d44 100644 --- a/dev/webpack/webpack.dev.js +++ b/dev/webpack/webpack.dev.js @@ -24,9 +24,7 @@ fs.emptyDirSync(path.join(process.cwd(), 'assets-legacy')) module.exports = { mode: 'development', entry: { - app: ['./client/index-app.js', 'webpack-hot-middleware/client'], - legacy: ['./client/index-legacy.js', 'webpack-hot-middleware/client'], - setup: ['./client/index-setup.js', 'webpack-hot-middleware/client'] + app: ['./client/index-app.js', 'webpack-hot-middleware/client'] }, output: { path: path.join(process.cwd(), 'assets-legacy'), @@ -197,25 +195,10 @@ module.exports = { ] }), new HtmlWebpackPlugin({ - template: 'dev/templates/master.pug', - filename: '../server/views/master.pug', + template: 'dev/templates/base.pug', + filename: '../server/views/base.pug', hash: false, - inject: false, - excludeChunks: ['setup', 'legacy'] - }), - new HtmlWebpackPlugin({ - template: 'dev/templates/legacy.pug', - filename: '../server/views/legacy/master.pug', - hash: false, - inject: false, - excludeChunks: ['setup', 'app'] - }), - new HtmlWebpackPlugin({ - template: 'dev/templates/setup.pug', - filename: '../server/views/setup.pug', - hash: false, - inject: false, - excludeChunks: ['app', 'legacy'] + inject: false }), new HtmlWebpackPugPlugin(), new WebpackBarPlugin({ diff --git a/dev/webpack/webpack.prod.js b/dev/webpack/webpack.prod.js index f7bc315b..58d6c788 100644 --- a/dev/webpack/webpack.prod.js +++ b/dev/webpack/webpack.prod.js @@ -29,9 +29,7 @@ fs.emptyDirSync(path.join(process.cwd(), 'assets-legacy')) module.exports = { mode: 'production', entry: { - app: './client/index-app.js', - legacy: './client/index-legacy.js', - setup: './client/index-setup.js' + app: './client/index-app.js' }, output: { path: path.join(process.cwd(), 'assets-legacy'), @@ -208,25 +206,10 @@ module.exports = { chunkFilename: 'css/[name].[chunkhash].css' }), new HtmlWebpackPlugin({ - template: 'dev/templates/master.pug', - filename: '../server/views/master.pug', + template: 'dev/templates/base.pug', + filename: '../server/views/base.pug', hash: false, - inject: false, - excludeChunks: ['setup', 'legacy'] - }), - new HtmlWebpackPlugin({ - template: 'dev/templates/legacy.pug', - filename: '../server/views/legacy/master.pug', - hash: false, - inject: false, - excludeChunks: ['setup', 'app'] - }), - new HtmlWebpackPlugin({ - template: 'dev/templates/setup.pug', - filename: '../server/views/setup.pug', - hash: false, - inject: false, - excludeChunks: ['app', 'legacy'] + inject: false }), new HtmlWebpackPugPlugin(), new ScriptExtHtmlWebpackPlugin({ diff --git a/package.json b/package.json index 9bb75bfb..e7d75086 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "scripts": { "start": "node server", "dev": "nodemon server", - "legacy:dev": "node dev", + "legacy:dev": "NODE_OPTIONS=--openssl-legacy-provider node dev", "legacy:build": "NODE_OPTIONS=--openssl-legacy-provider webpack --profile --config dev/webpack/webpack.prod.js", "test": "eslint --format codeframe --ext .js,.vue . && pug-lint server/views && jest", "cypress:open": "cypress open" diff --git a/server/core/kernel.js b/server/core/kernel.js index f2a067b9..cf6903dd 100644 --- a/server/core/kernel.js +++ b/server/core/kernel.js @@ -24,14 +24,13 @@ module.exports = { process.exit(1) } - this.bootMaster() + this.bootWeb() }, /** - * Pre-Master Boot Sequence + * Pre-Web Boot Sequence */ - async preBootMaster() { + async preBootWeb() { try { - await this.initTelemetry() WIKI.sideloader = await require('./sideloader').init() WIKI.cache = require('./cache').init() WIKI.scheduler = require('./scheduler').init() @@ -48,22 +47,22 @@ module.exports = { } }, /** - * Boot Master Process + * Boot Web Process */ - async bootMaster() { + async bootWeb() { try { - await this.preBootMaster() - await require('../master')() - this.postBootMaster() + await this.preBootWeb() + await require('../web')() + this.postBootWeb() } catch (err) { WIKI.logger.error(err) process.exit(1) } }, /** - * Post-Master Boot Sequence + * Post-Web Boot Sequence */ - async postBootMaster() { + async postBootWeb() { await WIKI.models.analytics.refreshProvidersFromDisk() await WIKI.models.authentication.refreshStrategiesFromDisk() await WIKI.models.commentProviders.refreshProvidersFromDisk() @@ -74,30 +73,16 @@ module.exports = { await WIKI.auth.activateStrategies() await WIKI.models.commentProviders.initProvider() + await WIKI.models.sites.reloadCache() await WIKI.models.storage.initTargets() // WIKI.scheduler.start() await WIKI.models.subscribeToNotifications() }, - /** - * Init Telemetry - */ - async initTelemetry() { - require('./telemetry').init() - - process.on('unhandledRejection', (err) => { - WIKI.logger.warn(err) - WIKI.telemetry.sendError(err) - }) - process.on('uncaughtException', (err) => { - WIKI.logger.warn(err) - WIKI.telemetry.sendError(err) - }) - }, /** * Graceful shutdown */ - async shutdown () { + async shutdown (devMode = false) { if (WIKI.servers) { await WIKI.servers.stopServers() } @@ -113,6 +98,8 @@ module.exports = { if (WIKI.asar) { await WIKI.asar.unload() } - process.exit(0) + if (!devMode) { + process.exit(0) + } } } diff --git a/server/core/system.js b/server/core/system.js index c90d436e..2429c802 100644 --- a/server/core/system.js +++ b/server/core/system.js @@ -11,7 +11,7 @@ module.exports = { minimumVersionRequired: '3.0.0-beta.0', minimumNodeRequired: '18.0.0' }, - init() { + init () { // Clear content cache fs.emptyDir(path.resolve(WIKI.ROOTPATH, WIKI.config.dataPath, 'cache')) diff --git a/server/core/telemetry.js b/server/core/telemetry.js deleted file mode 100644 index 5453d693..00000000 --- a/server/core/telemetry.js +++ /dev/null @@ -1,144 +0,0 @@ -const _ = require('lodash') -const { createApolloFetch } = require('apollo-fetch') -const { v4: uuid } = require('uuid') -const os = require('os') -const fs = require('fs-extra') - -/* global WIKI */ - -module.exports = { - enabled: false, - init() { - WIKI.telemetry = this - - if (_.get(WIKI.config, 'telemetry.isEnabled', false) === true && WIKI.config.offline !== true) { - this.enabled = true - this.sendInstanceEvent('STARTUP') - } - }, - sendError(err) { - // TODO - }, - sendEvent(eventCategory, eventAction, eventLabel) { - // TODO - }, - async sendInstanceEvent(eventType) { - if (WIKI.devMode || !this.enabled) { return } - - try { - const apollo = createApolloFetch({ - uri: WIKI.config.graphEndpoint - }) - - // Platform detection - let platform = 'LINUX' - let isDockerized = false - let osname = `${os.type()} ${os.release()}` - switch (os.platform()) { - case 'win32': - platform = 'WINDOWS' - break - case 'darwin': - platform = 'MACOS' - break - default: - platform = 'LINUX' - isDockerized = await fs.pathExists('/.dockerenv') - if (isDockerized) { - osname = 'Docker' - } - break - } - - // DB Version detection - let dbVersion = 'Unknown' - switch (WIKI.config.db.type) { - case 'mariadb': - case 'mysql': - const resultMYSQL = await WIKI.models.knex.raw('SELECT VERSION() as version;') - dbVersion = _.get(resultMYSQL, '[0][0].version', 'Unknown') - break - case 'mssql': - const resultMSSQL = await WIKI.models.knex.raw('SELECT @@VERSION as version;') - dbVersion = _.get(resultMSSQL, '[0].version', 'Unknown') - break - case 'postgres': - dbVersion = _.get(WIKI.models, 'knex.client.version', 'Unknown') - break - case 'sqlite': - dbVersion = _.get(WIKI.models, 'knex.client.driver.VERSION', 'Unknown') - break - } - - let arch = os.arch().toUpperCase() - if (['ARM', 'ARM64', 'X32', 'X64'].indexOf(arch) < 0) { - arch = 'OTHER' - } - - // Send Event - const respStrings = await apollo({ - query: `mutation ( - $version: String! - $platform: TelemetryPlatform! - $os: String! - $architecture: TelemetryArchitecture! - $dbType: TelemetryDBType! - $dbVersion: String! - $nodeVersion: String! - $cpuCores: Int! - $ramMBytes: Int!, - $clientId: String!, - $event: TelemetryInstanceEvent! - ) { - telemetry { - instance( - version: $version - platform: $platform - os: $os - architecture: $architecture - dbType: $dbType - dbVersion: $dbVersion - nodeVersion: $nodeVersion - cpuCores: $cpuCores - ramMBytes: $ramMBytes - clientId: $clientId - event: $event - ) { - responseResult { - succeeded - errorCode - slug - message - } - } - } - }`, - variables: { - version: WIKI.version, - platform, - os: osname, - architecture: arch, - dbType: WIKI.config.db.type.toUpperCase(), - dbVersion, - nodeVersion: process.version.substr(1), - cpuCores: os.cpus().length, - ramMBytes: Math.round(os.totalmem() / 1024 / 1024), - clientId: WIKI.config.telemetry.clientId, - event: eventType - } - }) - const telemetryResponse = _.get(respStrings, 'data.telemetry.instance.responseResult', { succeeded: false, message: 'Unexpected Error' }) - if (!telemetryResponse.succeeded) { - WIKI.logger.warn('Failed to send instance telemetry: ' + telemetryResponse.message) - } else { - WIKI.logger.info('Telemetry is active: [ OK ]') - } - } catch (err) { - WIKI.logger.warn(err) - } - }, - generateClientId() { - _.set(WIKI.config, 'telemetry.clientId', uuid()) - return WIKI.config.telemetry.clientId - } -} diff --git a/server/graph/resolvers/storage.js b/server/graph/resolvers/storage.js index 1f659835..ec5f4d08 100644 --- a/server/graph/resolvers/storage.js +++ b/server/graph/resolvers/storage.js @@ -32,6 +32,7 @@ module.exports = { // }), ['title', 'key']) return _.sortBy(WIKI.storage.defs.map(md => { const dbTarget = dbTargets.find(tg => tg.module === md.key) + console.info(md.actions) return { id: dbTarget?.id ?? uuid(), isEnabled: dbTarget?.isEnabled ?? false, @@ -62,12 +63,12 @@ module.exports = { setup: { handler: md?.setup?.handler, state: dbTarget?.state?.setup ?? 'notconfigured', - values: md.setup?.handler - ? _.transform(md.setup.defaultValues, + values: md.setup?.handler ? + _.transform(md.setup.defaultValues, (r, v, k) => { r[k] = dbTarget?.config?.[k] ?? v - }, {}) - : {} + }, {}) : + {} }, config: _.transform(md.props, (r, v, k) => { const cfValue = dbTarget?.config?.[k] ?? v.default diff --git a/server/graph/schemas/authentication.graphql b/server/graph/schemas/authentication.graphql index 8834899f..d32a0853 100644 --- a/server/graph/schemas/authentication.graphql +++ b/server/graph/schemas/authentication.graphql @@ -8,6 +8,7 @@ extend type Query { apiState: Boolean authStrategies( + siteId: UUID enabledOnly: Boolean ): [AuthenticationStrategy] } diff --git a/server/index.js b/server/index.js index 8588963c..96af8921 100644 --- a/server/index.js +++ b/server/index.js @@ -22,6 +22,8 @@ let WIKI = { Error: require('./helpers/error'), configSvc: require('./core/config'), kernel: require('./core/kernel'), + sites: {}, + sitesMappings: {}, startedAt: DateTime.utc(), storage: { defs: [], diff --git a/server/models/sites.js b/server/models/sites.js index 329c3a5f..b0c5b5a9 100644 --- a/server/models/sites.js +++ b/server/models/sites.js @@ -28,6 +28,28 @@ module.exports = class Site extends Model { return ['config'] } + static async getSiteByHostname ({ hostname, forceReload = false }) { + if (forceReload) { + await WIKI.models.sites.reloadCache() + } + const siteId = WIKI.sitesMappings[hostname] || WIKI.sitesMappings['*'] + if (siteId) { + return WIKI.sites[siteId] + } + return null + } + + static async reloadCache () { + WIKI.logger.info('Reloading site configurations...') + const sites = await WIKI.models.sites.query().orderBy('id') + WIKI.sites = _.keyBy(sites, 'id') + WIKI.sitesMappings = {} + for (const site of sites) { + WIKI.sitesMappings[site.hostname] = site.id + } + WIKI.logger.info(`Loaded ${sites.length} site configurations [ OK ]`) + } + static async createSite (hostname, config) { const newSite = await WIKI.models.sites.query().insertAndFetch({ hostname, diff --git a/server/setup.js b/server/setup.js deleted file mode 100644 index 6d87a29f..00000000 --- a/server/setup.js +++ /dev/null @@ -1,450 +0,0 @@ -const path = require('path') -const { v4: uuid } = require('uuid') -const bodyParser = require('body-parser') -const compression = require('compression') -const express = require('express') -const favicon = require('serve-favicon') -const http = require('http') -const Promise = require('bluebird') -const fs = require('fs-extra') -const _ = require('lodash') -const crypto = Promise.promisifyAll(require('crypto')) -const pem2jwk = require('pem-jwk').pem2jwk -const semver = require('semver') - -/* global WIKI */ - -module.exports = () => { - WIKI.config.site = { - path: '', - title: 'Wiki.js' - } - - WIKI.system = require('./core/system') - - // ---------------------------------------- - // Define Express App - // ---------------------------------------- - - let app = express() - app.use(compression()) - - // ---------------------------------------- - // Public Assets - // ---------------------------------------- - - app.use(favicon(path.join(WIKI.ROOTPATH, 'assets', 'favicon.ico'))) - app.use('/_assets', express.static(path.join(WIKI.ROOTPATH, 'assets'))) - - // ---------------------------------------- - // View Engine Setup - // ---------------------------------------- - - app.set('views', path.join(WIKI.SERVERPATH, 'views')) - app.set('view engine', 'pug') - - app.use(bodyParser.json()) - app.use(bodyParser.urlencoded({ extended: false })) - - app.locals.config = WIKI.config - app.locals.data = WIKI.data - app.locals._ = require('lodash') - app.locals.devMode = WIKI.devMode - - // ---------------------------------------- - // HMR (Dev Mode Only) - // ---------------------------------------- - - if (global.DEV) { - app.use(global.WP_DEV.devMiddleware) - app.use(global.WP_DEV.hotMiddleware) - } - - // ---------------------------------------- - // Controllers - // ---------------------------------------- - - app.get('*', async (req, res) => { - let packageObj = await fs.readJson(path.join(WIKI.ROOTPATH, 'package.json')) - res.render('setup', { packageObj }) - }) - - /** - * Finalize - */ - app.post('/finalize', async (req, res) => { - try { - // Set config - _.set(WIKI.config, 'auth', { - audience: 'urn:wiki.js', - tokenExpiration: '30m', - tokenRenewal: '14d' - }) - _.set(WIKI.config, 'company', '') - _.set(WIKI.config, 'features', { - featurePageRatings: true, - featurePageComments: true, - featurePersonalWikis: true - }) - _.set(WIKI.config, 'graphEndpoint', 'https://graph.requarks.io') - _.set(WIKI.config, 'host', req.body.siteUrl) - _.set(WIKI.config, 'lang', { - code: 'en', - autoUpdate: true, - namespacing: false, - namespaces: [] - }) - _.set(WIKI.config, 'logo', { - hasLogo: false, - logoIsSquare: false - }) - _.set(WIKI.config, 'mail', { - senderName: '', - senderEmail: '', - host: '', - port: 465, - secure: true, - verifySSL: true, - user: '', - pass: '', - useDKIM: false, - dkimDomainName: '', - dkimKeySelector: '', - dkimPrivateKey: '' - }) - _.set(WIKI.config, 'seo', { - description: '', - robots: ['index', 'follow'], - analyticsService: '', - analyticsId: '' - }) - _.set(WIKI.config, 'sessionSecret', (await crypto.randomBytesAsync(32)).toString('hex')) - _.set(WIKI.config, 'telemetry', { - isEnabled: req.body.telemetry === true, - clientId: uuid() - }) - _.set(WIKI.config, 'theming', { - theme: 'default', - darkMode: false, - iconset: 'mdi', - injectCSS: '', - injectHead: '', - injectBody: '' - }) - _.set(WIKI.config, 'title', 'Wiki.js') - - // Init Telemetry - WIKI.kernel.initTelemetry() - // WIKI.telemetry.sendEvent('setup', 'install-start') - - // Basic checks - if (!semver.satisfies(process.version, '>=10.12')) { - throw new Error('Node.js 10.12.x or later required!') - } - - // Create directory structure - WIKI.logger.info('Creating data directories...') - await fs.ensureDir(path.resolve(WIKI.ROOTPATH, WIKI.config.dataPath)) - await fs.emptyDir(path.resolve(WIKI.ROOTPATH, WIKI.config.dataPath, 'cache')) - await fs.ensureDir(path.resolve(WIKI.ROOTPATH, WIKI.config.dataPath, 'uploads')) - - // Generate certificates - WIKI.logger.info('Generating certificates...') - const certs = crypto.generateKeyPairSync('rsa', { - modulusLength: 2048, - publicKeyEncoding: { - type: 'pkcs1', - format: 'pem' - }, - privateKeyEncoding: { - type: 'pkcs1', - format: 'pem', - cipher: 'aes-256-cbc', - passphrase: WIKI.config.sessionSecret - } - }) - - _.set(WIKI.config, 'certs', { - jwk: pem2jwk(certs.publicKey), - public: certs.publicKey, - private: certs.privateKey - }) - - // Save config to DB - WIKI.logger.info('Persisting config to DB...') - await WIKI.configSvc.saveToDb([ - 'auth', - 'certs', - 'company', - 'features', - 'graphEndpoint', - 'host', - 'lang', - 'logo', - 'mail', - 'seo', - 'sessionSecret', - 'telemetry', - 'theming', - 'uploads', - 'title' - ], false) - - // Truncate tables (reset from previous failed install) - await WIKI.models.locales.query().where('code', '!=', 'x').del() - await WIKI.models.navigation.query().truncate() - switch (WIKI.config.db.type) { - case 'postgres': - await WIKI.models.knex.raw('TRUNCATE groups, users CASCADE') - break - case 'mysql': - case 'mariadb': - await WIKI.models.groups.query().where('id', '>', 0).del() - await WIKI.models.users.query().where('id', '>', 0).del() - await WIKI.models.knex.raw('ALTER TABLE `groups` AUTO_INCREMENT = 1') - await WIKI.models.knex.raw('ALTER TABLE `users` AUTO_INCREMENT = 1') - break - case 'mssql': - await WIKI.models.groups.query().del() - await WIKI.models.users.query().del() - await WIKI.models.knex.raw(` - IF EXISTS (SELECT * FROM sys.identity_columns WHERE OBJECT_NAME(OBJECT_ID) = 'groups' AND last_value IS NOT NULL) - DBCC CHECKIDENT ([groups], RESEED, 0) - `) - await WIKI.models.knex.raw(` - IF EXISTS (SELECT * FROM sys.identity_columns WHERE OBJECT_NAME(OBJECT_ID) = 'users' AND last_value IS NOT NULL) - DBCC CHECKIDENT ([users], RESEED, 0) - `) - break - case 'sqlite': - await WIKI.models.groups.query().truncate() - await WIKI.models.users.query().truncate() - break - } - - // Create default locale - WIKI.logger.info('Installing default locale...') - await WIKI.models.locales.query().insert({ - code: 'en', - strings: {}, - isRTL: false, - name: 'English', - nativeName: 'English' - }) - - // Create default groups - - WIKI.logger.info('Creating default groups...') - const adminGroup = await WIKI.models.groups.query().insert({ - name: 'Administrators', - permissions: JSON.stringify(['manage:system']), - pageRules: JSON.stringify([]), - isSystem: true - }) - const guestGroup = await WIKI.models.groups.query().insert({ - name: 'Guests', - permissions: JSON.stringify(['read:pages', 'read:assets', 'read:comments']), - pageRules: JSON.stringify([ - { id: 'guest', roles: ['read:pages', 'read:assets', 'read:comments'], match: 'START', deny: false, path: '', locales: [] } - ]), - isSystem: true - }) - if (adminGroup.id !== 1 || guestGroup.id !== 2) { - throw new Error('Incorrect groups auto-increment configuration! Should start at 0 and increment by 1. Contact your database administrator.') - } - - // Load local authentication strategy - await WIKI.models.authentication.query().insert({ - key: 'local', - config: {}, - selfRegistration: false, - isEnabled: true, - domainWhitelist: {v: []}, - autoEnrollGroups: {v: []}, - order: 0, - strategyKey: 'local', - displayName: 'Local' - }) - - // Load editors + enable default - await WIKI.models.editors.refreshEditorsFromDisk() - await WIKI.models.editors.query().patch({ isEnabled: true }).where('key', 'markdown') - - // Load loggers - await WIKI.models.loggers.refreshLoggersFromDisk() - - // Load renderers - await WIKI.models.renderers.refreshRenderersFromDisk() - - // Load search engines + enable default - await WIKI.models.searchEngines.refreshSearchEnginesFromDisk() - await WIKI.models.searchEngines.query().patch({ isEnabled: true }).where('key', 'db') - - // WIKI.telemetry.sendEvent('setup', 'install-loadedmodules') - - // Load storage targets - await WIKI.models.storage.refreshTargetsFromDisk() - - // Create root administrator - WIKI.logger.info('Creating root administrator...') - const adminUser = await WIKI.models.users.query().insert({ - email: req.body.adminEmail.toLowerCase(), - provider: 'local', - password: req.body.adminPassword, - name: 'Administrator', - locale: 'en', - defaultEditor: 'markdown', - tfaIsActive: false, - isActive: true, - isVerified: true - }) - await adminUser.$relatedQuery('groups').relate(adminGroup.id) - - // Create Guest account - WIKI.logger.info('Creating guest account...') - const guestUser = await WIKI.models.users.query().insert({ - provider: 'local', - email: 'guest@example.com', - name: 'Guest', - password: '', - locale: 'en', - defaultEditor: 'markdown', - tfaIsActive: false, - isSystem: true, - isActive: true, - isVerified: true - }) - await guestUser.$relatedQuery('groups').relate(guestGroup.id) - if (adminUser.id !== 1 || guestUser.id !== 2) { - throw new Error('Incorrect users auto-increment configuration! Should start at 0 and increment by 1. Contact your database administrator.') - } - - // Create site nav - - WIKI.logger.info('Creating default site navigation') - await WIKI.models.navigation.query().insert({ - key: 'site', - config: [ - { - locale: 'en', - items: [ - { - id: uuid(), - icon: 'mdi-home', - kind: 'link', - label: 'Home', - target: '/', - targetType: 'home', - visibilityMode: 'all', - visibilityGroups: null - } - ] - } - ] - }) - - WIKI.logger.info('Setup is complete!') - // WIKI.telemetry.sendEvent('setup', 'install-completed') - res.json({ - ok: true, - redirectPath: '/', - redirectPort: WIKI.config.port - }).end() - - if (WIKI.config.telemetry.isEnabled) { - await WIKI.telemetry.sendInstanceEvent('INSTALL') - } - - WIKI.config.setup = false - - WIKI.logger.info('Stopping Setup...') - WIKI.server.destroy(() => { - WIKI.logger.info('Setup stopped. Starting Wiki.js...') - _.delay(() => { - WIKI.kernel.bootMaster() - }, 1000) - }) - } catch (err) { - try { - await WIKI.models.knex('settings').truncate() - } catch (err) {} - WIKI.telemetry.sendError(err) - res.json({ ok: false, error: err.message }) - } - }) - - // ---------------------------------------- - // Error handling - // ---------------------------------------- - - app.use(function (req, res, next) { - const err = new Error('Not Found') - err.status = 404 - next(err) - }) - - app.use(function (err, req, res, next) { - res.status(err.status || 500) - res.send({ - message: err.message, - error: WIKI.IS_DEBUG ? err : {} - }) - WIKI.logger.error(err.message) - WIKI.telemetry.sendError(err) - }) - - // ---------------------------------------- - // Start HTTP server - // ---------------------------------------- - - WIKI.logger.info(`Starting HTTP server on port ${WIKI.config.port}...`) - - app.set('port', WIKI.config.port) - - WIKI.logger.info(`HTTP Server on port: [ ${WIKI.config.port} ]`) - WIKI.server = http.createServer(app) - WIKI.server.listen(WIKI.config.port, WIKI.config.bindIP) - - var openConnections = [] - - WIKI.server.on('connection', (conn) => { - let key = conn.remoteAddress + ':' + conn.remotePort - openConnections[key] = conn - conn.on('close', () => { - openConnections.splice(key, 1) - }) - }) - - WIKI.server.destroy = (cb) => { - WIKI.server.close(cb) - for (let key in openConnections) { - openConnections[key].destroy() - } - } - - WIKI.server.on('error', (error) => { - if (error.syscall !== 'listen') { - throw error - } - - switch (error.code) { - case 'EACCES': - WIKI.logger.error('Listening on port ' + WIKI.config.port + ' requires elevated privileges!') - return process.exit(1) - case 'EADDRINUSE': - WIKI.logger.error('Port ' + WIKI.config.port + ' is already in use!') - return process.exit(1) - default: - throw error - } - }) - - WIKI.server.on('listening', () => { - WIKI.logger.info('HTTP Server: [ RUNNING ]') - WIKI.logger.info('π»π»π»π»π»π»π»π»π»π»π»π»π»π»π»π»π»π»π»π»π»π»π»π»π»π»π»π»π»') - WIKI.logger.info('') - WIKI.logger.info(`Browse to http://YOUR-SERVER-IP:${WIKI.config.port}/ to complete setup!`) - WIKI.logger.info('') - WIKI.logger.info('πΊπΊπΊπΊπΊπΊπΊπΊπΊπΊπΊπΊπΊπΊπΊπΊπΊπΊπΊπΊπΊπΊπΊπΊπΊπΊπΊπΊπΊ') - }) -} diff --git a/server/themes/default/theme.yml b/server/themes/default/theme.yml deleted file mode 100644 index 42a9e274..00000000 --- a/server/themes/default/theme.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: Default -author: requarks.io -site: https://wiki.requarks.io/ -version: 1.0.0 -requirements: - minimum: '>= 2.0.0' - maximum: '< 3.0.0' -props: - accentColor: - type: String - title: Accent Color - hint: Color used in the sidebar navigation and other elements. - order: 1 - default: blue darken-2 - control: color-material - tocPosition: - type: String - title: Table of Contents Position - hint: Select whether the table of contents is shown on the left, right or not at all. - order: 2 - default: left - enum: - - left - - right - - hidden diff --git a/server/themes/default/thumbnail.png b/server/themes/default/thumbnail.png deleted file mode 100644 index 489e3f83..00000000 Binary files a/server/themes/default/thumbnail.png and /dev/null differ diff --git a/server/views/admin.pug b/server/views/admin.pug index 3434fdf3..487740cd 100644 --- a/server/views/admin.pug +++ b/server/views/admin.pug @@ -1,4 +1,4 @@ -extends master.pug +extends base.pug block body #root diff --git a/dev/templates/legacy.pug b/server/views/base.pug similarity index 80% rename from dev/templates/legacy.pug rename to server/views/base.pug index 14f9d489..b5d2dd8c 100644 --- a/dev/templates/legacy.pug +++ b/server/views/base.pug @@ -1,5 +1,5 @@ doctype html -html +html(lang=siteConfig.lang) head meta(http-equiv='X-UA-Compatible', content='IE=edge') meta(charset='UTF-8') @@ -21,12 +21,23 @@ html //- Favicon link(rel='apple-touch-icon', sizes='180x180', href='/_assets/favicons/apple-touch-icon.png') - link(rel='icon', type='image/png', sizes='192x192', href='/_assets/favicons/android-icon-192x192.png') + link(rel='icon', type='image/png', sizes='192x192', href='/_assets/favicons/android-chrome-192x192.png') link(rel='icon', type='image/png', sizes='32x32', href='/_assets/favicons/favicon-32x32.png') link(rel='icon', type='image/png', sizes='16x16', href='/_assets/favicons/favicon-16x16.png') link(rel='mask-icon', href='/_assets/favicons/safari-pinned-tab.svg', color='#1976d2') link(rel='manifest', href='/_assets/manifest.json') + //- Site Properties + script. + var siteId = "!{siteId}" + var siteConfig = !{JSON.stringify(siteConfig)} + var siteLangs = !{JSON.stringify(langs)} + + //- Dev Mode Warning + if devMode + script. + siteConfig.devMode = true + //- Icon Set if config.theming.iconset === 'fa' link( @@ -42,26 +53,24 @@ html ) //- CSS - <% for (var index in htmlWebpackPlugin.files.css) { %> - link( - type='text/css' - rel='stylesheet' - href='<%= htmlWebpackPlugin.files.css[index] %>' - ) - <% } %> - - script( - crossorigin='anonymous' - src='https://polyfill.io/v3/polyfill.min.js?features=EventSource' - ) + //- JS - <% for (var index in htmlWebpackPlugin.files.js) { %> + + + script( + type='text/javascript' + src='/_assets-legacy/js/runtime.js' + ) + + + script( type='text/javascript' - src='<%= htmlWebpackPlugin.files.js[index] %>' + src='/_assets-legacy/js/app.js' ) - <% } %> + + != analyticsCode.head diff --git a/server/views/editor.pug b/server/views/editor.pug index 0f0b64c0..b395cbec 100644 --- a/server/views/editor.pug +++ b/server/views/editor.pug @@ -1,4 +1,4 @@ -extends master.pug +extends base.pug block head if injectCode.css diff --git a/server/views/error.pug b/server/views/error.pug index acc8e280..27d45321 100644 --- a/server/views/error.pug +++ b/server/views/error.pug @@ -1,4 +1,4 @@ -extends master.pug +extends base.pug block body #root.is-fullscreen diff --git a/server/views/history.pug b/server/views/history.pug index 5adb9c57..02384329 100644 --- a/server/views/history.pug +++ b/server/views/history.pug @@ -1,4 +1,4 @@ -extends master.pug +extends base.pug block head diff --git a/server/views/legacy/login.pug b/server/views/legacy/login.pug deleted file mode 100644 index cd519561..00000000 --- a/server/views/legacy/login.pug +++ /dev/null @@ -1,23 +0,0 @@ -extends master.pug - -block body - #root - .login-deprecated!= t('outdatedBrowserWarning', { modernBrowser: '' + t('modernBrowser') + '', interpolation: { escapeValue: false } }) - .login - .login-dialog - if err - .login-error= err.message - form(method='post', action='/login') - h1= config.title - select(name='strategy') - each str in formStrategies - option(value=str.key, selected)= str.title - input(type='text', name='user', placeholder=t('auth:fields.emailUser')) - input(type='password', name='pass', placeholder=t('auth:fields.password')) - button(type='submit')= t('auth:actions.login') - if socialStrategies.length - .login-social - h2= t('auth:orLoginUsingStrategy') - each str in socialStrategies - a.login-social-icon(href='/login/' + str.key, class=str.color) - != str.icon diff --git a/server/views/legacy/page.pug b/server/views/legacy/page.pug deleted file mode 100644 index 48e8ad5e..00000000 --- a/server/views/legacy/page.pug +++ /dev/null @@ -1,60 +0,0 @@ -extends master.pug - -block head - if injectCode.css - style(type='text/css')!= injectCode.css - if injectCode.head - != injectCode.head - -block body - #root - .header - span.header-title= siteConfig.title - span.header-deprecated!= t('outdatedBrowserWarning', { modernBrowser: '' + t('modernBrowser') + '', interpolation: { escapeValue: false } }) - span.header-login - if !isAuthenticated - a(href='/login', title='Login') - i.mdi.mdi-account-circle - else - a(href='/logout', title='Logout') - i.mdi.mdi-logout - .main - .sidebar - each navItem in sidebar - if navItem.k === 'link' - a.sidebar-link(href=navItem.t) - i.mdi(class=navItem.c) - span= navItem.l - else if navItem.k === 'divider' - .sidebar-divider - else if navItem.k === 'header' - .sidebar-title= navItem.l - .main-container - .page-header - .page-header-left - h1= page.title - h2= page.description - //- .page-header-right - //- .page-header-right-title Last edited by - //- .page-header-right-author= page.authorName - //- .page-header-right-updated= page.updatedAt - .page-contents.v-content - .contents - div!= page.render - if page.toc.length - .toc - .toc-title= t('page.toc') - each tocItem, tocIdx in page.toc - a.toc-tile(href=tocItem.anchor) - i.mdi.mdi-chevron-right - span= tocItem.title - if tocIdx < page.toc.length - 1 || tocItem.children.length - .toc-divider - each tocSubItem in tocItem.children - a.toc-tile.inset(href=tocSubItem.anchor) - i.mdi.mdi-chevron-right - span= tocSubItem.title - if tocIdx < page.toc.length - 1 - .toc-divider.inset - if injectCode.body - != injectCode.body diff --git a/server/views/login.pug b/server/views/login.pug index c0408cd9..80cc7395 100644 --- a/server/views/login.pug +++ b/server/views/login.pug @@ -1,4 +1,4 @@ -extends master.pug +extends base.pug block body #root.is-fullscreen diff --git a/server/views/new.pug b/server/views/new.pug index 79080d20..f1487b34 100644 --- a/server/views/new.pug +++ b/server/views/new.pug @@ -1,4 +1,4 @@ -extends master.pug +extends base.pug block body #root.is-fullscreen diff --git a/server/views/notfound.pug b/server/views/notfound.pug index d0d5d66e..f678c4dd 100644 --- a/server/views/notfound.pug +++ b/server/views/notfound.pug @@ -1,4 +1,4 @@ -extends master.pug +extends base.pug block body #root.is-fullscreen diff --git a/server/views/page.pug b/server/views/page.pug index cc19fbae..4cfd3eba 100644 --- a/server/views/page.pug +++ b/server/views/page.pug @@ -1,4 +1,4 @@ -extends master.pug +extends base.pug block head if injectCode.css diff --git a/server/views/profile.pug b/server/views/profile.pug index 084ae408..f0dd2560 100644 --- a/server/views/profile.pug +++ b/server/views/profile.pug @@ -1,4 +1,4 @@ -extends master.pug +extends base.pug block body #root diff --git a/server/views/register.pug b/server/views/register.pug index 952885f8..a02e2c2e 100644 --- a/server/views/register.pug +++ b/server/views/register.pug @@ -1,4 +1,4 @@ -extends master.pug +extends base.pug block body #root.is-fullscreen diff --git a/server/views/source.pug b/server/views/source.pug index c3cb1e95..59e9e6aa 100644 --- a/server/views/source.pug +++ b/server/views/source.pug @@ -1,4 +1,4 @@ -extends master.pug +extends base.pug block head diff --git a/server/views/tags.pug b/server/views/tags.pug index 6443f0b4..f2f49f8d 100644 --- a/server/views/tags.pug +++ b/server/views/tags.pug @@ -1,4 +1,4 @@ -extends master.pug +extends base.pug block body #root diff --git a/server/views/unauthorized.pug b/server/views/unauthorized.pug index 3a36ec69..02e5138e 100644 --- a/server/views/unauthorized.pug +++ b/server/views/unauthorized.pug @@ -1,4 +1,4 @@ -extends master.pug +extends base.pug block body #root.is-fullscreen diff --git a/server/views/welcome.pug b/server/views/welcome.pug index 3be66e23..56b7693d 100644 --- a/server/views/welcome.pug +++ b/server/views/welcome.pug @@ -1,4 +1,4 @@ -extends master.pug +extends base.pug block body #root.is-fullscreen diff --git a/server/master.js b/server/web.js similarity index 91% rename from server/master.js rename to server/web.js index 7c6fd342..ba88ef9d 100644 --- a/server/master.js +++ b/server/web.js @@ -149,15 +149,20 @@ module.exports = async () => { // ---------------------------------------- app.use(async (req, res, next) => { + const currentSite = await WIKI.models.sites.getSiteByHostname({ hostname: req.hostname }) + if (!currentSite) { + return res.status(404).send('Site Not Found') + } + res.locals.siteConfig = { - title: WIKI.config.title, - theme: WIKI.config.theming.theme, - darkMode: WIKI.config.theming.darkMode, - lang: WIKI.config.lang.code, - rtl: WIKI.config.lang.rtl, - company: WIKI.config.company, - contentLicense: WIKI.config.contentLicense, - logoUrl: WIKI.config.logoUrl + id: currentSite.id, + title: currentSite.config.title, + darkMode: currentSite.config.theme.dark, + lang: currentSite.config.locale, + rtl: false, // TODO: handle RTL + company: currentSite.config.company, + contentLicense: currentSite.config.contentLicense, + logoUrl: currentSite.config.logoUrl } res.locals.langs = await WIKI.models.locales.getNavLocales({ cache: true }) res.locals.analyticsCode = await WIKI.models.analytics.getCode({ cache: true }) diff --git a/ux/.eslintrc.js b/ux/.eslintrc.js index 037260f2..e6f432a8 100644 --- a/ux/.eslintrc.js +++ b/ux/.eslintrc.js @@ -68,6 +68,7 @@ module.exports = { 'prefer-promise-reject-errors': 'off', 'no-unused-vars': 'off', + 'vue/multi-word-component-names': 'off', // allow debugger during development only 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' diff --git a/ux/index.html b/ux/index.html index ac7a142b..684144bb 100644 --- a/ux/index.html +++ b/ux/index.html @@ -8,6 +8,9 @@