gancio-upstream/server/api/controller/event.js

308 lines
9.2 KiB
JavaScript
Raw Normal View History

2019-04-03 00:25:12 +02:00
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,
user: User, notification: Notification, event_notification: EventNotification } = require('../models')
2019-05-30 12:04:14 +02:00
const Sequelize = require('sequelize')
2019-09-11 23:17:12 +02:00
const debug = require('debug')('controller:event')
2019-04-03 00:25:12 +02:00
const eventController = {
// NOT USED ANYWHERE, comments are added from fediverse, should we remove this?
2019-09-11 19:12:24 +02:00
async addComment (req, res) {
// comments could be added to an event or to another comment
2019-04-03 00:25:12 +02:00
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)
},
2019-09-11 19:12:24 +02:00
async getMeta (req, res) {
2019-05-30 12:04:14 +02:00
const places = await Place.findAll({
2019-05-30 12:12:51 +02:00
order: [[Sequelize.literal('weigth'), 'DESC']],
2019-05-30 12:04:14 +02:00
attributes: {
2019-09-11 19:12:24 +02:00
include: [[Sequelize.fn('count', Sequelize.col('events.placeId')), 'weigth']],
2019-05-30 12:12:51 +02:00
exclude: ['weigth', 'createdAt', 'updatedAt']
2019-05-30 12:04:14 +02:00
},
2019-05-30 12:12:51 +02:00
include: [{ model: Event, attributes: [] }],
group: ['place.id']
2019-05-30 12:04:14 +02:00
})
const tags = await Tag.findAll({
2019-06-07 17:02:33 +02:00
order: [['weigth', 'DESC']],
2019-05-30 12:04:14 +02:00
attributes: {
exclude: ['createdAt', 'updatedAt']
2019-09-11 19:12:24 +02:00
}
2019-05-30 12:12:51 +02:00
})
2019-05-30 12:04:14 +02:00
2019-04-03 00:25:12 +02:00
res.json({ tags, places })
},
async getNotifications (event, action) {
debug('getNotifications "%s" (%s)', event.title, action)
2019-09-11 19:12:24 +02:00
function match (event, filters) {
2019-04-03 00:25:12 +02:00
// matches if no filter specified
2019-09-11 19:12:24 +02:00
if (!filters) { return true }
2019-04-03 00:25:12 +02:00
// check for visibility
2019-09-11 19:12:24 +02:00
if (typeof filters.is_visible !== 'undefined' && filters.is_visible !== event.is_visible) { return false }
2019-04-03 00:25:12 +02:00
2019-09-11 19:12:24 +02:00
if (!filters.tags && !filters.places) { return true }
if (!filters.tags.length && !filters.places.length) { return true }
2019-04-03 00:25:12 +02:00
if (filters.tags.length) {
const m = lodash.intersection(event.tags.map(t => t.tag), filters.tags)
2019-09-11 19:12:24 +02:00
if (m.length > 0) { return true }
2019-04-03 00:25:12 +02:00
}
if (filters.places.length) {
if (filters.places.find(p => p === event.place.name)) {
return true
}
}
}
const notifications = await Notification.findAll({ where: { action }, include: [ Event ] })
2019-04-03 00:25:12 +02:00
// get notification that matches with selected event
const ret = notifications.filter(notification => match(event, notification.filters))
return ret
2019-04-03 00:25:12 +02:00
},
2019-09-11 19:12:24 +02:00
async updateTag (req, res) {
2019-04-03 00:25:12 +02:00
const tag = await Tag.findByPk(req.body.tag)
if (tag) {
res.json(await tag.update(req.body))
} else {
res.sendStatus(404)
}
},
2019-09-11 19:12:24 +02:00
async updatePlace (req, res) {
2019-04-03 00:25:12 +02:00
const place = await Place.findByPk(req.body.id)
await place.update(req.body)
res.json(place)
},
2019-06-14 23:26:13 +02:00
// 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;
2019-09-11 19:12:24 +02:00
async get (req, res) {
2019-07-04 01:09:35 +02:00
const is_admin = req.user && req.user.is_admin
2019-04-03 00:25:12 +02:00
const id = req.params.event_id
2019-09-11 19:12:24 +02:00
const event = await Event.findByPk(id, {
2019-06-26 14:44:21 +02:00
plain: true,
2019-09-11 19:12:24 +02:00
attributes: {
2019-07-23 16:26:54 +02:00
exclude: ['createdAt', 'updatedAt']
2019-07-23 01:31:43 +02:00
},
2019-06-14 23:26:13 +02:00
include: [
2019-06-26 14:44:21 +02:00
{ model: Tag, attributes: ['tag', 'weigth'], through: { attributes: [] } },
2019-08-02 13:43:28 +02:00
{ model: User, attributes: ['username'] },
2019-06-26 14:44:21 +02:00
{ model: Place, attributes: ['name', 'address'] },
Comment
2019-06-07 17:02:33 +02:00
],
2019-06-26 14:44:21 +02:00
order: [ [Comment, 'id', 'DESC'] ]
2019-05-30 12:04:14 +02:00
})
2019-06-25 01:05:38 +02:00
2019-07-04 01:02:45 +02:00
if (event && (event.is_visible || is_admin)) {
res.json(event)
} else {
res.sendStatus(404)
}
2019-04-03 00:25:12 +02:00
},
2019-09-11 19:12:24 +02:00
async confirm (req, res) {
2019-07-04 00:29:50 +02:00
const id = Number(req.params.event_id)
2019-04-03 00:25:12 +02:00
const event = await Event.findByPk(id)
2019-09-11 19:12:24 +02:00
if (!event) { return res.sendStatus(404) }
2019-04-03 00:25:12 +02:00
try {
2019-07-04 01:02:45 +02:00
event.is_visible = true
await event.save()
2019-04-03 00:25:12 +02:00
res.sendStatus(200)
2019-09-11 19:12:24 +02:00
// send notification
const notifier = require('../../notifier')
notifier.notifyEvent('Create', event.id)
2019-04-03 00:25:12 +02:00
} catch (e) {
res.sendStatus(404)
}
},
2019-09-11 19:12:24 +02:00
async unconfirm (req, res) {
2019-07-04 00:29:50 +02:00
const id = Number(req.params.event_id)
2019-04-03 00:25:12 +02:00
const event = await Event.findByPk(id)
2019-09-11 19:12:24 +02:00
if (!event) { return sendStatus(404) }
2019-04-03 00:25:12 +02:00
try {
2019-07-04 01:02:45 +02:00
event.is_visible = false
await event.save()
2019-04-03 00:25:12 +02:00
res.sendStatus(200)
} catch (e) {
res.sendStatus(404)
}
},
2019-09-11 19:12:24 +02:00
async getUnconfirmed (req, res) {
2019-04-03 00:25:12 +02:00
const events = await Event.findAll({
where: {
is_visible: false
},
order: [['start_datetime', 'ASC']],
include: [Tag, Place]
})
res.json(events)
},
2019-09-11 19:12:24 +02:00
async addNotification (req, res) {
2019-04-03 00:25:12 +02:00
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)
}
},
2019-09-11 19:12:24 +02:00
async delNotification (req, res) {
2019-04-03 00:25:12 +02:00
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)
},
2019-09-11 19:12:24 +02:00
async getAll (req, res) {
2019-04-03 00:25:12 +02:00
// this is due how v-calendar shows dates
2019-07-11 23:31:37 +02:00
const start = moment()
.year(req.params.year)
.month(req.params.month)
.startOf('month')
2019-07-23 01:31:43 +02:00
.startOf('week')
2019-10-02 16:00:51 +02:00
.utc(false)
2019-07-11 23:31:37 +02:00
let end = moment()
.year(req.params.year)
.month(req.params.month)
.endOf('month')
2019-10-02 16:00:51 +02:00
.utc(false)
2019-07-11 23:31:37 +02:00
2019-04-03 00:25:12 +02:00
const shownDays = end.diff(start, 'days')
2019-09-11 19:12:24 +02:00
if (shownDays <= 35) { end = end.add(1, 'week') }
2019-07-23 01:31:43 +02:00
end = end.endOf('week')
2019-07-11 23:31:37 +02:00
let events = await Event.findAll({
where: {
2019-07-13 01:02:11 +02:00
// return only confirmed events
is_visible: true,
2019-07-13 01:02:11 +02:00
[Op.or]: [
2019-09-12 11:59:30 +02:00
// return all recurrent events regardless start_datetime
2019-09-11 19:12:24 +02:00
{ recurrent: { [Op.ne]: null } },
2019-07-13 01:02:11 +02:00
// and events in specified range
2019-09-11 19:12:24 +02:00
{ start_datetime: { [Op.between]: [start.unix(), end.unix()] } }
]
},
2019-07-13 01:02:11 +02:00
attributes: { exclude: ['createdAt', 'updatedAt', 'placeId' ] },
order: [[Tag, 'weigth', 'DESC']],
include: [
2019-08-25 14:51:38 +02:00
{ model: Comment, required: false, attributes: ['id'] },
2019-07-13 01:02:11 +02:00
{ model: Tag, required: false },
2019-05-30 12:12:51 +02:00
{ model: Place, required: false, attributes: ['id', 'name', 'address'] }
]
2019-04-03 00:25:12 +02:00
})
2019-07-11 23:31:37 +02:00
2019-07-13 01:02:11 +02:00
events = events.map(e => e.get()).map(e => {
2019-07-11 23:31:37 +02:00
e.tags = e.tags.map(t => t.tag)
return e
})
2019-07-13 01:02:11 +02:00
// build singular events from a recurrent pattern
2019-09-11 19:12:24 +02:00
function createEventsFromRecurrent (e, dueTo = null) {
2019-07-11 23:31:37 +02:00
const events = []
2019-09-12 11:59:30 +02:00
const recurrent = JSON.parse(e.recurrent)
2019-09-11 19:12:24 +02:00
if (!recurrent.frequency) { return false }
2019-07-19 00:34:47 +02:00
2019-07-23 01:31:43 +02:00
let cursor = moment(start).startOf('week')
2019-10-02 16:00:51 +02:00
const start_date = moment.unix(e.start_datetime).utc(false)
2019-07-27 13:05:02 +02:00
const duration = moment.unix(e.end_datetime).diff(start_date, 's')
2019-07-13 01:02:11 +02:00
const frequency = recurrent.frequency
2019-07-15 23:35:59 +02:00
const days = recurrent.days
2019-07-14 01:44:28 +02:00
const type = recurrent.type
2019-07-11 23:31:37 +02:00
2019-07-15 23:35:59 +02:00
// default frequency is '1d' => each day
2019-09-11 19:12:24 +02:00
const toAdd = { n: 1, unit: 'day' }
2019-07-23 01:31:43 +02:00
2019-07-15 23:35:59 +02:00
// each week or 2 (search for the first specified day)
if (frequency === '1w' || frequency === '2w') {
2019-09-11 19:12:24 +02:00
cursor.add(days[0] - 1, 'day')
2019-07-15 23:35:59 +02:00
if (frequency === '2w') {
2019-09-11 19:12:24 +02:00
const nWeeks = cursor.diff(e.start_datetime, 'w') % 2
if (!nWeeks) { cursor.add(1, 'week') }
2019-07-11 23:31:37 +02:00
}
2019-07-15 23:35:59 +02:00
toAdd.n = Number(frequency[0])
2019-09-11 19:12:24 +02:00
toAdd.unit = 'week'
2019-07-23 01:31:43 +02:00
// cursor.set('hour', start_date.hour()).set('minute', start_date.minutes())
2019-07-11 23:31:37 +02:00
}
2019-10-02 16:00:51 +02:00
cursor.set('hour', start_date.hour()).set('minute', start_date.minutes())
2019-07-15 23:35:59 +02:00
// each month or 2
2019-07-23 01:31:43 +02:00
if (frequency === '1m' || frequency === '2m') {
// find first match
toAdd.n = 1
toAdd.unit = 'month'
if (type === 'weekday') {
} else if (type === 'ordinal') {
}
}
2019-07-15 23:35:59 +02:00
2019-09-11 19:12:24 +02:00
// add event at specified frequency
2019-07-15 23:35:59 +02:00
while (true) {
2019-09-11 19:12:24 +02:00
const first_event_of_week = cursor.clone()
2019-07-19 00:34:47 +02:00
days.forEach(d => {
2019-07-23 01:31:43 +02:00
if (type === 'ordinal') {
cursor.date(d)
} else {
2019-09-11 19:12:24 +02:00
cursor.day(d - 1)
2019-07-23 01:31:43 +02:00
}
2019-09-11 19:12:24 +02:00
if (cursor.isAfter(dueTo) || cursor.isBefore(start)) { return }
2019-10-02 16:00:51 +02:00
e.start_datetime = cursor.utc(true).unix()
2019-09-11 19:12:24 +02:00
e.end_datetime = e.start_datetime + duration
events.push(Object.assign({}, e))
})
if (cursor.isAfter(dueTo)) { break }
2019-07-19 00:34:47 +02:00
cursor = first_event_of_week.add(toAdd.n, toAdd.unit)
2019-10-02 16:00:51 +02:00
cursor.set('hour', start_date.hour()).set('minute', start_date.minutes())
2019-07-14 01:44:28 +02:00
}
2019-07-11 23:31:37 +02:00
return events
}
2019-09-11 23:17:12 +02:00
let allEvents = events.filter(e => !e.recurrent || e.recurrent.length === 0)
events.filter(e => e.recurrent && e.recurrent.length).forEach(e => {
2019-07-13 01:02:11 +02:00
const events = createEventsFromRecurrent(e, end)
2019-09-11 19:12:24 +02:00
if (events) { allEvents = allEvents.concat(events) }
2019-07-13 01:02:11 +02:00
})
2019-07-11 23:31:37 +02:00
2019-07-13 01:02:11 +02:00
// allEvents.sort((a,b) => a.start_datetime-b.start_datetime)
2019-09-11 19:12:24 +02:00
res.json(allEvents.sort((a, b) => a.start_datetime - b.start_datetime))
2019-04-03 00:25:12 +02:00
}
}
module.exports = eventController