improve installation/documentation
This commit is contained in:
61
README.md
61
README.md
@@ -1,14 +1,54 @@
|
|||||||
## gancio
|
# gancio
|
||||||
### shared agenda for local communities
|
#### a shared agenda for local communities
|
||||||
|
|
||||||
> :warning: Gancio is under heavy development,
|
> :warning: WARNING :warning:
|
||||||
> if something is not working as expected, it's expected :D
|
> Gancio is under heavy development, if something is not working as expected, it's expected :D
|
||||||
|
Please be patient and open an [issue](/cisti/gancio/issues)!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Install
|
## Installation
|
||||||
You will need `npm` or `yarn` installed in your system.
|
|
||||||
|
|
||||||
|
##### Install node
|
||||||
|
```bash
|
||||||
|
# source https://github.com/nodesource/distributions/blob/master/README.md
|
||||||
|
curl -sL https://deb.nodesource.com/setup_12.x | bash -
|
||||||
|
apt-get install -y nodejs
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Install postgres
|
||||||
|
```bash
|
||||||
|
apt install postgresql
|
||||||
|
```
|
||||||
|
##### Create database
|
||||||
|
```bash
|
||||||
|
sudo -u postgres psql
|
||||||
|
postgres=# create database gancio;
|
||||||
|
postgres=# create user gancio with encrypted password 'gancio';
|
||||||
|
postgres=# grant all privileges on database gancio to gancio;
|
||||||
|
```
|
||||||
|
##### Install gancio
|
||||||
|
```bash
|
||||||
|
npm install --global gancio
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Create a new user
|
||||||
|
```bash
|
||||||
|
adduser gancio
|
||||||
|
su gancio
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Setup & test
|
||||||
|
```bash
|
||||||
|
gancio --help
|
||||||
|
gancio setup
|
||||||
|
gancio start
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Hacking
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
# clone this repo
|
# clone this repo
|
||||||
@@ -18,18 +58,9 @@ cd gancio
|
|||||||
# install dependencies
|
# install dependencies
|
||||||
yarn install
|
yarn install
|
||||||
|
|
||||||
# edit configuration
|
|
||||||
cp config.example.js config.js
|
|
||||||
|
|
||||||
# - migrate/create test sqlite db
|
|
||||||
yarn migrate:dev
|
|
||||||
|
|
||||||
# testing with sqlite db
|
# testing with sqlite db
|
||||||
yarn dev
|
yarn dev
|
||||||
|
|
||||||
# - migrate/create production db
|
|
||||||
yarn migrate
|
|
||||||
|
|
||||||
# build for production and launch server
|
# build for production and launch server
|
||||||
yarn build
|
yarn build
|
||||||
yarn start
|
yarn start
|
||||||
|
|||||||
@@ -8,8 +8,7 @@
|
|||||||
},
|
},
|
||||||
"db": {
|
"db": {
|
||||||
"dialect": "sqlite",
|
"dialect": "sqlite",
|
||||||
"storage": "./db.sqlite",
|
"storage": "./db.sqlite"
|
||||||
"logging": false
|
|
||||||
},
|
},
|
||||||
"upload_path": "./",
|
"upload_path": "./",
|
||||||
"smtp": {
|
"smtp": {
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
"nuxt.config.js",
|
"nuxt.config.js",
|
||||||
"locales/",
|
"locales/",
|
||||||
"dist/",
|
"dist/",
|
||||||
|
"views/",
|
||||||
"store/",
|
"store/",
|
||||||
"config/",
|
"config/",
|
||||||
".nuxt"
|
".nuxt"
|
||||||
|
|||||||
@@ -58,7 +58,6 @@ export default {
|
|||||||
Message({ message: this.$t('login.check_email'), type: 'success' })
|
Message({ message: this.$t('login.check_email'), type: 'success' })
|
||||||
},
|
},
|
||||||
async submit (e) {
|
async submit (e) {
|
||||||
console.error('dentro submit', e)
|
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
try {
|
try {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
|
|||||||
@@ -59,13 +59,13 @@ ${event.description.length > 200 ? event.description.substr(0, 200) + '...' : ev
|
|||||||
const type = msg.event
|
const type = msg.event
|
||||||
|
|
||||||
if (type === 'delete') {
|
if (type === 'delete') {
|
||||||
const activitypub_id = msg.data
|
const activitypub_id = String(msg.data)
|
||||||
const event = await Comment.findOne({ where: { activitypub_id } })
|
const event = await Comment.findOne({ where: { activitypub_id } })
|
||||||
if (event) await event.destroy()
|
if (event) await event.destroy()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const activitypub_id = msg.data.in_reply_to_id
|
const activitypub_id = String(msg.data.in_reply_to_id)
|
||||||
if (!activitypub_id) return
|
if (!activitypub_id) return
|
||||||
let event = await Event.findOne({ where: { activitypub_id } })
|
let event = await Event.findOne({ where: { activitypub_id } })
|
||||||
if (!event) {
|
if (!event) {
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
module.exports = (sequelize, DataTypes) => {
|
module.exports = (sequelize, DataTypes) => {
|
||||||
const comment = sequelize.define('comment', {
|
const comment = sequelize.define('comment', {
|
||||||
activitypub_id: DataTypes.STRING(18),
|
activitypub_id: {
|
||||||
|
type: DataTypes.STRING(18),
|
||||||
|
index: true,
|
||||||
|
unique: true,
|
||||||
|
},
|
||||||
data: DataTypes.JSON
|
data: DataTypes.JSON
|
||||||
}, {})
|
}, {})
|
||||||
comment.associate = function (models) {
|
comment.associate = function (models) {
|
||||||
|
|||||||
@@ -6,7 +6,11 @@ const sharp = require('sharp')
|
|||||||
const consola = require('consola')
|
const consola = require('consola')
|
||||||
const config = require('config')
|
const config = require('config')
|
||||||
|
|
||||||
mkdirp.sync(config.upload_path + '/thumb')
|
try {
|
||||||
|
mkdirp.sync(config.upload_path + '/thumb')
|
||||||
|
} catch (e) {
|
||||||
|
consola.error(e)
|
||||||
|
}
|
||||||
|
|
||||||
const DiskStorage = {
|
const DiskStorage = {
|
||||||
_handleFile(req, file, cb) {
|
_handleFile(req, file, cb) {
|
||||||
|
|||||||
134
server/cli.js
134
server/cli.js
@@ -1,56 +1,19 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
process.env.NODE_ENV = "production"
|
process.env.NODE_ENV = 'production'
|
||||||
|
|
||||||
|
const fs = require('fs')
|
||||||
|
const consola = require('consola')
|
||||||
|
const sequelize = require('sequelize')
|
||||||
|
const inquirer = require('inquirer')
|
||||||
|
const package = require('../package.json')
|
||||||
|
const firstrun = require('./firstrun')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
|
||||||
const cwd = process.cwd()
|
const cwd = process.cwd()
|
||||||
|
|
||||||
// needed by nuxt
|
// needed by nuxt
|
||||||
process.chdir(path.resolve(__dirname, '..'))
|
process.chdir(path.resolve(__dirname, '..'))
|
||||||
|
|
||||||
const arg = require('arg')
|
|
||||||
const inquirer = require('inquirer')
|
|
||||||
const package = require('../package.json')
|
|
||||||
const consola = require('consola')
|
|
||||||
const firstrun = require('./firstrun')
|
|
||||||
const fs = require('fs')
|
|
||||||
const sequelize = require('sequelize')
|
|
||||||
|
|
||||||
/**
|
|
||||||
* initial setup:
|
|
||||||
* - check first run
|
|
||||||
* - ask title, description, baseurl
|
|
||||||
* - ask and create upload path and thumb dir
|
|
||||||
* - ask and inizialite db
|
|
||||||
* - create first admin account
|
|
||||||
* - enable open registration?
|
|
||||||
* - enable anon event?
|
|
||||||
* - enable email export?
|
|
||||||
* - enable email notification?
|
|
||||||
* - enable notifier?
|
|
||||||
* - enable pm2
|
|
||||||
*
|
|
||||||
* start gancio:
|
|
||||||
*
|
|
||||||
* update gancio:
|
|
||||||
* - yarn/npm global update...
|
|
||||||
* - sequelize migrate !
|
|
||||||
*/
|
|
||||||
|
|
||||||
function parseArguments(rawArgs) {
|
|
||||||
const args = arg({
|
|
||||||
'--config': String,
|
|
||||||
'--install': Boolean,
|
|
||||||
'--upgrade': Boolean
|
|
||||||
}, {
|
|
||||||
argv: rawArgs.slice(2),
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
config: path.resolve(cwd, args['--config'] || '/etc/gancio_config.json') ,
|
|
||||||
install: args['--install'] || false,
|
|
||||||
upgrade: args['--upgrade'] || false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function notEmpty (value) {
|
function notEmpty (value) {
|
||||||
return value.length>0
|
return value.length>0
|
||||||
}
|
}
|
||||||
@@ -58,10 +21,17 @@ function notEmpty (value) {
|
|||||||
async function setupQuestionnaire() {
|
async function setupQuestionnaire() {
|
||||||
|
|
||||||
const questions = []
|
const questions = []
|
||||||
|
questions.push({
|
||||||
|
name: 'title',
|
||||||
|
message: 'Name of your instance',
|
||||||
|
default: 'Gancio',
|
||||||
|
validate: notEmpty
|
||||||
|
})
|
||||||
|
|
||||||
questions.push({
|
questions.push({
|
||||||
message: 'Specify a baseurl for this gancio installation! (eg. http://gancio.cisti.org)',
|
message: 'Specify a baseurl for this gancio installation! (eg. http://gancio.cisti.org)',
|
||||||
name: 'baseurl',
|
name: 'baseurl',
|
||||||
default: 'http://localhost:3000',
|
default: 'http://localhost:13120',
|
||||||
validate: notEmpty
|
validate: notEmpty
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -88,7 +58,7 @@ async function setupQuestionnaire() {
|
|||||||
questions.push({
|
questions.push({
|
||||||
name: 'db.storage',
|
name: 'db.storage',
|
||||||
message: 'sqlite db path',
|
message: 'sqlite db path',
|
||||||
default: '/var/gancio/db.sqlite',
|
default: './db.sqlite',
|
||||||
filter: p => path.resolve(cwd, p),
|
filter: p => path.resolve(cwd, p),
|
||||||
when: answers => answers.db.dialect === 'sqlite',
|
when: answers => answers.db.dialect === 'sqlite',
|
||||||
validate: db_path => db_path.length>0 && fs.existsSync(path.dirname(db_path))
|
validate: db_path => db_path.length>0 && fs.existsSync(path.dirname(db_path))
|
||||||
@@ -128,7 +98,7 @@ async function setupQuestionnaire() {
|
|||||||
try {
|
try {
|
||||||
const db = new sequelize({ ...options.db, dialect: 'postgres' , password, logging: false })
|
const db = new sequelize({ ...options.db, dialect: 'postgres' , password, logging: false })
|
||||||
return db.authenticate().then( () => {
|
return db.authenticate().then( () => {
|
||||||
// consola.info(`DB connected`)
|
db.close()
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
@@ -141,7 +111,7 @@ async function setupQuestionnaire() {
|
|||||||
questions.push({
|
questions.push({
|
||||||
name: 'upload_path',
|
name: 'upload_path',
|
||||||
message: 'Where gancio has to store media?',
|
message: 'Where gancio has to store media?',
|
||||||
default: '/var/gancio/',
|
default: './uploads',
|
||||||
filter: p => path.resolve(cwd, p),
|
filter: p => path.resolve(cwd, p),
|
||||||
validate: p => {
|
validate: p => {
|
||||||
const exists = fs.existsSync(p)
|
const exists = fs.existsSync(p)
|
||||||
@@ -187,38 +157,48 @@ async function setupQuestionnaire() {
|
|||||||
return answers
|
return answers
|
||||||
}
|
}
|
||||||
|
|
||||||
async function cli(args) {
|
async function start (options) {
|
||||||
|
|
||||||
const options = parseArguments(args)
|
|
||||||
consola.info(`${package.name} - v${package.version} - ${package.description}`)
|
|
||||||
|
|
||||||
// install flag specified?
|
|
||||||
if (options.install) {
|
|
||||||
consola.info(`Cool! You're going to setup gancio on this machine.`)
|
|
||||||
const config = await setupQuestionnaire()
|
|
||||||
await firstrun.setup(config, options.config)
|
|
||||||
consola.info(`You can edit '${options.config}' to modify your configuration. `)
|
|
||||||
consola.info(`- Run "gancio --config ${options.config}"`)
|
|
||||||
process.exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// upgrade gancio / TODO npm/yarn global upgrade gancio ?
|
|
||||||
if (options.upgrade) {
|
|
||||||
consola.warn('Not implemented yet but should be an easy task! PR welcome!')
|
|
||||||
process.exit(-1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// is first run?
|
// is first run?
|
||||||
if (firstrun.check(options.config)) {
|
if (firstrun.check(options.config)) {
|
||||||
consola.error(`Configuration file "${options.config}" not found!
|
consola.error(`Configuration file "${options.config}" not found!
|
||||||
This is your first run? You could create it using --install flag`)
|
This is your first run? You could create it using --install flag`)
|
||||||
|
|
||||||
process.exit(-1)
|
process.exit(-1)
|
||||||
} else {
|
|
||||||
process.env.config_path = options.config
|
|
||||||
require('./index')
|
|
||||||
}
|
}
|
||||||
|
require('./index')
|
||||||
}
|
}
|
||||||
|
|
||||||
cli(process.argv)
|
async function setup (options) {
|
||||||
|
consola.info(`You're going to setup gancio on this machine.`)
|
||||||
|
const config = await setupQuestionnaire()
|
||||||
|
await firstrun.setup(config, options.config)
|
||||||
|
consola.info(`You can edit '${options.config}' to modify your configuration. `)
|
||||||
|
consola.info(`Run "gancio --config ${options.config}"`)
|
||||||
|
process.exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function upgrade (options) {
|
||||||
|
consola.warn('Not implemented yet but should be an easy task! PR welcome!')
|
||||||
|
process.exit(-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
consola.info(`${package.name} - v${package.version} - ${package.description}`)
|
||||||
|
|
||||||
|
require('yargs')
|
||||||
|
.usage('Usage $0 <command> [options]')
|
||||||
|
.option('config', {
|
||||||
|
alias: 'c',
|
||||||
|
describe: 'Configuration file',
|
||||||
|
default: './gancio_config.json',
|
||||||
|
})
|
||||||
|
.coerce('config', config_path => {
|
||||||
|
const absolute_config_path = path.resolve(cwd, config_path)
|
||||||
|
process.env.config_path = absolute_config_path
|
||||||
|
return absolute_config_path
|
||||||
|
})
|
||||||
|
.command(['start', 'run', '$0'], 'Start gancio', {}, start)
|
||||||
|
.command('setup', 'Setup a new instance', {}, setup)
|
||||||
|
.command('upgrade', 'Upgrade gancio to a new release (interactive)', {}, upgrade)
|
||||||
|
.help('h')
|
||||||
|
.alias('h', 'help')
|
||||||
|
.epilog('Made with ❤ by underscore hacklab - https://autistici.org/underscore')
|
||||||
|
.argv
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
// const argv = require('yargs').argv
|
|
||||||
// const path = require('path')
|
|
||||||
// const fs = require('fs')
|
|
||||||
|
|
||||||
// const config_path = path.resolve(argv.config || './config.js')
|
|
||||||
|
|
||||||
// let user_config
|
|
||||||
// if (fs.existsSync(config_path)) {
|
|
||||||
// user_config = require(config_path)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const config = {
|
|
||||||
// baseurl: 'PLEASE CONFIGURE YOUR BASEURL!',
|
|
||||||
// server: {
|
|
||||||
// host: 'localhost',
|
|
||||||
// port: 3000
|
|
||||||
// },
|
|
||||||
// secret: '',
|
|
||||||
// db: {
|
|
||||||
// dialect: 'sqlite'
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// module.exports = Object.assign( config, user_config )
|
|
||||||
@@ -12,34 +12,39 @@ module.exports = {
|
|||||||
consola.info('Generate random salt')
|
consola.info('Generate random salt')
|
||||||
config.secret = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15)
|
config.secret = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15)
|
||||||
|
|
||||||
|
// do not save admin's password in config file
|
||||||
const admin = { email: config.admin.email, password: config.admin.password }
|
const admin = { email: config.admin.email, password: config.admin.password }
|
||||||
delete config.admin
|
delete config.admin
|
||||||
|
|
||||||
config.admin_email = admin.email
|
config.admin_email = admin.email
|
||||||
consola.info(`Save configuration into ${config_path}`)
|
config.db.logging = false
|
||||||
|
consola.info(`Save configuration to ${config_path}`)
|
||||||
fs.writeFileSync(config_path, JSON.stringify(config, null, 2))
|
fs.writeFileSync(config_path, JSON.stringify(config, null, 2))
|
||||||
|
|
||||||
// sync db
|
// sync db
|
||||||
const db = require('./api/models')
|
const db = require('./api/models')
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await db.user.findAll()
|
await db.user.findAll()
|
||||||
consola.warning(`!WARNING! Non empty db!`)
|
consola.warn(`⚠️ Non empty db! Please move your current db elsewhere than retry.
|
||||||
|
If you want to `)
|
||||||
return -1
|
return -1
|
||||||
} catch(e) {}
|
} catch(e) { console.error(e) }
|
||||||
|
|
||||||
|
consola.info(`Create tables schema`)
|
||||||
await db.sequelize.sync().catch(e => {
|
await db.sequelize.sync().catch(e => {
|
||||||
consola.error('Error creating tables', e)
|
consola.error('Error creating tables', e)
|
||||||
return -1
|
return -1
|
||||||
})
|
})
|
||||||
|
|
||||||
// create admin user
|
// create admin user
|
||||||
consola.info('Create admin user')
|
consola.info('Create admin user', admin)
|
||||||
await db.user.create({
|
await db.user.create({
|
||||||
...admin,
|
...admin,
|
||||||
is_admin: true,
|
is_admin: true,
|
||||||
is_active: true
|
is_active: true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
// set default settings
|
// set default settings
|
||||||
consola.info('Set default settings')
|
consola.info('Set default settings')
|
||||||
const settings = require('./api/controller/settings')
|
const settings = require('./api/controller/settings')
|
||||||
@@ -54,5 +59,8 @@ module.exports = {
|
|||||||
|
|
||||||
// send every event to admin
|
// send every event to admin
|
||||||
await db.notification.create({ type: 'admin_email' })
|
await db.notification.create({ type: 'admin_email' })
|
||||||
|
|
||||||
|
// close db connection
|
||||||
|
await db.sequelize.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@ const express = require('express')
|
|||||||
const consola = require('consola')
|
const consola = require('consola')
|
||||||
const morgan = require('morgan')
|
const morgan = require('morgan')
|
||||||
const { Nuxt, Builder } = require('nuxt')
|
const { Nuxt, Builder } = require('nuxt')
|
||||||
const firstRun = require('./firstrun')
|
|
||||||
// Import and Set Nuxt.js options
|
// Import and Set Nuxt.js options
|
||||||
const nuxt_config = require('../nuxt.config.js')
|
const nuxt_config = require('../nuxt.config.js')
|
||||||
const config = require('config')
|
const config = require('config')
|
||||||
|
|||||||
Reference in New Issue
Block a user