new web setup !
This commit is contained in:
@@ -261,5 +261,11 @@
|
|||||||
"scopes": {
|
"scopes": {
|
||||||
"event:write": "Add and edit your events"
|
"event:write": "Add and edit your events"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"setup": {
|
||||||
|
"check_db": "Check DB",
|
||||||
|
"completed": "Setup completed",
|
||||||
|
"completed_description": "Installation completed!<br/>You can now login with the following user: {email} / {password}. Please write to us at gancio@cisti.org for any question.",
|
||||||
|
"start": "Start"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
11
middleware/setup.js
Normal file
11
middleware/setup.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export default function ({ req, redirect, route }) {
|
||||||
|
if (process.server) {
|
||||||
|
if (req.firstrun && route.path !== '/setup') {
|
||||||
|
return redirect('/setup')
|
||||||
|
}
|
||||||
|
if (!req.firstrun && route.path === '/setup') {
|
||||||
|
return redirect('/')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -36,6 +36,7 @@ import Calendar from '@/components/Calendar'
|
|||||||
export default {
|
export default {
|
||||||
name: 'Index',
|
name: 'Index',
|
||||||
components: { Event, Search, Announcement, Calendar },
|
components: { Event, Search, Announcement, Calendar },
|
||||||
|
middleware: 'setup',
|
||||||
async asyncData ({ params, $api, store }) {
|
async asyncData ({ params, $api, store }) {
|
||||||
const events = await $api.getEvents({
|
const events = await $api.getEvents({
|
||||||
start: dayjs().startOf('month').unix(),
|
start: dayjs().startOf('month').unix(),
|
||||||
|
|||||||
40
pages/setup/Completed.vue
Normal file
40
pages/setup/Completed.vue
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<template lang="pug">
|
||||||
|
v-container
|
||||||
|
v-card-title.d-block.text-h5.text-center(v-text="$t('setup.completed')")
|
||||||
|
v-card-text
|
||||||
|
p(v-html="$t('setup.completed_description', user)")
|
||||||
|
v-card-actions
|
||||||
|
v-btn(text @click='next' color='primary' :loading='loading' :disabled='loading') {{$t('setup.start')}}
|
||||||
|
v-icon mdi-arrow-right
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
user: {
|
||||||
|
email: 'admin',
|
||||||
|
password: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
next () {
|
||||||
|
window.location='/'
|
||||||
|
},
|
||||||
|
async start (user) {
|
||||||
|
this.user = { ...user }
|
||||||
|
this.loading = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.$axios.$get('/ping')
|
||||||
|
// window.location='/'
|
||||||
|
this.loading = false
|
||||||
|
} catch (e) {
|
||||||
|
setTimeout(() => this.start(user), 1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
48
pages/setup/DbStep.vue
Normal file
48
pages/setup/DbStep.vue
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
<template lang="pug">
|
||||||
|
v-container
|
||||||
|
v-card-title.text-h5 Database
|
||||||
|
v-card-text
|
||||||
|
v-form
|
||||||
|
v-btn-toggle(text color='primary' v-model='db.dialect')
|
||||||
|
v-btn(value='sqlite' text) sqlite
|
||||||
|
v-btn(value='postgres' text) postgres
|
||||||
|
template(v-if='db.dialect === "sqlite"')
|
||||||
|
v-text-field(v-model='db.storage' label='Path')
|
||||||
|
template(v-if='db.dialect === "postgres"')
|
||||||
|
v-text-field(v-model='db.hostname' label='Hostname' :rules="[$validators.required('hostname')]")
|
||||||
|
v-text-field(v-model='db.database' label='Database' :rules="[$validators.required('database')]")
|
||||||
|
v-text-field(v-model='db.username' label='Username' :rules="[$validators.required('username')]")
|
||||||
|
v-text-field(type='password' v-model='db.password' label='Password' :rules="[$validators.required('password')]")
|
||||||
|
|
||||||
|
v-card-actions
|
||||||
|
v-btn(text @click='checkDb' color='primary' :loading='loading' :disabled='loading') {{$t('setup.check_db')}}
|
||||||
|
v-icon mdi-arrow-right
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
db: {
|
||||||
|
storage: './gancio.sqlite',
|
||||||
|
hostname: 'localhost',
|
||||||
|
database: 'gancio'
|
||||||
|
},
|
||||||
|
loading: false,
|
||||||
|
buttonText: 'setup.check_db'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async checkDb () {
|
||||||
|
this.loading = true
|
||||||
|
try {
|
||||||
|
await this.$axios.$post('/setup/db', { db: this.db })
|
||||||
|
this.$root.$message('DB Connection OK!', { color: 'success' })
|
||||||
|
this.$emit('complete', this.db)
|
||||||
|
} catch (e) {
|
||||||
|
this.$root.$message(e.response.data, { color: 'error' })
|
||||||
|
}
|
||||||
|
this.loading = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
57
pages/setup/index.vue
Normal file
57
pages/setup/index.vue
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<template lang="pug">
|
||||||
|
|
||||||
|
v-container.pa-6
|
||||||
|
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(: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')
|
||||||
|
DbStep(@complete='dbCompleted')
|
||||||
|
v-stepper-content(step='2')
|
||||||
|
Settings(setup, @complete='configCompleted')
|
||||||
|
v-stepper-content(step='3')
|
||||||
|
Completed(ref='completed')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import DbStep from './DbStep'
|
||||||
|
import Settings from '../../components/admin/Settings'
|
||||||
|
import Completed from './Completed'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: { DbStep, Settings, Completed },
|
||||||
|
middleware: 'setup',
|
||||||
|
layout: 'iframe',
|
||||||
|
auth: false,
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
config: {
|
||||||
|
db: {
|
||||||
|
dialect: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
step: 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
dbCompleted (db) {
|
||||||
|
this.step = this.step + 1
|
||||||
|
},
|
||||||
|
async configCompleted () {
|
||||||
|
const user = await this.$axios.$post('/setup/restart')
|
||||||
|
this.step = this.step + 1
|
||||||
|
this.$refs.completed.start(user)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
86
server/api/controller/setup.js
Normal file
86
server/api/controller/setup.js
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
const log = require('../../log')
|
||||||
|
const db = require('../models/index.js')
|
||||||
|
const Umzug = require('umzug')
|
||||||
|
const path = require('path')
|
||||||
|
const config = require('../../config')
|
||||||
|
const Sequelize = require('sequelize')
|
||||||
|
|
||||||
|
const crypto = require('crypto')
|
||||||
|
const { promisify } = require('util')
|
||||||
|
const randomBytes = promisify(crypto.randomBytes)
|
||||||
|
async function randomString (len = 16) {
|
||||||
|
const bytes = await randomBytes(len * 8)
|
||||||
|
return crypto
|
||||||
|
.createHash('sha1')
|
||||||
|
.update(bytes)
|
||||||
|
.digest('hex')
|
||||||
|
}
|
||||||
|
|
||||||
|
const setupController = {
|
||||||
|
|
||||||
|
async setupDb (req, res, next) {
|
||||||
|
log.debug('[SETUP] Check db')
|
||||||
|
const dbConf = req.body.db
|
||||||
|
if (!dbConf) {
|
||||||
|
return res.sendStatus(400)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const sequelize = await db.connect(dbConf)
|
||||||
|
const users = await sequelize.query('SELECT * from users').catch(e => {})
|
||||||
|
config.db = dbConf
|
||||||
|
if (users && users.length) {
|
||||||
|
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.')
|
||||||
|
} else {
|
||||||
|
// run migrations...
|
||||||
|
const umzug = new Umzug({
|
||||||
|
storage: 'sequelize',
|
||||||
|
storageOptions: { sequelize },
|
||||||
|
logging: log.debug.bind(log),
|
||||||
|
migrations: {
|
||||||
|
wrap: fun => {
|
||||||
|
return () =>
|
||||||
|
fun(sequelize.queryInterface, Sequelize).catch(e => {
|
||||||
|
log.error(e)
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
path: path.resolve(__dirname, '..', '..', 'migrations')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await umzug.up()
|
||||||
|
config.firstrun = false
|
||||||
|
config.db.logging = false
|
||||||
|
const settingsController = require('./settings')
|
||||||
|
await settingsController.load()
|
||||||
|
return res.sendStatus(200)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
return res.status(400).send(String(e))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async restart (req, res) {
|
||||||
|
config.write()
|
||||||
|
|
||||||
|
// create admin user
|
||||||
|
const password = await randomString()
|
||||||
|
const email = `admin@${req.settings.hostname}`
|
||||||
|
const User = require('../models/user')
|
||||||
|
await User.create({
|
||||||
|
email,
|
||||||
|
password,
|
||||||
|
is_admin: true,
|
||||||
|
is_active: true
|
||||||
|
})
|
||||||
|
|
||||||
|
res.json({ password, email })
|
||||||
|
|
||||||
|
// exit process so pm2 || docker could restart me
|
||||||
|
process.exit()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = setupController
|
||||||
Reference in New Issue
Block a user