allow_anon_event, comment via mastodon

This commit is contained in:
lesion 2019-06-25 01:05:38 +02:00
parent 3c9c85e268
commit b093dae3f3
32 changed files with 259 additions and 219 deletions

View file

@ -42,7 +42,7 @@ export default {
...mapGetters(['filteredEvents']),
attributes () {
let attributes = []
attributes.push ({ key: 'today', dates: new Date(), highlight: { color: 'yellow' }})
attributes.push ({ key: 'today', dates: new Date(), highlight: { color: 'green' }})
attributes = attributes.concat(this.filteredEvents
.filter(e => !e.multidate)

View file

@ -9,7 +9,7 @@
el-menu-item(v-if='!$auth.loggedIn' :title="$t('common.login')")
v-icon(color='lightgreen' name='user')
nuxt-link(to='/add')
nuxt-link(v-if='could_add' to='/add')
el-menu-item(:title="$t('common.add_event')")
v-icon(color='lightgreen' name='plus')
@ -17,8 +17,9 @@
placement="bottom"
trigger="click")
Search(past-filter)
el-menu-item(slot='reference')
el-menu-item(slot='reference' :title="$t('common.search')" icon='el-share-button')
v-icon(color='lightblue' name='search')
el-badge(v-if='filters.tags.length+filters.places.length>0' is-dot type='warning')
nuxt-link(to='/settings')
el-menu-item(v-if='$auth.loggedIn' :title="$t('common.settings')")
@ -38,14 +39,22 @@
</template>
<script>
import { Message } from 'element-ui'
import { mapState } from 'vuex'
import Search from '@/components/Search'
export default {
name: 'Nav',
components: { Search },
computed: {
could_add () {
return (this.$auth.loggedIn || this.settings.allow_anon_event)
},
...mapState(['filters', 'settings']),
},
methods: {
logout () {
Message({
showClose: true,
message: this.$t('common.logout_ok'),
type: 'success'
})

View file

@ -13,8 +13,9 @@
inactive-color='lightgreen'
v-model='showPast'
)
el-select.search(v-model='filter' multiple
no-ssr
el-select.search(v-model='filter'
multiple
filterable collapse-tags default-first-option
:placeholder='$t("common.search")')
el-option(v-for='(keyword, id) in keywords' :key='keyword.value'

View file

@ -8,12 +8,13 @@
},
"db": {
"dialect": "sqlite",
"storage": "./db.sqlite"
"storage": "./db.sqlite",
"logging": false
},
"upload_path": "./",
"admin": {
"email": "les",
"password": "les"
"email": "",
"password": ""
},
"secret": "za34yz70mmwlervesgxor"
"secret": "notsosecret"
}

View file

@ -112,6 +112,7 @@ const it = {
where_description: `Dov'è il gancio? Se il posto non è presente, scrivilo e <b>premi invio</b>. `,
confirmed: 'Evento confermato',
not_found: 'Evento non trovato',
remove_confirmation: `Sicura di voler eliminare questo evento?`
},
admin: {
@ -124,7 +125,8 @@ const it = {
delete_user_confirm: 'Sicura di rimuovere questo utente?',
user_remove_ok: 'Utente eliminato',
user_create_ok: 'Utente creato',
allow_registration_description : 'Puoi decidere se abilitare la registrazione',
allow_registration_description : 'Vuoi abilitare la registrazione?',
allow_anon_event: 'Si possono inserire eventi anonimi (previa conferma)?'
},
auth: {
@ -142,9 +144,39 @@ const it = {
err: {
register_error: 'Errore nella registrazione'
}
},
about: `
<p>
Gancio e' un progetto dell'<a href='https://autistici.org/underscore'>underscore hacklab</a> e uno dei
servizi di <a href='https://cisti.org'>cisti.org</a>.</p>
<h5> Cos'è gancio?</h5>
<p>Uno strumento di condivisione di eventi per comunità radicali.
Dentro gancio puoi trovare e inserire eventi.
Gancio, come tutto <a href='https://cisti.org'>cisti.org</a> è uno strumento
antisessista, antirazzista, antifascista e anticapitalista, riflettici quando
pubblichi un evento.</p>
<h5>Ok, ma cosa vuol dire gancio?</h5>
<p>
Se vieni a Torino e dici: "ehi, ci diamo un gancio alle 8?" nessuno si presenterà con i guantoni per fare a mazzate.
Darsi un gancio vuol dire beccarsi alle ore X in un posto Y.</p>
<code>
<ul>
<li> a che ora è il gancio in radio per andare al presidio?</li>
<li> non so ma domani non posso venire, ho gia' un gancio per caricare il bar.</li>
</ul>
</code>
<h5> Contatti</h5>
<p>
Hai scritto una nuova interfaccia per gancio? Vuoi aprire un nuovo nodo di gancio nella tua città?
C'è qualcosa che vorresti migliorare? Per contribuire i sorgenti sono liberi e disponibili
<a href='https://git.lattuga.net/cisti/gancio'>qui</a>. Aiuti e suggerimenti sono sempre benvenuti, puoi scriverci
su underscore chicciola autistici.org</p>
`
}
module.exports = it
export default it

View file

@ -35,8 +35,9 @@ module.exports = {
'@/plugins/element-ui', // UI library -> https://element.eleme.io/#/en-US/
'@/plugins/filters', // text filters, datetime, etc.
'@/plugins/vue-awesome', // icon
'@/plugins/axios', // icon
{ src: '@/plugins/v-calendar', ssr: false } // calendar, TO-REDO
'@/plugins/axios', // axios baseurl configuration
{ src: '@/plugins/v-calendar', ssr: false }, // calendar, TO-REDO
'@/plugins/i18n.js'
],
/*
@ -46,20 +47,6 @@ module.exports = {
// Doc: https://axios.nuxtjs.org/usage
'@nuxtjs/axios',
'@nuxtjs/auth',
['nuxt-i18n', {
locales: [
{ code: 'en', iso: 'en-US', file: './locales/en.js' },
{ code: 'it', iso: 'it-IT', file: './locales/it.js' },
],
defaultLocale: 'it',
vueI18n: {
fallbackLocale: 'it',
messages: {
it: require('./locales/it'),
en: require('./locales/en'),
}
}
}]
],
/*
** Axios module configuration

View file

@ -47,7 +47,7 @@
"cross-env": "^5.2.0",
"dayjs": "^1.8.14",
"element-ui": "^2.9.1",
"email-templates": "^5.1.0",
"email-templates": "^6.0.0",
"express": "^4.17.1",
"express-jwt": "^5.3.1",
"ics": "^2.13.2",

View file

@ -5,31 +5,6 @@
v-icon(name='times' color='red')
h3 {{$t('common.info')}}
p.
Gancio e' un progetto dell'<a href='https://autistici.org/underscore'>underscore hacklab</a> e uno dei
servizi di <a href='https://cisti.org'>cisti.org</a>.
h5 Cos'è gancio?
p.
Uno strumento di condivisione di eventi per comunità radicali.
Dentro gancio puoi trovare e inserire eventi.
Gancio, come tutto <a href='https://cisti.org'>cisti.org</a> è uno strumento
antisessista, antirazzista, antifascista e anticapitalista, riflettici quando
pubblichi un evento.
h5 Ok, ma cosa vuol dire gancio?
blockquote.
Se vieni a Torino e dici: "ehi, ci diamo un gancio alle 8?" nessuno si presenterà con i guantoni per fare a mazzate.
Darsi un gancio vuol dire beccarsi alle ore X in un posto Y
li A: a che ora è il gancio in radio per andare al presidio?
li B: non so ma domani non posso venire, ho gia' un gancio per caricare il bar.
br
h5 Contatti
p.
Hai scritto una nuova interfaccia per gancio? Vuoi aprire un nuovo nodo di gancio nella tua città?
C'è qualcosa che vorresti migliorare? Per contribuire i sorgenti sono liberi e disponibili
<a href='https://git.lattuga.net/cisti/gancio'>qui</a>. Aiuti e suggerimenti sono sempre benvenuti, puoi scriverci
su underscore chicciola autistici.org
div(v-html='$t("about")')
</template>

View file

@ -1,7 +1,6 @@
<template lang="pug">
el-card(v-loading='loading')
el-card
nuxt-link.float-right(to='/')
el-button
v-icon(name='times' color='red')
h5 {{edit?$t('common.edit_event'):$t('common.add_event')}}
el-form
@ -103,6 +102,9 @@ import { Message } from 'element-ui'
export default {
name: 'Add',
components: { List },
validate ({store}) {
return (store.state.auth.loggedIn || store.state.settings.allow_anon_event)
},
data() {
const month = moment().month()+1
const year = moment().year()
@ -120,7 +122,6 @@ export default {
date: null,
time: { start: '20:00', end: null },
edit: false,
loading: true,
}
},
name: 'newEvent',
@ -153,7 +154,6 @@ export default {
let event
try {
event = await $axios.$get('/event/'+ data.id)
console.error(event)
} catch (e) {
error({ statusCode: 404, message: 'Event not found!'})
return {}
@ -174,10 +174,9 @@ export default {
if (event.tags) {
data.event.tags = event.tags.map(t => t.tag)
}
data.loading = false
return data
}
return { loading: false }
return {}
},
computed: {
...mapState({
@ -221,6 +220,7 @@ export default {
.filter(e => e.multidate)
.map( e => ({ key: e.id, highlight: {}, dates: {
start: new Date(e.start_datetime*1000), end: new Date(e.end_datetime*1000) }})))
return attributes
},
disableAddress () {
return this.places_name.find(p => p.name === this.event.place.name)
@ -301,7 +301,6 @@ export default {
}
if (this.event.tags)
this.event.tags.forEach(tag => formData.append('tags[]', tag))
this.loading = true
try {
if (this.edit) {
await this.updateEvent(formData)
@ -310,10 +309,8 @@ export default {
}
this.updateMeta()
this.$router.replace('/')
Message({ type: 'success', message: this.$auth.loggedIn ? this.$t('event.added') : this.$t('event.added_anon')})
this.loading = false
Message({ type: 'success', showClose: true, message: this.$auth.loggedIn ? this.$t('event.added') : this.$t('event.added_anon')})
} catch (e) {
this.loading = false
console.error(e)
}
}

View file

@ -1,7 +1,6 @@
<template lang="pug">
el-card
nuxt-link.float-right(to='/')
el-button
v-icon(name='times' color='red')
h5 {{$t('common.admin')}}
@ -40,7 +39,7 @@
el-button(size='mini'
type='danger'
@click='delete_user(data.row)') {{$t('admin.delete_user')}}
no-ssr
el-pagination(:page-size='perPage' :currentPage.sync='userPage' :total='users.length')
//- PLACES
@ -60,6 +59,7 @@
template(slot-scope='data') {{data.row.name}}
el-table-column(:label="$t('common.address')")
template(slot-scope='data') {{data.row.address}}
no-ssr
el-pagination(:page-size='perPage' :currentPage.sync='placePage' :total='places.length')
//- EVENTS
@ -77,7 +77,7 @@
template(slot-scope='data')
el-button(type='primary' @click='confirm(data.row.id)' size='mini') {{$t('common.confirm')}}
el-button(type='success' @click='preview(data.row.id)' size='mini') {{$t('common.preview')}}
no-ssr
el-pagination(:page-size='perPage' :currentPage.sync='eventPage' :total='events.length')
//- SETTINGS
@ -96,6 +96,9 @@
p {{$t('admin.allow_registration_description')}}
el-form-item(:label="allow_registration?$t('common.disable'):$t('common.enable')")
el-switch(v-model='allow_registration')
p {{$t('admin.allow_anon_event')}}
el-form-item(:label="allow_anon_event?$t('common.disable'):$t('common.enable')")
el-switch(v-model='allow_anon_event')
</template>
@ -141,7 +144,6 @@ export default {
},
async asyncData ({ $axios, params, store }) {
try {
console.error(store)
const users = await $axios.$get('/users')
const events = await $axios.$get('/event/unconfirmed')
return { users, events, mastodon_instance: store.state.settings.mastodon_instance }
@ -152,12 +154,12 @@ export default {
computed: {
...mapState(['tags', 'places', 'settings']),
allow_registration: {
get () {
return this.settings.allow_registration
get () { return this.settings.allow_registration },
set (value) { this.setSetting({ key: 'allow_registration', value }) }
},
set (value) {
this.setSetting({ key: 'allow_registration', value })
}
allow_anon_event: {
get () { return this.settings.allow_anon_event },
set (value) { this.setSetting({ key: 'allow_anon_event', value })}
},
paginatedEvents () {
return this.events.slice((this.eventPage-1) * this.perPage,
@ -221,6 +223,7 @@ export default {
.then( () => this.$axios.delete(`/user/${user.id}`) )
.then( () => {
Message({
showClose: true,
type: 'success',
message: this.$t('admin.user_remove_ok')
})
@ -233,11 +236,14 @@ export default {
const user = await this.$axios.$post('/user', this.new_user)
this.new_user = { email: '', password: '', is_admin: false }
Message({
showClose: true,
type: 'success',
message: this.$t('admin.user_create_ok')
})
this.users.push(user)
} catch (e) {
Message({
showClose: true,
type: 'error',
message: this.$t('user.error_create') + e
})
@ -250,6 +256,7 @@ export default {
this.loading = false
Message({
message: this.$t('event.confirmed'),
showClose: true,
type: 'success'
})
this.events = this.events.filter(e => e.id !== id)

View file

@ -2,8 +2,7 @@
el-card#eventDetail(v-loading='!loaded')
//- close button
nuxt-link.float-right(to='/')
el-button(type='danger' plain)
v-icon(name='times')
v-icon(name='times' color='red')
div(v-if='!event')
h5 {{$t('event.not_found')}}
@ -13,10 +12,10 @@
h5.text-center {{event.title}}
div.nextprev
nuxt-link(v-if='prev' :to='`/event/${prev.id}`')
el-button(round type='success')
el-button( type='success' size='mini')
v-icon(name='chevron-left')
nuxt-link.float-right(v-if='next' :to='`/event/${next.id}`')
el-button(round type='success')
el-button(type='success' size='mini')
v-icon(name='chevron-right')
//- image
@ -43,18 +42,20 @@
//- comments
.card-body(v-if='event.activitypub_id && settings')
strong {{$t('common.related')}} -
a(:href='`https://mastodon.cisti.org/web/statuses/${event.activitypub_id}`') {{$t('common.add')}}
a(:href='`https://${settings.mastodon_instance}/web/statuses/${event.activitypub_id}`') {{$t('common.add')}}
.card-header(v-for='comment in event.comments' :key='comment.id')
img.avatar(:src='comment.data.last_status.account.avatar')
strong {{comment.author}}
a.float-right(:href='comment.data.last_status.url')
//- a.float-right(:href='comment.data.last_status.url')
a.float-right(:href='`https://${settings.mastodon_instance}/web/statuses/${comment.data.last_status.id}`')
small {{comment.data.last_status.created_at|datetime}}
div.mt-1(v-html='comment_filter(comment.text)')
img(v-for='img in comment.data.last_status.media_attachments' :src='img.preview_url')
div.mt-1(v-html='comment_filter(comment.data.last_status.content)')
img(v-for='img in comment.data.last_status.media_attachments' :src='img.url')
</template>
<script>
import { mapState, mapActions, mapGetters } from 'vuex'
import { MessageBox } from 'element-ui'
export default {
name: 'Event',
@ -147,9 +148,13 @@ export default {
},
async remove () {
try {
await MessageBox.confirm(this.$t('event.remove_confirmation'), this.$t('common.confirm'), {
confirmButtonText: this.$t('common.ok'),
cancelButtonText: this.$t('common.cancel'),
type: 'error'})
await this.$axios.delete(`/user/event/${this.id}`)
this.delEvent(Number(this.id))
this.$router.back()
this.$router.replace("/")
} catch (e) {
console.error(e)
}
@ -184,7 +189,8 @@ export default {
}
h5 {
font-size: 1.4em;
font-size: 2em;
font-weight: 600;
min-height: 40px;
}

View file

@ -2,11 +2,9 @@
el-card
nuxt-link.float-right(to='/')
el-button
v-icon(name='times' color='red')
h5 {{$t('common.export')}}
p {{$t('export.intro')}}
Search
//- li(v-if='filters.tags.length') {{$t('common.tags')}}:
@ -71,28 +69,28 @@ export default {
components: { List, Search },
data () {
return {
type: 'email',
type: 'feed',
notification: { email: '' },
list: { title: 'Gancio' },
}
},
// filters,
methods: {
// TODO
async add_notification () {
if (!this.notification.email){
Message({message:'Inserisci una mail', type: 'error'})
Message({message:'Inserisci una mail', showClose: true, type: 'error'})
// return this.$refs.email.focus()
}
// await api.addNotification({ ...this.notification, filters: this.filters})
// this.$refs.modal.hide()
Message({message: this.$t('email_notification_activated'), type: 'success'})
Message({message: this.$t('email_notification_activated'), showClose: true, type: 'success'})
},
imgPath (event) {
return event.image_path && event.image_path
},
},
computed: {
...mapState(['filters', 'events']),
...mapState(['filters', 'events', 'settings']),
...mapGetters(['filteredEvents']),
listScript () {
const params = []
@ -108,7 +106,7 @@ export default {
params.push(`tags=${this.filters.tags}`)
}
return `<iframe src="${this.$axios.defaults.baseURL}/embed/list?${params.join('&')}"></iframe>`
return `<iframe src="${this.settings.baseurl}/embed/list?${params.join('&')}"></iframe>`
},
link () {
const tags = this.filters.tags.join(',')
@ -124,7 +122,7 @@ export default {
}
}
return `${this.$axios.defaults.baseURL}/api/export/${this.type}${query}`
return `${this.settings.baseurl}/api/export/${this.type}${query}`
},
showLink () {
return (['feed', 'ics'].indexOf(this.type)>-1)

View file

@ -1,11 +1,9 @@
<template lang='pug'>
el-card
nuxt-link.float-right(to='/')
v-icon(name='times' color='red')
h5 {{$t('common.login')}}
el-form(v-loading='loading' method='POST' action='/api/auth/login')
el-form(v-loading='loading')
p(v-html="$t('login.description')")
el-input.mb-2(v-model='email' type='email' name='email'
@ -16,7 +14,7 @@
type='password' :placeholder='$t("common.password")')
v-icon(name='lock' slot='prepend')
el-button.mr-1(plain type="success" native-type='submit'
el-button.mr-1(plain type="success"
:disabled='disabled' @click='submit') {{$t('common.login')}}
nuxt-link(to='/register' v-if='settings.allow_registration')
@ -50,7 +48,7 @@ export default {
...mapActions(['login']),
async forgot () {
if (!this.email) {
Message({ message: this.$t('login.insert_email'), type: 'error' })
Message({ message: this.$t('login.insert_email'), showClose:true, type: 'error' })
this.$refs.email.focus()
return
}
@ -60,15 +58,16 @@ export default {
Message({ message: this.$t('login.check_email'), type: 'success' })
},
async submit (e) {
console.error('dentro submit', e)
e.preventDefault()
try {
this.loading = true
await this.$auth.loginWith('local', { data: { email: this.email, password: this.password } })
this.loading = false
Message({ message: this.$t('login.ok'), type: 'success' })
Message({ message: this.$t('login.ok'), showClose: true, type: 'success' })
} catch (e) {
e = get(e, 'response.data.message', e)
Message({ message: this.$t('login.error') + this.$t(e), type: 'error' })
Message({ message: this.$t('login.error') + this.$t(e), showClose: true, type: 'error' })
this.loading = false
return
}

View file

@ -37,11 +37,13 @@ export default {
try {
const res = await this.$axios.$post('/user/recover_password', { recover_code: this.code, password: this.new_password })
Message({
showClose: true,
type: 'success',
message: this.$t('Password changed!')
})
} catch(e) {
Message({
showClose: true,
type: 'warning',
message: e
})

View file

@ -50,6 +50,7 @@ export default {
try {
const { user } = await this.$axios.$post('/user/register', this.user)
Message({
showClose: true,
message: this.$t(`register.${user.is_admin ? 'admin_' : ''}complete`),
type: 'success'
})
@ -57,6 +58,7 @@ export default {
} catch (e) {
const error = get(e, 'e.response.data.errors[0].message', String(e))
Message({
showClose: true,
message: this.$t('register.error') + this.$t(error),
type: 'error'
})

View file

@ -1,7 +1,6 @@
<template lang="pug">
el-card
nuxt-link.float-right(to='/')
el-button
v-icon(name='times' color='red')
h5 {{$t('common.settings')}}
@ -35,7 +34,7 @@ export default {
const user_data = { id : this.$auth.user.id, password: this.password }
try {
const user = await this.$axios.$put('/user', user_data)
Message({ message: this.$t('settings.password_updated'), type: 'success' })
Message({ message: this.$t('settings.password_updated'), showClose: true, type: 'success' })
this.$router.replace('/')
} catch (e) {
console.log(e)

View file

@ -1,13 +1,5 @@
export default function({ $axios, store }) {
if (process.server) {
console.error('dentro il server ', store.settings )
// $axios.defaults.baseurl =
} else {
// const protocol = window.location.protocol
// const hostname = window.location.hostname
// const port = 8000
// const url = `${protocol}//${hostname}:${port}`
if (process.client) {
$axios.defaults.baseURL = window.location.origin + '/api'
console.error('dentro il client !')
}
}

View file

@ -10,8 +10,8 @@ const locales = {
en: require('element-ui/lib/locale/lang/en')
}
export default ({ app }) => {
locale.use(locales[app.i18n.locale])
export default ({ app, store }) => {
locale.use(locales[store.state.locale])
Vue.use(Button)
Vue.use(Collapse)
Vue.use(CollapseItem)

View file

@ -2,8 +2,8 @@ import Vue from 'vue'
import moment from 'dayjs'
import 'dayjs/locale/it'
export default ({ app }) => {
moment.locale(app.i18n.locale)
export default ({ app, store }) => {
moment.locale(store.state.locale)
Vue.filter('linkify', value => value.replace(/(https?:\/\/[^\s]+)/g, '<a href="$1">$1</a>'))
Vue.filter('datetime', value => moment(value).format('ddd, D MMMM HH:mm'))
Vue.filter('short_datetime', value => moment(value).format('D/MM HH:mm'))

View file

@ -1,6 +1,7 @@
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import it from '@/locales/it.js'
import en from '@/locales/en.js'
Vue.use(VueI18n)
@ -8,10 +9,10 @@ export default ({ app, store }) => {
// Set i18n instance on app
// This way we can use it in middleware and pages asyncData/fetch
app.i18n = new VueI18n({
locale: process.env.locale,
fallbackLocale: process.env.locale,
locale: store.state.locale,
fallbackLocale: 'it',
messages: {
it
it, en
}
})
}

View file

@ -5,15 +5,17 @@ const { event: Event, comment: Comment } = require('../models')
const config = require('config')
const Mastodon = require('mastodon-api')
const settingsController = require('./settings')
const get = require('lodash/get')
const botController = {
bot: null,
async initialize() {
if (!settings.mastodon_auth || !settings.mastodon_auth.access_token) return
const mastodon_auth = settings.mastodon_auth
const access_token = get(settingsController.secretSettings, 'mastodon_auth.access_token')
const instance = get(settingsController.settings, 'mastodon_instance')
if (!access_token || !instance) return
botController.bot = new Mastodon({
access_token: mastodon_auth.access_token,
api_url: `https://${mastodon_auth.instance}/api/v1`
access_token,
api_url: `https://${instance}/api/v1`
})
const listener = botController.bot.stream('/streaming/direct')
listener.on('message', botController.message)
@ -38,10 +40,8 @@ const botController = {
// listener.on('error', botController.error)
// botController.bots.push({ email: user.email, bot })
},
async post(mastodon_auth, event) {
const { access_token, instance } = mastodon_auth
const bot = new Mastodon({ access_token, api_url: `https://${instance}/api/v1/` })
const status = `${event.title} @ ${event.place.name} ${moment(event.start_datetime).format('ddd, D MMMM HH:mm')} -
async post(instance, access_token, event) {
const status = `${event.title} @${event.place.name} ${moment(event.start_datetime).format('ddd, D MMMM HH:mm')} -
${event.description.length > 200 ? event.description.substr(0, 200) + '...' : event.description} - ${event.tags.map(t => '#' + t.tag).join(' ')} ${config.baseurl}/event/${event.id}`
let media
@ -51,42 +51,30 @@ ${event.description.length > 200 ? event.description.substr(0, 200) + '...' : ev
media = await bot.post('media', { file: fs.createReadStream(file) })
}
}
return bot.post('statuses', { status, visibility: 'direct', media_ids: media ? [media.data.id] : [] })
return botController.bot.post('/statuses', { status, visibility: 'direct', media_ids: media ? [media.data.id] : [] })
},
// TOFIX: enable message deletion
async message(msg) {
const replyid = msg.data.in_reply_to_id || msg.data.last_status.in_reply_to_id
if (!replyid) return
const event = await Event.findOne({ where: { activitypub_id: replyid } })
let event = await Event.findOne({ where: { activitypub_id: replyid } })
if (!event) {
// check for comment..
// const comment = await Comment.findOne( {where: { }})
return
const comment = await Comment.findOne( { include: [Event], where: { activitypub_id: replyid }})
if (!comment) return
event = comment.event
}
const comment = await Comment.create({
activitypub_id: msg.data.last_status.id,
// text: msg.data.last_status.content,
data: msg.data
// author: msg.data.accounts[0].username
data: msg.data,
eventId: event.id
})
event.addComment(comment)
// const comment = await Comment.findOne( { where: {activitypub_id: msg.data.in_reply_to}} )
// console.log('dentro message ', data)
// add comment to specified event
// let comment
// if (!event) {
// const comment = await Comment.findOne({where: {activitypub_id: req.body.id}, include: Event})
// event = comment.event
// }
// const comment = new Comment(req.body)
// event.addComment(comment)
},
error(err) {
console.log('error ', err)
}
}
return setTimeout(botController.initialize, 2000)
// botController.initialize()
setTimeout(botController.initialize, 5000)
module.exports = botController

View file

@ -95,7 +95,9 @@ const eventController = {
],
order: [ [Comment, 'id', 'DESC'], [Tag, 'weigth', 'DESC'] ]
})
if (event) {
event.activitypub_id = event.activitypub_id ? String(event.activitypub_id) : null
res.json(event)
} else {
res.sendStatus(404)

View file

@ -1,20 +1,23 @@
const Mastodon = require('mastodon-api')
const { setting: Setting } = require('../models')
const config = require('config')
const settingsController = {
settings: null,
secretSettings: null,
settings: { initialized: false },
secretSettings: {},
// initialize instance settings from db
async init (req, res, next) {
if (!settingsController.settings) {
async initialize () {
if (!settingsController.settings.initialized) {
const settings = await Setting.findAll()
settingsController.settings = {}
settingsController.secretSettings = {}
settings.forEach( s => settingsController[s.is_secret?'secretSettings':'settings'][s.key] = s.value)
settingsController.settings.initialized = true
settings.forEach( s => {
if (s.is_secret) {
settingsController.secretSettings[s.key] = s.value
} else {
settingsController.settings[s.key] = s.value
}
})
}
next()
},
async set(key, value, is_secret=false) {
@ -26,8 +29,6 @@ const settingsController = {
if (!created) return settings.update({ value, is_secret })
})
settingsController[is_secret?'secretSettings':'settings'][key]=value
console.error('settings ', settingsController.settings)
console.error('settings controller ', settingsController.secretSettings)
return true
} catch(e) {
console.error(e)
@ -43,12 +44,16 @@ const settingsController = {
},
getAllRequest(req, res) {
res.json(settingsController.settings)
// get public settings and public configuration
const settings = {
...settingsController.settings,
baseurl: config.baseurl
}
res.json(settings)
},
async getAuthURL(req, res) {
const instance = req.body.instance
console.error('DENTRO GET AUTH URL ', instance)
const callback = `${config.baseurl}/api/settings/oauth`
const { client_id, client_secret } = await Mastodon.createOAuthApp(`https://${instance}/api/v1/apps`,
'gancio', 'read write', callback)
@ -72,13 +77,14 @@ const settingsController = {
`https://${instance}`, callback)
const mastodon_auth = { client_id, client_secret, access_token }
await settingsController.set('mastodon_auth', mastodon_auth, true)
const botController = require('./bot')
botController.initialize()
res.redirect('/admin')
} catch (e) {
res.json(e)
}
},
}
setTimeout(settingsController.initialize, 200)
module.exports = settingsController

View file

@ -7,8 +7,8 @@ const jsonwebtoken = require('jsonwebtoken')
const config = require('config')
const mail = require('../mail')
const { user: User, event: Event, tag: Tag, place: Place } = require('../models')
const eventController = require('./event')
const settingsController = require('./settings')
const notifier = require('../../notifier')
const userController = {
async login(req, res) {
@ -76,7 +76,7 @@ const userController = {
const eventDetails = {
title: body.title,
description: body.description.replace(/(<([^>]+)>)/ig, ''),
description: body.description ? body.description.replace(/(<([^>]+)>)/ig, '') : '',
multidate: body.multidate,
start_datetime: body.start_datetime,
end_datetime: body.end_datetime,
@ -108,14 +108,19 @@ const userController = {
const tags = await Tag.findAll({ where: { tag: { [Op.in]: body.tags } } })
await event.addTags(tags)
}
if (req.user) await req.user.addEvent(event)
event = await Event.findByPk(event.id, { include: [User, Tag, Place] })
if (req.user) {
await req.user.addEvent(event)
await event.setUser(req.user)
}
// insert notifications
const notifications = await eventController.getNotifications(event)
await event.setNotifications(notifications)
// event = await Event.findByPk(event.id, { include: [Tag, Place] })
// send response to client
res.json(event)
// send notification (mastodon/email/confirmation)
notifier.notifyEvent(event.id)
return res.json(event)
},
async updateEvent(req, res) {
@ -155,8 +160,8 @@ const userController = {
const tags = await Tag.findAll({ where: { tag: { [Op.in]: body.tags } } })
await event.addTags(tags)
}
const newEvent = await Event.findByPk(event.id, { include: [User, Tag, Place] })
return res.json(newEvent)
const newEvent = await Event.findByPk(event.id, { include: [Tag, Place] })
res.json(newEvent)
},
async forgotPassword(req, res) {

View file

@ -18,7 +18,7 @@ const api = express.Router()
api.use(cookieParser())
api.use(bodyParser.urlencoded({ extended: false }))
api.use(bodyParser.json())
api.use(settingsController.init)
// api.use(settingsController.init)
const jwt = expressJwt({
secret: config.secret,

View file

@ -1,7 +1,7 @@
'use strict'
module.exports = (sequelize, DataTypes) => {
const comment = sequelize.define('comment', {
activitypub_id: DataTypes.BIGINT,
activitypub_id: DataTypes.STRING(18),
data: DataTypes.JSON
}, {})
comment.associate = function (models) {

View file

@ -16,9 +16,9 @@ module.exports = (sequelize, DataTypes) => {
image_path: DataTypes.STRING,
is_visible: DataTypes.BOOLEAN,
activitypub_id: {
type: DataTypes.BIGINT,
type: DataTypes.STRING(18),
index: true
}
},
}, {})
event.associate = function (models) {
event.belongsTo(models.place)

View file

@ -1,6 +1,6 @@
'use strict'
module.exports = (sequelize, DataTypes) => {
const eventNotification = sequelize.define('eventNotification', {
const event_notification = sequelize.define('event_notification', {
status: {
type: DataTypes.ENUM,
values: ['new', 'sent', 'error'],
@ -10,5 +10,5 @@ module.exports = (sequelize, DataTypes) => {
}
}, {})
return eventNotification
return event_notification
}

View file

@ -1,10 +1,13 @@
#!/usr/bin/env node
process.env.NODE_ENV = "production"
const path = require('path')
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 path = require('path')
const fs = require('fs')
const sequelize = require('sequelize')
@ -138,8 +141,8 @@ async function cli(args) {
consola.info(`Cool! You're going to setup gancio on this machine.`)
const config = await setupQuestionnaire()
await firstrun.setup(config, options.config)
consola.info(`This is your configuration, run "gancio --install" or edit ${options.config} to modify it: `)
consola.info(JSON.stringify(config, null, 2))
consola.info(`You can edit '${options.config}' to modify your configuration. `)
consola.info(`- Run "gancio --config ${options.config}"`)
process.exit(0)
}

View file

@ -34,10 +34,17 @@ module.exports = {
is_active: true
})
// set default settings
consola.info('Set default settings')
const settings = require('./api/controller/settings')
settings.set('enable_registration', true)
settings.set('allow_anon_event', true)
settings.set('allow_mastodon_association', true)
await settings.set('allow_registration', true)
await settings.set('allow_anon_event', true)
// add default notification
consola.info('Add default notification')
// send confirmed event to mastodon
await db.notification.create({ type: 'mastodon', filters: { is_visible: true } })
// await notification.create({ type: 'mastodon', filters: { is_visible: true } })
}
}

View file

@ -1,14 +1,18 @@
const mail = require('./api/mail')
const bot = require('./api/controller/bot')
const settingsController = require('./api/controller/settings')
const eventController = require()
const config = require('config')
const eventController = require('./api/controller/event')
const get = require('lodash/get')
const { event: Event, notification: Notification, eventNotification: EventNotification,
const { event: Event, notification: Notification, event_notification: EventNotification,
user: User, place: Place, tag: Tag } = require('./api/models')
const notifier = {
async sendNotification(notification, event, eventNotification) {
async sendNotification(notification, event) {
console.error('dentro sendNotification ', settingsController.settings, notification.type)
const access_token = get(settingsController.secretSettings, 'mastodon_auth.access_token')
const instance = get(settingsController.settings, 'mastodon_instance')
const promises = []
switch (notification.type) {
case 'mail':
@ -19,26 +23,39 @@ const notifier = {
return mail.send(admin_emails, 'event', { event, to_confirm: true, notification })
case 'mastodon':
// instance publish
if (settings.mastodon_auth.instance && settings.mastodon_auth.access_token) {
const b = bot.post(settings.mastodon_auth, event).then(b => {
if (instance && access_token) {
const b = bot.post(instance, access_token, event).then(b => {
console.error(b)
event.activitypub_id = b.data.id
event.activitypub_ids.push(b.data.id)
return event.save()
}).catch(e => {
console.error("ERRORE !! ", e)
})
promises.push(b)
}
}
return Promise.all(promises)
},
async notifyEvent(event) {
async notifyEvent(eventId) {
const event = await Event.findByPk(eventId, {
include: [ Tag, Place, User ]
})
// insert notifications
const notifications = await eventController.getNotifications(event)
await event.setNotifications(notifications)
const a = await event.setNotifications(notifications)
const promises = notifications.map(async e => {
const eventNotifications = await EventNotification.findAll({
where: {
notificationId: notifications.map(n=>n.id),
status: 'new'
}
})
const promises = eventNotifications.map(async e => {
const notification = await Notification.findByPk(e.notificationId)
try {
await sendNotification(notification, event, e)
await notifier.sendNotification(notification, event)
e.status = 'sent'
} catch (err) {
console.error(err)
@ -80,3 +97,4 @@ const notifier = {
// startLoop(26000)
module.exports = notifier
// export default notifier

View file

@ -3,11 +3,14 @@ import intersection from 'lodash/intersection'
import map from 'lodash/map'
export const state = () => ({
config: {},
// config: {},
locale: '',
events: [],
tags: [],
places: [],
settings: {},
settings: {
},
filters: {
tags: [],
places: [],
@ -99,18 +102,21 @@ export const mutations = {
setSetting(state, setting) {
state.settings[setting.key] = setting.value
},
setConfig(state, config) {
state.config = config
setLocale(state, locale) {
state.locale = locale
}
}
export const actions = {
// this method is called server side only for each request
// we use it to get configuration from db
async nuxtServerInit ({ commit }, { app } ) {
async nuxtServerInit ({ commit }, { app, req } ) {
const settings = await app.$axios.$get('/settings')
console.error('dentro NUXST SERVER INIT', settings)
return commit('setSettings', settings)
commit('setSettings', settings)
console.error('NUXT SETTINGS', settings)
const lang = req.acceptsLanguages('en', 'it')
commit('setLocale', lang || 'it')
},
async updateEvents({ commit }, page) {
const events = await this.$axios.$get(`/event/${page.month - 1}/${page.year}`)
@ -148,7 +154,4 @@ export const actions = {
await this.$axios.$post('/settings', setting )
commit('setSetting', setting)
},
setConfig({ commit }, config) {
commit('setConfig', config)
}
}