start with nuxt

This commit is contained in:
lesion
2019-04-03 00:25:12 +02:00
parent afa6ad2a6b
commit 88b43f9bb1
54 changed files with 2742 additions and 0 deletions

View File

@@ -0,0 +1,82 @@
// 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 fs = require('fs')
const path = require('path')
const moment = require('moment')
moment.locale('it')
const botController = {
bots: [],
// async initialize () {
// console.log('initialize bots')
// const botUsers = await User.findAll({ where: { mastodon_auth: { [Op.ne]: null } } })
// console.log(botUsers)
// botController.bots = botUsers.map(user => {
// console.log('initialize bot ', user.name)
// console.log('.. ', user.mastodon_auth)
// const { client_id, client_secret, access_token } = user.mastodon_auth
// 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)
// },
// add (user, token) {
// const bot = new Mastodon({ access_token: user.mastodon_auth.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)
// 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')} -
${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
if (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)
// 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)
// }
}
// setTimeout(botController.initialize, 2000)
module.exports = botController

View File

@@ -0,0 +1,169 @@
const crypto = require('crypto')
const moment = require('moment')
const { Op } = require('sequelize')
const lodash = require('lodash')
const { User, Event, Comment, Tag, Place, Notification } = require('../model')
const eventController = {
async addComment(req, res) {
// comment could be added to an event or to another comment
let event = await Event.findOne({ where: { activitypub_id: { [Op.eq]: req.body.id } } })
if (!event) {
const comment = await Comment.findOne({ where: { activitypub_id: { [Op.eq]: req.body.id } }, include: Event })
event = comment.event
}
const comment = new Comment(req.body)
event.addComment(comment)
res.json(comment)
},
async getMeta(req, res) {
const places = await Place.findAll()
const tags = await Tag.findAll()
res.json({ tags, places })
},
async getNotifications(event) {
function match(event, filters) {
// matches if no filter specified
if (!filters) return true
// check for visibility
if (typeof filters.is_visible !== 'undefined' && filters.is_visible !== event.is_visible) return false
if (!filters.tags && !filters.places) return true
if (!filters.tags.length && !filters.places.length) return true
if (filters.tags.length) {
const m = lodash.intersection(event.tags.map(t => t.tag), filters.tags)
if (m.length > 0) return true
}
if (filters.places.length) {
if (filters.places.find(p => p === event.place.name)) {
return true
}
}
}
const notifications = await Notification.findAll()
// get notification that matches with selected event
return notifications.filter(notification => match(event, notification.filters))
},
async updateTag(req, res) {
const tag = await Tag.findByPk(req.body.tag)
if (tag) {
res.json(await tag.update(req.body))
} else {
res.sendStatus(404)
}
},
async updatePlace(req, res) {
const place = await Place.findByPk(req.body.id)
await place.update(req.body)
res.json(place)
},
async get(req, res) {
const id = req.params.event_id
const event = await Event.findByPk(id, { include: [User, Tag, Comment, Place] })
res.json(event)
},
async confirm(req, res) {
const id = req.params.event_id
const event = await Event.findByPk(id)
try {
await event.update({ is_visible: true })
// insert notification
const notifications = await eventController.getNotifications(event)
await event.setNotifications(notifications)
res.sendStatus(200)
} catch (e) {
res.sendStatus(404)
}
},
async unconfirm(req, res) {
const id = req.params.event_id
const event = await Event.findByPk(id)
try {
await event.update({ is_visible: false })
res.sendStatus(200)
} catch (e) {
res.sendStatus(404)
}
},
async getUnconfirmed(req, res) {
const events = await Event.findAll({
where: {
is_visible: false
},
order: [['start_datetime', 'ASC']],
include: [Tag, Place]
})
res.json(events)
},
async addNotification(req, res) {
try {
const notification = {
filters: { is_visible: true },
email: req.body.email,
type: 'mail',
remove_code: crypto.randomBytes(16).toString('hex')
}
await Notification.create(notification)
res.sendStatus(200)
} catch (e) {
res.sendStatus(404)
}
},
async delNotification(req, res) {
const remove_code = req.params.code
try {
const notification = await Notification.findOne({ where: { remove_code: { [Op.eq]: remove_code } } })
await notification.destroy()
} catch (e) {
return res.sendStatus(404)
}
res.sendStatus(200)
},
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')
let end = moment().year(req.params.year).month(req.params.month).endOf('month')
const shownDays = end.diff(start, 'days')
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 }
// ]
})
console.log(events)
res.json(events)
}
}
module.exports = eventController

View File

@@ -0,0 +1,64 @@
const { Event, Comment, Tag, Place } = require('../model')
const { Op } = require('sequelize')
const config = require('../config')
const moment = require('moment')
const ics = require('ics')
const exportController = {
async export (req, res) {
console.log('type ', req.params.type)
const type = req.params.type
const tags = req.query.tags
const places = req.query.places
const whereTag = {}
const wherePlace = {}
const yesterday = moment().subtract('1', 'day')
if (tags) {
whereTag.tag = tags.split(',')
}
if (places) {
wherePlace.name = places.split(',')
}
const events = await Event.findAll({
where: { is_visible: true, start_datetime: { [Op.gte]: yesterday } },
include: [Comment, {
model: Tag,
where: whereTag
}, { model: Place, where: wherePlace } ]
})
switch (type) {
case 'feed':
return exportController.feed(res, events.slice(0, 20))
case 'ics':
return exportController.ics(res, events)
}
},
async feed (res, events) {
res.type('application/rss+xml; charset=UTF-8')
res.render('feed/rss.pug', { events, config, moment })
},
async ics (res, events) {
const eventsMap = events.map(e => {
const tmpStart = moment(e.start_datetime)
const tmpEnd = moment(e.end_datetime)
const start = [tmpStart.year(), tmpStart.month() + 1, tmpStart.date(), tmpStart.hour(), tmpStart.minute()]
const end = [tmpEnd.year(), tmpEnd.month() + 1, tmpEnd.date(), tmpEnd.hour(), tmpEnd.minute()]
return {
start,
end,
title: e.title,
description: e.description,
location: e.place.name + ' ' + e.place.address
}
})
res.type('text/calendar; charset=UTF-8')
const { error, value } = ics.createEvents(eventsMap)
console.log(error, value)
res.send(value)
}
}
module.exports = exportController

View File

@@ -0,0 +1,27 @@
const { Settings } = require('../model')
const settingsController = {
async setAdminSetting (key, value) {
await Settings.findOrCreate({ where: { key },
defaults: { value } })
.spread((settings, created) => {
if (!created) return settings.update({ value })
})
},
async getAdminSettings (req, res) {
const settings = await settingsController.settings()
res.json(settings)
},
async settings () {
const settings = await Settings.findAll()
const map = {}
settings.forEach(setting => {
map[setting.key] = setting.value
})
return map
}
}
module.exports = settingsController

View File

@@ -0,0 +1,283 @@
const jwt = require('jsonwebtoken')
const Mastodon = require('mastodon-api')
const User = require('../models/user')
const { Event, Tag, Place } = require('../models/event')
const settingsController = require('./settings')
const eventController = require('./event')
const config = require('../config')
const mail = require('../mail')
const { Op } = require('sequelize')
const fs = require('fs')
const path = require('path')
const crypto = require('crypto')
const userController = {
async login (req, res) {
// find the user
const user = await User.findOne({ where: { email: { [Op.eq]: req.body.email } } })
if (!user) {
res.status(404).json({ success: false, message: 'AUTH_FAIL' })
} else if (user) {
if (!user.is_active) {
res.status(403).json({ success: false, message: 'NOT_CONFIRMED' })
// check if password matches
} else if (!await user.comparePassword(req.body.password)) {
res.status(403).json({ success: false, message: 'AUTH_FAIL' })
} else {
// if user is found and password is right
// create a token
const payload = { email: user.email }
var token = jwt.sign(payload, config.secret)
res.json({
success: true,
message: 'Enjoy your token!',
token,
user
})
}
}
},
async setToken (req, res) {
req.user.mastodon_auth = req.body
await req.user.save()
res.json(req.user)
},
async delEvent (req, res) {
const event = await Event.findByPk(req.params.id)
// check if event is mine (or user is admin)
if (event && (req.user.is_admin || req.user.id === event.userId)) {
if (event.image_path) {
const old_path = path.resolve(__dirname, '..', '..', 'uploads', event.image_path)
const old_thumb_path = path.resolve(__dirname, '..', '..', 'uploads', 'thumb', event.image_path)
await fs.unlink(old_path)
await fs.unlink(old_thumb_path)
}
await event.destroy()
res.sendStatus(200)
} else {
res.sendStatus(403)
}
},
// ADD EVENT
async addEvent (req, res) {
const body = req.body
// remove description tag and create anchor tags
const description = body.description
.replace(/(<([^>]+)>)/ig, '')
.replace(/(https?:\/\/[^\s]+)/g, '<a href="$1">$1</a>')
const eventDetails = {
title: body.title,
description,
multidate: body.multidate,
start_datetime: body.start_datetime,
end_datetime: body.end_datetime,
is_visible: !!req.user
}
if (req.file) {
eventDetails.image_path = req.file.filename
}
let event = await Event.create(eventDetails)
// create place
let place
try {
place = await Place.findOrCreate({ where: { name: body.place_name },
defaults: { address: body.place_address } })
.spread((place, created) => place)
await event.setPlace(place)
} catch (e) {
console.error(e)
}
// create/assign tags
if (body.tags) {
await Tag.bulkCreate(body.tags.map(t => ({ tag: t })), { ignoreDuplicates: true })
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] })
// insert notifications
const notifications = await eventController.getNotifications(event)
await event.setNotifications(notifications)
return res.json(event)
},
async updateEvent (req, res) {
const body = req.body
const event = await Event.findByPk(body.id)
if (!req.user.is_admin && event.userId !== req.user.id) {
return res.sendStatus(403)
}
if (req.file) {
if (event.image_path) {
const old_path = path.resolve(__dirname, '..', '..', 'uploads', event.image_path)
const old_thumb_path = path.resolve(__dirname, '..', '..', 'uploads', 'thumb', event.image_path)
await fs.unlink(old_path, e => console.error(e))
await fs.unlink(old_thumb_path, e => console.error(e))
}
body.image_path = req.file.filename
}
body.description = body.description
.replace(/(<([^>]+)>)/ig, '') // remove all tags from description
.replace(/(https?:\/\/[^\s]+)/g, '<a href="$1">$1</a>') // add links
await event.update(body)
let place
try {
place = await Place.findOrCreate({ where: { name: body.place_name },
defaults: { address: body.place_address } })
.spread((place, created) => place)
} catch (e) {
console.log('error', e)
}
await event.setPlace(place)
await event.setTags([])
if (body.tags) {
await Tag.bulkCreate(body.tags.map(t => ({ tag: t })), { ignoreDuplicates: true })
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)
},
async getAuthURL (req, res) {
const instance = req.body.instance
const is_admin = req.body.admin && req.user.is_admin
const callback = `${config.baseurl}/${is_admin ? 'admin/oauth' : 'settings'}`
const { client_id, client_secret } = await Mastodon.createOAuthApp(`https://${instance}/api/v1/apps`,
config.title, 'read write', callback)
const url = await Mastodon.getAuthorizationUrl(client_id, client_secret,
`https://${instance}`, 'read write', callback)
if (is_admin) {
await settingsController.setAdminSetting('mastodon_auth', { client_id, client_secret, instance })
} else {
req.user.mastodon_auth = { client_id, client_secret, instance }
await req.user.save()
}
res.json(url)
},
async code (req, res) {
const { code, is_admin } = req.body
let client_id, client_secret, instance
const callback = `${config.baseurl}/${is_admin ? 'admin/oauth' : 'settings'}`
if (is_admin) {
const settings = await settingsController.settings();
({ client_id, client_secret, instance } = settings.mastodon_auth)
} else {
({ client_id, client_secret, instance } = req.user.mastodon_auth)
}
try {
const token = await Mastodon.getAccessToken(client_id, client_secret, code,
`https://${instance}`, callback)
const mastodon_auth = { client_id, client_secret, access_token: token, instance }
if (is_admin) {
await settingsController.setAdminSetting('mastodon_auth', mastodon_auth)
res.json(instance)
} else {
req.user.mastodon_auth = mastodon_auth
await req.user.save()
// await bot.add(req.user, token)
res.json(req.user)
}
} catch (e) {
res.json(e)
}
},
async forgotPassword (req, res) {
const email = req.body.email
const user = await User.findOne({ where: { email: { [Op.eq]: email } } })
if (!user) return res.sendStatus(200)
user.recover_code = crypto.randomBytes(16).toString('hex')
mail.send(user.email, 'recover', { user, config })
await user.save()
res.sendStatus(200)
},
async checkRecoverCode (req, res) {
const recover_code = req.body.recover_code
if (!recover_code) return res.sendStatus(400)
const user = await User.findOne({ where: { recover_code: { [Op.eq]: recover_code } } })
if (!user) return res.sendStatus(400)
res.json(user)
},
async updatePasswordWithRecoverCode (req, res) {
const recover_code = req.body.recover_code
if (!recover_code) return res.sendStatus(400)
const password = req.body.password
const user = await User.findOne({ where: { recover_code: { [Op.eq]: recover_code } } })
if (!user) return res.sendStatus(400)
user.password = password
await user.save()
res.sendStatus(200)
},
async current (req, res) {
res.json(req.user)
},
async getAll (req, res) {
const users = await User.findAll({
order: [['createdAt', 'DESC']]
})
res.json(users)
},
async update (req, res) {
const user = await User.findByPk(req.body.id)
if (user) {
if (!user.is_active && req.body.is_active) {
await mail.send(user.email, 'confirm', { user, config })
}
await user.update(req.body)
res.json(user)
} else {
res.sendStatus(400)
}
},
async register (req, res) {
const n_users = await User.count()
try {
if (n_users === 0) {
// the first registered user will be an active admin
req.body.is_active = req.body.is_admin = true
} else {
req.body.is_active = false
}
const user = await User.create(req.body)
try {
mail.send([user.email, config.admin], 'register', { user, config })
} catch (e) {
return res.status(400).json(e)
}
const payload = { email: user.email }
const token = jwt.sign(payload, config.secret)
res.json({ user, token })
} catch (e) {
res.status(404).json(e)
}
}
}
module.exports = userController