diff --git a/middleware/setup.js b/middleware/setup.js index 350bede9..2847d234 100644 --- a/middleware/setup.js +++ b/middleware/setup.js @@ -1,9 +1,14 @@ -export default function ({ req, redirect, route }) { +export default async function ({ $config, req, redirect, route, error }) { if (process.server) { - if (req.firstrun && route.path !== '/setup') { - return redirect('/setup') + if (req.status === 'SETUP' && route.path !== '/setup/0') { + return redirect('/setup/0') } - if (!req.firstrun && route.path === '/setup') { + + if (req.status === 'DBCONF' && route.path !== '/setup/1') { + return redirect('/setup/1') + } + + if (req.status === 'READY' && route.path.startsWith('/setup')) { return redirect('/') } } diff --git a/nuxt.config.js b/nuxt.config.js index 54a86ff4..032b7248 100644 --- a/nuxt.config.js +++ b/nuxt.config.js @@ -20,7 +20,7 @@ module.exports = { vue: { config: { - ignoredElements: ['gancio-events'] + ignoredElements: ['gancio-events', 'gancio-event'] } }, diff --git a/package.json b/package.json index 661e2fa2..7fa0610b 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "linkify-html": "^3.0.4", "linkifyjs": "3.0.4", "lodash": "^4.17.21", + "mariadb": "^2.5.5", "microformat-node": "^2.0.1", "mkdirp": "^1.0.4", "multer": "^1.4.3", diff --git a/pages/setup/DbStep.vue b/pages/setup/DbStep.vue index 5fd6517f..38eee780 100644 --- a/pages/setup/DbStep.vue +++ b/pages/setup/DbStep.vue @@ -24,6 +24,7 @@ export default { data () { return { db: { + dialect: 'sqlite', storage: './gancio.sqlite', host: 'localhost', database: 'gancio' diff --git a/pages/setup/index.vue b/pages/setup/_db.vue similarity index 83% rename from pages/setup/index.vue rename to pages/setup/_db.vue index fa936a5e..e23e789a 100644 --- a/pages/setup/index.vue +++ b/pages/setup/_db.vue @@ -4,14 +4,14 @@ h2.mb-2.text-center Gancio Setup v-stepper.grey.lighten-5(v-model='step') v-stepper-header - v-stepper-step(:complete='step > 1' step='1') Database - v-divider + v-stepper-step(v-show='!dbdone' :complete='step > 1' step='1') Database + v-divider(v-show='!dbdone') v-stepper-step(:complete='step > 2' step='2') Configuration v-divider v-stepper-step(:complete='step > 3' step='3') Finish v-stepper-items - v-stepper-content(step='1') + v-stepper-content(v-show='!dbdone' step='1') DbStep(@complete='dbCompleted') v-stepper-content(step='2') Settings(setup, @complete='configCompleted') @@ -36,14 +36,16 @@ export default { title: 'Setup', }, auth: false, - data () { + asyncData ({ params }) { + return { + dbdone: !!Number(params.db), config: { db: { dialect: '' } }, - step: 1 + step: 1 + Number(params.db) } }, methods: { diff --git a/server/api/controller/settings.js b/server/api/controller/settings.js index e4cdea64..7d6a23d3 100644 --- a/server/api/controller/settings.js +++ b/server/api/controller/settings.js @@ -54,7 +54,7 @@ const settingsController = { secretSettings: {}, async load () { - if (config.firstrun) { + if (config.status !== 'READY') { settingsController.settings = defaultSettings return } diff --git a/server/api/controller/setup.js b/server/api/controller/setup.js index ff00b7fb..011d1fb8 100644 --- a/server/api/controller/setup.js +++ b/server/api/controller/setup.js @@ -8,49 +8,59 @@ const path = require('path') const setupController = { - async setupDb (req, res, next) { + async _setupDb (dbConf) { + + if (!dbConf) { + throw Error('Empty DB configuration') + } + + if (dbConf.dialect === 'sqlite' && dbConf.storage) { + dbConf.storage = path.resolve(process.env.cwd || '', dbConf.storage) + } else { + dbConf.storage = '' + } + + // try to connect + dbConf.logging = false + await db.connect(dbConf) + + // is empty ? + const isEmpty = await db.isEmpty() + if (!isEmpty) { + log.warn(' ⚠ Non empty db! Please move your current db elsewhere than retry.') + throw Error(' ⚠ Non empty db! Please move your current db elsewhere than retry.') + } + + await db.runMigrations() + + config.db = dbConf + config.status = 'DBCONF' + config.db.logging = false + + const settingsController = require('./settings') + await settingsController.load() + }, + + async setupDb (req, res) { log.debug('[SETUP] Check db') const dbConf = req.body.db - if (!dbConf) { - return res.sendStatus(400) - } - - if (dbConf.storage) { - dbConf.storage = path.resolve(process.env.cwd || '', dbConf.storage) - } try { - // try to connect - dbConf.logging = false - await db.connect(dbConf) - - // is empty ? - const isEmpty = await db.isEmpty() - if (!isEmpty) { - log.warn(' ⚠ Non empty db! Please move your current db elsewhere than retry.') - return res.status(400).send(' ⚠ Non empty db! Please move your current db elsewhere than retry.') - } - - await db.runMigrations() - - config.db = dbConf - config.firstrun = false - config.db.logging = false - config.baseurl = req.protocol + '://' + req.headers.host - config.hostname = new URL.URL(config.baseurl).hostname - - const settingsController = require('./settings') - await settingsController.load() - return res.sendStatus(200) + await setupController._setupDb(dbConf) } catch (e) { return res.status(400).send(String(e)) } + + return res.sendStatus(200) }, async restart (req, res) { try { + config.baseurl = req.protocol + '://' + req.headers.host + config.hostname = new URL.URL(config.baseurl).hostname + // write configuration config.write() @@ -72,8 +82,9 @@ const setupController = { log.info('Restart needed') res.end() + // exit process so pm2 || docker could restart me || service - process.kill(process.pid) + setTimeout(() => process.kill(process.pid), 1000) } catch (e) { log.error(String(e)) diff --git a/server/api/index.js b/server/api/index.js index 5294971a..75698dbd 100644 --- a/server/api/index.js +++ b/server/api/index.js @@ -10,7 +10,7 @@ api.use(express.urlencoded({ extended: false })) api.use(express.json()) -if (config.firstrun) { +if (config.status !== 'READY') { const setupController = require('./controller/setup') const settingsController = require('./controller/settings') diff --git a/server/api/models/index.js b/server/api/models/index.js index 1e996ee8..4ee532d5 100644 --- a/server/api/models/index.js +++ b/server/api/models/index.js @@ -22,7 +22,7 @@ const db = { return !(users && users.length) }, async runMigrations () { - const logging = config.firstrun ? false : log.debug.bind(log) + const logging = config.status !== 'READY' ? false : log.debug.bind(log) const umzug = new Umzug({ storage: 'sequelize', storageOptions: { sequelize: db.sequelize }, @@ -41,7 +41,7 @@ const db = { return await umzug.up() }, async initialize () { - if (!config.firstrun) { + if (config.status === 'READY') { try { await db.connect() log.debug('Running migrations') diff --git a/server/config.js b/server/config.js index 18930e1a..4827c306 100644 --- a/server/config.js +++ b/server/config.js @@ -3,7 +3,7 @@ const path = require('path') const URL = require('url') let config = { - firstrun: true, + status: 'SETUP', baseurl: '', hostname: '', server: { @@ -15,7 +15,7 @@ let config = { db: {}, upload_path: path.resolve(process.env.cwd || '', 'uploads'), write (config_path= process.env.config_path || './config.json') { - delete config.firstrun + delete config.status return fs.writeFileSync(config_path, JSON.stringify(config, null, 2)) }, @@ -26,12 +26,12 @@ let config = { if (fs.existsSync(config_path)) { const configContent = fs.readFileSync(config_path) config = Object.assign(config, JSON.parse(configContent)) - config.firstrun = false + config.status = 'READY' if (!config.hostname) { config.hostname = new URL.URL(config.baseurl).hostname } } else { - config.firstrun = true + config.status = 'SETUP' console.info('> Configuration file does not exists, running setup..') } } diff --git a/server/initialize.server.js b/server/initialize.server.js index aee88569..53124294 100644 --- a/server/initialize.server.js +++ b/server/initialize.server.js @@ -1,9 +1,6 @@ export default async function () { - const db = require('./api/models/index') - await db.initialize() async function start (nuxt) { - const log = require('../server/log') const config = require('../server/config') const settingsController = require('./api/controller/settings') @@ -14,7 +11,7 @@ export default async function () { dayjs.tz.setDefault(settingsController.settings.instance_timezone) let TaskManager - if (!config.firstrun) { + if (config.status === 'READY') { TaskManager = require('../server/taskManager').TaskManager TaskManager.start() } diff --git a/server/routes.js b/server/routes.js index b34296fa..3035c4c5 100644 --- a/server/routes.js +++ b/server/routes.js @@ -6,6 +6,28 @@ const cookieParser = require('cookie-parser') // const metricsMiddleware = promBundle({ includeMethod: true }) const config = require('./config') + +if (config.status == 'READY') { + const db = require('./api/models/index') + db.initialize() +} else { + if (process.env.GANCIO_DB_DIALECT) { + const setupController = require('./api/controller/setup') + const dbConf = { + dialect: process.env.GANCIO_DB_DIALECT, + storage: process.env.GANCIO_DB_STORAGE, + host: process.env.GANCIO_DB_HOST, + database: process.env.GANCIO_DB_DATABASE, + username: process.env.GANCIO_DB_USERNAME, + password: process.env.GANCIO_DB_PASSWORD, + } + + setupController._setupDb(dbConf) + .catch(e => { process.exit(1) }) + } + +} + const helpers = require('./helpers') const log = require('./log') const api = require('./api') @@ -23,7 +45,7 @@ app.use(cookieParser()) // do not handle all routes on setup -if (!config.firstrun) { +if (config.status === 'READY') { const cors = require('cors') const { spamFilter } = require('./federation/helpers') const oauth = require('./api/oauth') @@ -65,13 +87,13 @@ app.use((error, req, res, next) => { app.use(async (req, res, next) => { // const start_datetime = getUnixTime(startOfWeek(startOfMonth(new Date()))) // req.events = await eventController._select(start_datetime, 100) - if (!config.firstrun) { + if (config.status === 'READY') { const eventController = require('./api/controller/event') const announceController = require('./api/controller/announce') req.meta = await eventController._getMeta() req.announcements = await announceController._getVisible() } - req.firstrun = config.firstrun + req.status = config.status next() }) diff --git a/store/index.js b/store/index.js index 8437284b..cd182e11 100644 --- a/store/index.js +++ b/store/index.js @@ -54,7 +54,7 @@ export const actions = { // we use it to get configuration from db, set locale, etc... nuxtServerInit ({ commit }, { req }) { commit('setSettings', req.settings) - if (!req.firstrun) { + if (req.status === 'READY') { commit('setAnnouncements', req.announcements) commit('update', req.meta) }