gancio-upstream/server/api/controller/event.js
2019-07-11 23:31:37 +02:00

260 lines
7.3 KiB
JavaScript

const crypto = require('crypto')
const moment = require('moment')
const { Op } = require('sequelize')
const lodash = require('lodash')
const { event: Event, comment: Comment, tag: Tag, place: Place, notification: Notification } = require('../models')
const Sequelize = require('sequelize')
const notifier = require('../../notifier')
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({
order: [[Sequelize.literal('weigth'), 'DESC']],
attributes: {
include: [[Sequelize.fn('count', Sequelize.col('events.placeId')) , 'weigth']],
exclude: ['weigth', 'createdAt', 'updatedAt']
},
include: [{ model: Event, attributes: [] }],
group: ['place.id']
})
const tags = await Tag.findAll({
order: [['weigth', 'DESC']],
attributes: {
exclude: ['createdAt', 'updatedAt']
},
})
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)
},
// TODO retrieve next/prev event also
// select id, start_datetime, title from events where start_datetime > (select start_datetime from events where id=89) order by start_datetime limit 20;
async get(req, res) {
const is_admin = req.user && req.user.is_admin
const id = req.params.event_id
let event = await Event.findByPk(id, {
plain: true,
attributes: { exclude: ['createdAt', 'updatedAt'] },
include: [
{ model: Tag, attributes: ['tag', 'weigth'], through: { attributes: [] } },
{ model: Place, attributes: ['name', 'address'] },
Comment
],
order: [ [Comment, 'id', 'DESC'] ]
})
if (event && (event.is_visible || is_admin)) {
res.json(event)
} else {
res.sendStatus(404)
}
},
async confirm(req, res) {
console.error('confirm event')
const id = Number(req.params.event_id)
const event = await Event.findByPk(id)
if (!event) return res.sendStatus(404)
try {
event.is_visible = true
await event.save()
res.sendStatus(200)
// send notification
notifier.notifyEvent(event.id)
} catch (e) {
res.sendStatus(404)
}
},
async unconfirm(req, res) {
const id = Number(req.params.event_id)
const event = await Event.findByPk(id)
if (!event) return sendStatus(404)
try {
event.is_visible = false
await event.save()
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) {
// 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 <= 35) end = end.add(1, 'week')
end = end.endOf('isoWeek')
let events = await Event.findAll({
where: {
is_visible: true,
[Op.and]: [
Sequelize.literal(`start_datetime >= ${start.unix()}`),
Sequelize.literal(`start_datetime <= ${end.unix()}`)
]
},
order: [
['start_datetime', 'ASC'],
[Tag, 'weigth', 'DESC']
],
include: [
{ model: Tag, required: false, attributes: ['tag', 'weigth'] },
{ model: Place, required: false, attributes: ['id', 'name', 'address'] }
]
})
events = events.map(e => {
e.start_datetime = e.start_datetime*1000
e.end_datetime = e.end_datetime*1000
e.tags = e.tags.map(t => t.tag)
return e
})
// build singular events from a recurrent pattern from today due to
// specified parameters
function createEventsFromRecurrent(e, dueTo=null, maxEvents=20) {
const events = []
const cursor = moment()
const start_date = moment(e.start_datetime)
const frequency = e.recurrent.frequency
const days = e.recurrent.days
const ordinal = e.recurrent.ordinal
// EACH WEEK
if (frequency === '1w') {
while(true) {
const found = days.indexOf(cursor.day())
if (found) break
cursor.add(1, 'day')
}
e.start_datetime = cursor.set('hour', e.start_datetime.hour()).set('minute', e.start_datetime.minutes())
while (true) {
if ((dueTo && cursor.isAfter(dueTo)) || events.length>maxEvents) break
e.start_datetime = cursor.unix()
events.push(e)
cursors.add(1, 'week')
}
}
// EACH TWO WEEKS
return events
}
const normalEvents = events.filter(e => !e.recurrent)
const recurrentEvents = events.filter(e => e.recurrent).map(createEventsFromRecurrent)
res.json(normalEvents.concat(recurrentEvents))
}
}
module.exports = eventController