fix #10 choose upload path in config.js

This commit is contained in:
lesion
2019-06-11 17:44:11 +02:00
parent a557348b21
commit 5778c64108
16 changed files with 99 additions and 95 deletions

View File

@@ -1,14 +1,15 @@
const path = require('path')
/** /**
* -[ GANCIO CONFIGURATION ]- * -[ GANCIO CONFIGURATION ]-
* *
* search and replace 'CHANGE ME'
*
* -[ Database configuration ]- * -[ Database configuration ]-
* `development` configuration is enabled running `yarn dev` * `development` configuration is enabled running `yarn dev`
* while `production` with `yarn start` * while `production` with `yarn start`
* ref: http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor * ref: http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor
* *
*/ */
const path = require('path')
const DB_CONF = { const DB_CONF = {
development: { development: {
@@ -16,8 +17,8 @@ const DB_CONF = {
dialect: 'sqlite' dialect: 'sqlite'
}, },
production: { production: {
username: '', username: 'CHANGE ME',
password: '', password: 'CHANGE ME',
database: 'gancio', database: 'gancio',
host: 'localhost', host: 'localhost',
dialect: 'postgres', dialect: 'postgres',
@@ -26,7 +27,7 @@ const DB_CONF = {
} }
const env = process.env.NODE_ENV || 'development' const env = process.env.NODE_ENV || 'development'
const isDev = env === 'development'
/** /**
* -[ Main configuration ]- * -[ Main configuration ]-
* *
@@ -34,30 +35,34 @@ const env = process.env.NODE_ENV || 'development'
const config = { const config = {
server: { server: {
port: '3000', port: '3000',
host: '0', host: 'localhost', // use 0.0.0.0 to bind to all interface
// uncomment to use unix socket to serve gancio // uncomment to use unix socket to serve gancio
// path: '/tmp/gancio_socket', // path: '/tmp/gancio_socket',
}, },
locale: 'it', locale: 'it',
title: 'GANCIO', title: isDev ? 'GANCIO' : 'CHANGE ME',
description: 'A shared agenda for radical communities', description: isDev ? 'A shared agenda for radical communities' : 'CHANGE ME',
baseurl: '' || 'http://localhost:3000', baseurl: isDev ? 'http://localhost:3000' : 'https://CHANGE_ME',
upload_path: isDev ? '/tmp/gancio_upload' : '/var/gancio/upload/',
// where events/users confirmation email are sent // where events/users confirmation email are sent
admin: '', admin: 'CHANGE ME',
// jwt salt secret, generate it randomly with // jwt salt secret, generate it randomly with
// < /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-32};echo; // < /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-32};echo;
secret: '', secret: isDev ? 'notreallyrandom' : 'CHANGE ME',
// smtp account to send email // smtp account to send email
smtp: { smtp: {
host: process.env.SMTP_HOST || 'mail.example.com', host: 'CHANGE ME', // mail.example.com
secure: true,
auth: { auth: {
user: process.env.SMTP_USER || 'gancio@example.com', user: 'CHANGE ME',
pass: process.env.SMTP_PASS || '' pass: 'CHANGE ME'
} },
secure: true
}, },
db: DB_CONF[env] db: DB_CONF[env]
} }

View File

@@ -122,21 +122,21 @@ const it = {
}, },
settings: { settings: {
change_password: 'Cambia password' change_password: 'Cambia password',
password_updated: 'Password modificata'
}, },
err: { err: {
register_error: 'Errore nella registrazione' register_error: 'Errore nella registrazione'
} }
// firstrun: { // firstrun: {
// basic: `Inserisci titolo e descrizione della tua istanza di gancio.`, // basic: `Inserisci titolo e descrizione della tua istanza di gancio.`,
// database: `Gancio ha bisogno di un database postgresql!`, // database: `Gancio ha bisogno di un database postgresql!`,
// smtp: `Inserisci un account SMTP relativo a questa istanza di gancio.` // smtp: `Inserisci un account SMTP relativo a questa istanza di gancio.`
// }, // },
// email: {
// registration: `Abbiamo ricevuto la richiesta di registrazione. La confermeremo quanto prima.\n Ciao`
// }
} }
export default it export default it

View File

@@ -223,6 +223,8 @@ export default {
const place = this.places.find( p => p.name === this.event.place.name ) const place = this.places.find( p => p.name === this.event.place.name )
if (place && place.address) { if (place && place.address) {
this.event.place.address = place.address this.event.place.address = place.address
} else {
this.event.place.address = ''
} }
this.$refs.address.focus() this.$refs.address.focus()
}, },

View File

@@ -5,13 +5,13 @@
import { mapState } from 'vuex' import { mapState } from 'vuex'
import List from '../../components/List' import List from '../../components/List'
import moment from 'dayjs' import moment from 'dayjs'
import get from 'lodash/get'
export default { export default {
layout: 'iframe', layout: 'iframe',
components: { List }, components: { List },
computed: mapState(['config']),
async asyncData ({ $axios, req, res }) { async asyncData ({ $axios, req, res }) {
const title = req && req.query && req.query.title || this.config.title const title = get(req, 'query.title')
const tags = req && req.query && req.query.tags const tags = req && req.query && req.query.tags
const places = req && req.query && req.query.places const places = req && req.query && req.query.places
const now = new Date() const now = new Date()

View File

@@ -1,6 +1,5 @@
<template lang="pug"> <template lang="pug">
el-card#eventDetail el-card#eventDetail(v-loading='!loaded')
//- close button //- close button
nuxt-link.float-right(to='/') nuxt-link.float-right(to='/')
el-button(circle icon='el-icon-close' type='danger' size='small' plain) el-button(circle icon='el-icon-close' type='danger' size='small' plain)
@@ -18,7 +17,7 @@
el-button(icon='el-icon-arrow-right' round type='success') el-button(icon='el-icon-arrow-right' round type='success')
//- image //- image
img(:src='imgPath' v-if='event.image_path') img(:src='imgPath' v-if='event.image_path' @load='image_loaded')
.info .info
div {{event|event_when}} div {{event|event_when}}
@@ -56,6 +55,11 @@ import { mapState, mapActions, mapGetters } from 'vuex'
export default { export default {
name: 'Event', name: 'Event',
data () {
return {
loaded: false,
}
},
// transition: null, // transition: null,
// Watch for $route.query.page to call Component methods (asyncData, fetch, validate, layout, etc.) // Watch for $route.query.page to call Component methods (asyncData, fetch, validate, layout, etc.)
// watchQuery: ['id'], // watchQuery: ['id'],
@@ -84,7 +88,8 @@ export default {
}, },
async asyncData ( { $axios, params }) { async asyncData ( { $axios, params }) {
const event = await $axios.$get(`/event/${params.id}`) const event = await $axios.$get(`/event/${params.id}`)
return { event, id: params.id} const loaded = !event.image_path
return { event, id: params.id, loaded }
}, },
computed: { computed: {
...mapGetters(['filteredEvents']), ...mapGetters(['filteredEvents']),
@@ -112,6 +117,9 @@ export default {
}, },
}, },
methods: { methods: {
image_loaded (e, b) {
this.loaded = true
},
...mapActions(['delEvent']), ...mapActions(['delEvent']),
comment_filter (value) { comment_filter (value) {
return value.replace(/<a.*href="([^">]+).*>(?:.(?!\<\/a\>))*.<\/a>/, (orig, url) => { return value.replace(/<a.*href="([^">]+).*>(?:.(?!\<\/a\>))*.<\/a>/, (orig, url) => {

View File

@@ -15,14 +15,14 @@
//- el-tag.ml-1(size='mini' v-for='place in filters.places' :key='place.id') {{place}} //- el-tag.ml-1(size='mini' v-for='place in filters.places' :key='place.id') {{place}}
el-tabs.mt-2(v-model='type') el-tabs.mt-2(v-model='type')
el-tab-pane.pt-1(label='email' name='email') //- el-tab-pane.pt-1(label='email' name='email')
p(v-html='$t(`export.email_description`)') //- p(v-html='$t(`export.email_description`)')
el-form(@submit.native.prevent) //- el-form(@submit.native.prevent)
//- el-switch(v-model='notification.notify_on_add' :active-text="$t('notify_on_insert')") //- //- el-switch(v-model='notification.notify_on_add' :active-text="$t('notify_on_insert')")
//- br //- //- br
//- el-switch.mt-2(v-model='notification.send_notification' :active-text="$t('send_notification')") //- //- el-switch.mt-2(v-model='notification.send_notification' :active-text="$t('send_notification')")
el-input.mt-2(v-model='notification.email' :placeholder="$t('export.insert_your_address')" ref='email') //- el-input.mt-2(v-model='notification.email' :placeholder="$t('export.insert_your_address')" ref='email')
el-button.mt-2.float-right(native-type= 'submit' type='success' @click='add_notification') {{$t('common.send')}} //- el-button.mt-2.float-right(native-type= 'submit' type='success' @click='add_notification') {{$t('common.send')}}
el-tab-pane.pt-1(label='feed rss' name='feed') el-tab-pane.pt-1(label='feed rss' name='feed')
span(v-html='$t(`export.feed_description`)') span(v-html='$t(`export.feed_description`)')
@@ -104,10 +104,14 @@ export default {
params.push(`title=${this.list.title}`) params.push(`title=${this.list.title}`)
} }
if (this.filters.places) { if (this.filters.places.length) {
params.push(`places=${this.filters.places}`) params.push(`places=${this.filters.places}`)
} }
if (this.filters.tags.length) {
params.push(`tags=${this.filters.tags}`)
}
return `<iframe src="${process.env.baseurl}/embed/list?${params.join('&')}"></iframe>` return `<iframe src="${process.env.baseurl}/embed/list?${params.join('&')}"></iframe>`
}, },
link () { link () {

View File

@@ -5,21 +5,21 @@
v-icon(name='times' color='red') v-icon(name='times' color='red')
h5 {{$t('common.settings')}} h5 {{$t('common.settings')}}
//- el-form el-form(action='/api/user' method='PUT' @submit.native.prevent='change')
//- el-form-item {{$t('settings.change_password')}} el-form-item {{$t('settings.change_password')}}
el-divider {{$t('settings.change_password')}} el-input(v-model='password' type='password')
el-input(v-model='password' type='password') el-button(type='success' native-type='submit') {{$t('common.send')}}
el-button(slot='append' @click='change' type='success') {{$t('common.send')}}
</template> </template>
<script> <script>
import { mapState, mapActions } from 'vuex' import { mapState, mapActions } from 'vuex'
import { Message } from 'element-ui'
export default { export default {
data () { data () {
return { return {
password: '', password: '',
} }
}, },
// computed: mapState(['user']),
// async asyncData ({ $axios, params }) { // async asyncData ({ $axios, params }) {
// const user = await $axios.$get('/auth/user') // const user = await $axios.$get('/auth/user')
// user.mastodon_auth = '' // user.mastodon_auth = ''
@@ -31,6 +31,8 @@ export default {
const user_data = { id : this.$auth.user.id, password: this.password } const user_data = { id : this.$auth.user.id, password: this.password }
try { try {
const user = await this.$axios.$put('/user', user_data) const user = await this.$axios.$put('/user', user_data)
Message({ message: this.$t('settings.password_updated'), type: 'success' })
this.$router.replace('/')
} catch (e) { } catch (e) {
console.log(e) console.log(e)
} }

View File

@@ -1,16 +1,20 @@
import Vue from 'vue' import Vue from 'vue'
import { Button, Select, Tag, Option, Table, FormItem, Card, Row, Col, Upload, Checkbox, import { Button, Select, Tag, Option, Table, FormItem, Card, Row, Col, Upload, Checkbox,
Form, Tabs, TabPane, Switch, Input, Loading, TimeSelect, Badge, ButtonGroup, Divider, Step, Steps, Form, Tabs, TabPane, Switch, Input, Loading, TimeSelect, Badge, ButtonGroup, Divider, Step, Steps,
TableColumn, ColorPicker, Pagination, Popover, Tooltip, Dialog, TableColumn, ColorPicker, Pagination, Popover, Tooltip, Dialog, Image,
Container, Footer , Timeline, TimelineItem, Menu, MenuItem } from 'element-ui' Container, Footer, Timeline, TimelineItem, Menu, MenuItem } from 'element-ui'
import localeEn from 'element-ui/lib/locale/lang/en'
import localeIt from 'element-ui/lib/locale/lang/it'
import locale from 'element-ui/lib/locale' import locale from 'element-ui/lib/locale'
locale.use(localeIt)
const locales = {
it: require('element-ui/lib/locale/lang/it'),
en: require('element-ui/lib/locale/lang/en')
}
locale.use(locales[process.env.locale])
export default () => { export default () => {
Vue.use(Button) Vue.use(Button)
Vue.use(Divider) Vue.use(Divider)
Vue.use(Image)
Vue.use(Step) Vue.use(Step)
Vue.use(Steps) Vue.use(Steps)
Vue.use(Checkbox) Vue.use(Checkbox)

View File

@@ -48,7 +48,7 @@ ${event.description.length > 200 ? event.description.substr(0, 200) + '...' : ev
let media let media
if (event.image_path) { if (event.image_path) {
const file = path.join(__dirname, '..', '..', '..', 'uploads', event.image_path) const file = path.join(config.upload_path, event.image_path)
if (fs.statSync(file)) { if (fs.statSync(file)) {
media = await bot.post('media', { file: fs.createReadStream(file) }) media = await bot.post('media', { file: fs.createReadStream(file) })
} }

View File

@@ -53,8 +53,8 @@ const userController = {
// check if event is mine (or user is admin) // check if event is mine (or user is admin)
if (event && (req.user.is_admin || req.user.id === event.userId)) { if (event && (req.user.is_admin || req.user.id === event.userId)) {
if (event.image_path) { if (event.image_path) {
const old_path = path.resolve(__dirname, '..', '..', 'uploads', event.image_path) const old_path = path.join(config.upload_path, event.image_path)
const old_thumb_path = path.resolve(__dirname, '..', '..', 'uploads', 'thumb', event.image_path) const old_thumb_path = path.join(config.upload_path, 'thumb', event.image_path)
try { try {
await fs.unlink(old_path) await fs.unlink(old_path)
await fs.unlink(old_thumb_path) await fs.unlink(old_thumb_path)
@@ -126,8 +126,8 @@ const userController = {
if (req.file) { if (req.file) {
if (event.image_path) { if (event.image_path) {
const old_path = path.resolve(__dirname, '..', '..', 'uploads', event.image_path) const old_path = path.resolve(config.upload_path, event.image_path)
const old_thumb_path = path.resolve(__dirname, '..', '..', 'uploads', 'thumb', event.image_path) const old_thumb_path = path.resolve(config.upload_path, 'thumb', event.image_path)
await fs.unlink(old_path, e => console.error(e)) await fs.unlink(old_path, e => console.error(e))
await fs.unlink(old_thumb_path, e => console.error(e)) await fs.unlink(old_thumb_path, e => console.error(e))
} }

View File

@@ -11,9 +11,7 @@ const exportController = require('./controller/export')
const userController = require('./controller/user') const userController = require('./controller/user')
const settingsController = require('./controller/settings') const settingsController = require('./controller/settings')
const storage = require('./storage')({ const storage = require('./storage')
destination: 'uploads/'
})
const upload = multer({ storage }) const upload = multer({ storage })
const api = express.Router() const api = express.Router()

View File

@@ -1,62 +1,43 @@
const fs = require('fs') const fs = require('fs')
const os = require('os')
const path = require('path') const path = require('path')
const crypto = require('crypto') const crypto = require('crypto')
const mkdirp = require('mkdirp') const mkdirp = require('mkdirp')
const sharp = require('sharp') const sharp = require('sharp')
const consola = require('consola')
const config = require('../config')
function getDestination(req, file, cb) { mkdirp.sync(config.upload_path + '/thumb')
cb(null, os.tmpdir())
}
function DiskStorage(opts) {
if (typeof opts.destination === 'string') {
mkdirp.sync(opts.destination)
this.getDestination = function ($0, $1, cb) { cb(null, opts.destination) }
} else {
this.getDestination = (opts.destination || getDestination)
}
}
DiskStorage.prototype._handleFile = function _handleFile(req, file, cb) {
const that = this
that.getDestination(req, file, function (err, destination) {
if (err) return cb(err)
const DiskStorage = {
_handleFile(req, file, cb) {
const filename = crypto.randomBytes(16).toString('hex') + '.jpg' const filename = crypto.randomBytes(16).toString('hex') + '.jpg'
const finalPath = path.join(destination, filename) const finalPath = path.resolve(config.upload_path, filename)
const thumbPath = path.join(destination, 'thumb', filename) const thumbPath = path.resolve(config.upload_path, 'thumb', filename)
const outStream = fs.createWriteStream(finalPath) const outStream = fs.createWriteStream(finalPath)
const thumbStream = fs.createWriteStream(thumbPath) const thumbStream = fs.createWriteStream(thumbPath)
const resizer = sharp().resize(800).jpeg({ quality: 90 }) const resizer = sharp().resize(800).jpeg({ quality: 90 })
const thumbnailer = sharp().resize(400).jpeg({ quality: 90 }) const thumbnailer = sharp().resize(400).jpeg({ quality: 90 })
file.stream.pipe(thumbnailer).pipe(thumbStream) file.stream.pipe(thumbnailer).pipe(thumbStream)
thumbStream.on('error', e => console.log('thumbStream error ', e)) thumbStream.on('error', e => consola.error('thumbStream error ', e))
file.stream.pipe(resizer).pipe(outStream) file.stream.pipe(resizer).pipe(outStream)
outStream.on('error', cb) outStream.on('error', cb)
outStream.on('finish', function () { outStream.on('finish', function () {
cb(null, { cb(null, {
destination, destination: config.upload_path,
filename, filename,
path: finalPath, path: finalPath,
size: outStream.bytesWritten size: outStream.bytesWritten
}) })
}) })
}) },
_removeFile(req, file, cb) {
delete file.destination
delete file.filename
delete file.path
fs.unlink(path, cb)
}
} }
DiskStorage.prototype._removeFile = function _removeFile(req, file, cb) { module.exports = DiskStorage
let path = file.path
delete file.destination
delete file.filename
delete file.path
fs.unlink(path, cb)
}
module.exports = function (opts) {
return new DiskStorage(opts)
}

View File

@@ -3,7 +3,7 @@ p Dove: #{event.place.name} - #{event.place.address}
p Quando: #{datetime(event.start_datetime)} p Quando: #{datetime(event.start_datetime)}
br br
if event.image_path if event.image_path
<img style="width: 100%" src="#{config.apiurl}/uploads/#{event.image_path}" /> <img style="width: 100%" src="#{config.apiurl}/media/#{event.image_path}" />
p #{event.description} p #{event.description}
each tag in event.tags each tag in event.tags

View File

@@ -1,3 +1,3 @@
p= t('mail.recover') p= t('email.recover')
<a href="#{config.baseurl}/recover/#{user.recover_code}">#{t('press here')}</a> <a href="#{config.baseurl}/recover/#{user.recover_code}">#{t('email.press_here')}</a>

View File

@@ -26,7 +26,7 @@ async function start() {
// Give nuxt middleware to express // Give nuxt middleware to express
app.use(morgan('dev')) app.use(morgan('dev'))
app.use('/media/', express.static(path.join(__dirname, '..', 'uploads'))) app.use('/media/', express.static(config.upload_path))
app.use(nuxt.render) app.use(nuxt.render)
// Listen the server // Listen the server

View File

@@ -16,7 +16,7 @@ rss(version='2.0')
| <h4>#{event.title}</h4> | <h4>#{event.title}</h4>
| <strong>#{event.place.name} - #{event.place.address}</strong> | <strong>#{event.place.name} - #{event.place.address}</strong>
| #{moment(event.start_datetime).format("dddd, D MMMM HH:mm")}<br/> | #{moment(event.start_datetime).format("dddd, D MMMM HH:mm")}<br/>
| <img src="#{config.apiurl}/../uploads/#{event.image_path}"/> | <img src="#{config.apiurl}/media/#{event.image_path}"/>
| <pre>!{event.description}</pre> | <pre>!{event.description}</pre>
| ]]> | ]]>
pubDate= new Date(event.createdAt).toUTCString() pubDate= new Date(event.createdAt).toUTCString()