mille storie

commenti da mastodon, widget con custom widget test...
This commit is contained in:
lesion
2019-04-29 00:27:29 +02:00
parent 3b80dd5f73
commit ac5ef6e324
34 changed files with 573 additions and 275 deletions

View File

@@ -1,43 +1,30 @@
const jwt = require('jsonwebtoken')
const { Op } = require('sequelize')
const config = require('./config')
const User = require('./models/user')
const Auth = {
fillUser(req, res, next) {
const token =
req.body.token || req.params.token || req.headers.authorization
if (!token) return next()
jwt.verify(token, config.secret, async (err, decoded) => {
if (err) return next()
req.user = await User.findOne({
where: { email: { [Op.eq]: decoded.email }, is_active: true }
})
next()
async fillUser(req, res, next) {
if (!req.user) return next(new Error('ERROR! No user'))
req.user = await User.findOne({
where: { id: { [Op.eq]: req.user.id }, is_active: true }
})
next()
},
isAuth(req, res, next) {
const token =
(req.body && req.body.token) ||
req.params.token ||
req.headers.authorization
if (!token) return res.status(403).send({ message: 'Token not found' })
jwt.verify(token, config.secret, async (err, decoded) => {
if (err) {
return res
.status(403)
.send({ message: 'Failed to authenticate token ' + err })
}
req.user = await User.findOne({
where: { email: { [Op.eq]: decoded.email }, is_active: true }
})
if (!req.user) {
return res
.status(403)
.send({ message: 'Failed to authenticate token ' + err })
}
next()
async isAuth(req, res, next) {
if (!req.user) {
return res
.status(403)
.send({ message: 'Failed to authenticate token ' })
}
req.user = await User.findOne({
where: { id: { [Op.eq]: req.user.id }, is_active: true }
})
if (!req.user) {
return res
.status(403)
.send({ message: 'Failed to authenticate token ' + err })
}
next()
},
isAdmin(req, res, next) {
if (req.user.is_admin && req.user.is_active) return next()

View File

@@ -6,11 +6,11 @@ module.exports = {
locale: process.env.LOCALE || 'it',
title: process.env.TITLE || 'GANCIO',
description: process.env.DESCRIPTION || 'A calendar for radical communities',
baseurl: process.env.BASE_URL || 'http://localhost:8080',
baseurl: process.env.BASE_URL || 'http://localhost:3000',
apiurl:
env === 'production'
? process.env.BASE_URL + '/api'
: 'http://localhost:9000',
: 'http://localhost:3000/api',
db,
admin: process.env.ADMIN_EMAIL,

View File

@@ -1,17 +1,29 @@
// const { User, Event, Comment, Tag } = require('../model')
const { User, Event, Comment, Tag } = require('../model')
const config = require('../config')
const Mastodon = require('mastodon-api')
// const Sequelize = require('sequelize')
// const Op = Sequelize.Op
const settingsController = require('./settings')
const fs = require('fs')
const path = require('path')
const moment = require('moment')
moment.locale('it')
const botController = {
bots: [],
// async initialize () {
// console.log('initialize bots')
bot: null,
async initialize () {
console.log('initialize bot')
const settings = await settingsController.settings()
if (!settings.mastodon_auth) return
const mastodon_auth = settings.mastodon_auth
console.log('instance ', `https://${mastodon_auth.instance}/api/v1/`)
botController.bot = new Mastodon({
access_token: mastodon_auth.access_token,
api_url: `https://${mastodon_auth.instance}/api/v1`
})
const listener = botController.bot.stream('/streaming/direct')
listener.on('message', botController.message)
listener.on('error', botController.error)
// const botUsers = await User.findAll({ where: { mastodon_auth: { [Op.ne]: null } } })
// console.log(botUsers)
// botController.bots = botUsers.map(user => {
@@ -21,7 +33,6 @@ const botController = {
// const bot = new Mastodon({ access_token, api_url: `https://${user.mastodon_instance}/api/v1/` })
// const listener = bot.stream('streaming/direct')
// listener.on('message', botController.message)
// listener.on('error', botController.error)
// return { email: user.email, bot }
// })
// console.log(botController.bots)
@@ -32,8 +43,9 @@ const botController = {
// listener.on('message', botController.message)
// listener.on('error', botController.error)
// botController.bots.push({ email: user.email, bot })
// },
},
async post (mastodon_auth, event) {
console.log('dentro post!')
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')} -
@@ -41,28 +53,30 @@ ${event.description.length > 200 ? event.description.substr(0, 200) + '...' : ev
let media
if (event.image_path) {
const file = path.join(__dirname, '..', '..', 'uploads', event.image_path)
const file = path.join(__dirname, '..', '..', '..', 'uploads', event.image_path)
if (fs.statSync(file)) {
media = await bot.post('media', { file: fs.createReadStream(file) })
}
}
return bot.post('statuses', { status, visibility: 'public', media_ids: media ? [media.data.id] : [] })
}
// async message (msg) {
// console.log(msg)
// console.log(msg.data.accounts)
// 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 } })
// if (!event) {
// check for comment..
// const comment = await Comment.findOne( {where: { }})
// }
// const comment = await Comment.create({activitypub_id: msg.data.last_status.id, text: msg.data.last_status.content, author: msg.data.accounts[0].username })
// event.addComment(comment)
// console.log(event)
// const comment = await Comment.findOne( { where: {activitypub_id: msg.data.in_reply_to}} )
// console.log('dentro message ', data)
return bot.post('statuses', { status, visibility: 'direct', media_ids: media ? [media.data.id] : [] })
},
async message (msg) {
console.log(msg)
console.log(msg.data.accounts)
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 } })
if (!event) {
console.error('associated event not found !')
// check for comment..
// const comment = await Comment.findOne( {where: { }})
return
}
const comment = await Comment.create({activitypub_id: msg.data.last_status.id, text: msg.data.last_status.content, author: msg.data.accounts[0].username })
event.addComment(comment)
console.log(event)
// 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
@@ -72,11 +86,11 @@ ${event.description.length > 200 ? event.description.substr(0, 200) + '...' : ev
// }
// const comment = new Comment(req.body)
// event.addComment(comment)
// },
// error (err) {
// console.log('error ', err)
// }
},
error (err) {
console.log('error ', err)
}
}
// setTimeout(botController.initialize, 2000)
setTimeout(botController.initialize, 2000)
module.exports = botController

View File

@@ -136,7 +136,6 @@ const eventController = {
},
async getAll(req, res) {
console.log('sono qui dentro !')
// this is due how v-calendar shows dates
const start = moment().year(req.params.year).month(req.params.month)
.startOf('month').startOf('isoWeek')
@@ -145,20 +144,20 @@ const eventController = {
if (shownDays <= 34) end = end.add(1, 'week')
end = end.endOf('isoWeek')
const events = await Event.findAll({
// where: {
// is_visible: true,
// [Op.and]: [
// { start_datetime: { [Op.gte]: start } },
// { start_datetime: { [Op.lte]: end } }
// ]
// },
// order: [['start_datetime', 'ASC']],
// include: [
// { model: User, required: false },
// Comment,
// Tag,
// { model: Place, required: false }
// ]
where: {
is_visible: true,
[Op.and]: [
{ start_datetime: { [Op.gte]: start } },
{ start_datetime: { [Op.lte]: end } }
]
},
order: [['start_datetime', 'ASC']],
include: [
{ model: User, required: false },
Comment,
Tag,
{ model: Place, required: false }
]
})
// console.log(events)
res.json(events)

View File

@@ -32,6 +32,8 @@ const exportController = {
return exportController.feed(res, events.slice(0, 20))
case 'ics':
return exportController.ics(res, events)
case 'json':
return res.json(events)
}
},

View File

@@ -27,12 +27,12 @@ const userController = {
} else {
// if user is found and password is right
// create a token
const accessToken = jsonwebtoken.sign({ user:
const accessToken = jsonwebtoken.sign(
{
id: user.id,
email: user.email,
scope: [user.is_admin ? 'admin' : 'user']
}},
},
config.secret
)

View File

@@ -7,7 +7,7 @@ const userController = require('./controller/user')
const settingsController = require('./controller/settings')
const config = require('./config')
// const botController = require('./controller/bot')
const botController = require('./controller/bot')
const jwt = require('express-jwt')({secret: config.secret})
const storage = require('./storage')({
@@ -20,7 +20,7 @@ const api = express.Router()
// AUTH
api.post('/auth/login', userController.login)
api.post('/auth/logout', userController.logout)
api.get('/auth/user', jwt, userController.current)
api.get('/auth/user', jwt, fillUser, userController.current)
api.post('/user/recover', userController.forgotPassword)
api.post('/user/check_recover_code', userController.checkRecoverCode)
@@ -33,32 +33,32 @@ api
// get current user
// .get(isAuth, userController.current)
// update user (eg. confirm)
.put(isAuth, isAdmin, userController.update)
.put(jwt, isAuth, isAdmin, userController.update)
// get all users
api.get('/users', isAuth, isAdmin, userController.getAll)
api.get('/users', jwt, isAuth, isAdmin, userController.getAll)
// update a tag (modify color)
api.put('/tag', isAuth, isAdmin, eventController.updateTag)
api.put('/tag', jwt, isAuth, isAdmin, eventController.updateTag)
// update a place (modify address..)
api.put('/place', isAuth, isAdmin, eventController.updatePlace)
api.put('/place', jwt, isAuth, isAdmin, eventController.updatePlace)
api
.route('/user/event')
// add event
.post(fillUser, upload.single('image'), userController.addEvent)
.post(jwt, fillUser, upload.single('image'), userController.addEvent)
// update event
.put(isAuth, upload.single('image'), userController.updateEvent)
.put(jwt, isAuth, upload.single('image'), userController.updateEvent)
// remove event
api.delete('/user/event/:id', isAuth, userController.delEvent)
api.delete('/user/event/:id', jwt, isAuth, userController.delEvent)
// get tags/places
api.get('/event/meta', eventController.getMeta)
// get unconfirmed events
api.get('/event/unconfirmed', isAuth, isAdmin, eventController.getUnconfirmed)
api.get('/event/unconfirmed', jwt, isAuth, isAdmin, eventController.getUnconfirmed)
// add event notification
api.post('/event/notification', eventController.addNotification)
@@ -71,22 +71,17 @@ api.post('/settings', settingsController.setAdminSetting)
api.get('/event/:event_id', eventController.get)
// confirm event
api.get('/event/confirm/:event_id', isAuth, isAdmin, eventController.confirm)
api.get(
'/event/unconfirm/:event_id',
isAuth,
isAdmin,
eventController.unconfirm
)
api.get('/event/confirm/:event_id', jwt, isAuth, isAdmin, eventController.confirm)
api.get('/event/unconfirm/:event_id', jwt, isAuth, isAdmin, eventController.unconfirm)
// export events (rss/ics)
api.get('/export/:type', exportController.export)
// get events in this range
api.get('/event/:year/:month', eventController.getAll)
api.get('/event/:month/:year', eventController.getAll)
// mastodon oauth auth
api.post('/user/getauthurl', isAuth, userController.getAuthURL)
api.post('/user/code', isAuth, userController.code)
api.post('/user/getauthurl', jwt, isAuth, userController.getAuthURL)
api.post('/user/code', jwt, isAuth, userController.code)
module.exports = api

View File

@@ -9,8 +9,9 @@ const Event = db.define('event', {
start_datetime: { type: Sequelize.DATE, index: true },
end_datetime: { type: Sequelize.DATE, index: true },
image_path: Sequelize.STRING,
is_visible: Sequelize.BOOLEAN,
activitypub_id: { type: Sequelize.INTEGER, index: true },
is_visible: Sequelize.BOOLEAN
// activitypub_ids: { type: Sequelize.ARRAY, index}
})
const Tag = db.define('tag', {
@@ -20,6 +21,8 @@ const Tag = db.define('tag', {
const Comment = db.define('comment', {
activitypub_id: { type: Sequelize.INTEGER, index: true },
url: Sequelize.STRING,
media_attachments: { type: Sequelize.ARRAY(Sequelize.STRING) },
author: Sequelize.STRING,
text: Sequelize.STRING
})
@@ -63,10 +66,10 @@ Event.belongsTo(Place)
User.hasMany(Event)
Place.hasMany(Event)
// async function init() {
// await Notification.findOrCreate({ where: { type: 'mastodon', filters: { is_visible: true } } })
// await Notification.findOrCreate({ where: { type: 'admin_email', filters: { is_visible: false } } })
// }
async function init() {
await Notification.findOrCreate({ where: { type: 'mastodon', filters: { is_visible: true } } })
// await Notification.findOrCreate({ where: { type: 'admin_email', filters: { is_visible: false } } })
}
// init()
init()
module.exports = { Event, Comment, Tag, Place, Notification, EventNotification }

65
server/cron.js Normal file
View File

@@ -0,0 +1,65 @@
// const mail = require('./mail')
const bot = require('./api/controller/bot')
const settingsController = require('./api/controller/settings')
const config = require('./api/config.js')
const { Event, Notification, EventNotification,
User, Place, Tag } = require('./api/model')
let settings
async function sendNotification (notification, event, eventNotification) {
const promises = []
switch (notification.type) {
// case 'mail':
// return mail.send(notification.email, 'event', { event, config, notification })
// case 'admin_email':
// const admins = await User.findAll({ where: { is_admin: true } })
// const admin_emails = admins.map(admin => admin.email)
// 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 => {
console.log('ho postato admin post cose', b.data.id)
event.activitypub_id = b.data.id
return event.save()
})
promises.push(b)
}
// user publish
if (event.user && event.user.mastodon_auth && event.user.mastodon_auth.access_token) {
const b = bot.post(event.user.mastodon_auth, event).then(ret => {
event.activitypub_id = ret.id
return event.save()
})
promises.push(b)
}
break
}
return Promise.all(promises)
}
async function loop () {
settings = await settingsController.settings()
// get all event notification in queue
const eventNotifications = await EventNotification.findAll({ where: { status: 'new' } })
const promises = eventNotifications.map(async e => {
const event = await Event.findByPk(e.eventId, { include: [User, Place, Tag] })
if (!event.place) return
const notification = await Notification.findByPk(e.notificationId)
try {
await sendNotification(notification, event, e)
e.status = 'sent'
return e.save()
} catch (err) {
console.error(err)
e.status = 'error'
return e.save()
}
})
return Promise.all(promises)
}
setInterval(loop, 260000)
loop()

View File

@@ -3,6 +3,7 @@ const consola = require('consola')
const morgan = require('morgan')
const bodyParser = require('body-parser')
const cookieParser = require('cookie-parser')
const path = require('path')
const { Nuxt, Builder } = require('nuxt')
const app = express()
const cors = require('cors')
@@ -32,6 +33,7 @@ async function start() {
// Give nuxt middleware to express
app.use(cors(corsConfig))
app.use(morgan('dev'))
app.use('/media/', express.static(path.join(__dirname, '..', 'uploads')))
app.use(cookieParser())
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())