2019-04-03 00:25:12 +02:00
|
|
|
const crypto = require('crypto')
|
2020-10-25 00:34:22 +02:00
|
|
|
// const moment = require('moment-timezone')
|
2020-01-31 14:56:31 +01:00
|
|
|
const path = require('path')
|
|
|
|
const config = require('config')
|
|
|
|
const fs = require('fs')
|
2019-04-03 00:25:12 +02:00
|
|
|
const { Op } = require('sequelize')
|
2020-01-21 01:24:32 +01:00
|
|
|
const _ = require('lodash')
|
2020-02-10 00:40:23 +01:00
|
|
|
const helpers = require('../../helpers')
|
2020-02-11 12:08:15 +01:00
|
|
|
const linkifyHtml = require('linkifyjs/html')
|
|
|
|
const Sequelize = require('sequelize')
|
2020-10-25 00:34:22 +02:00
|
|
|
const dayjs = require('dayjs')
|
2020-02-10 00:40:23 +01:00
|
|
|
|
2020-06-27 02:10:10 +02:00
|
|
|
const Event = require('../models/event')
|
|
|
|
const Resource = require('../models/resource')
|
|
|
|
const Tag = require('../models/tag')
|
|
|
|
const Place = require('../models/place')
|
|
|
|
const Notification = require('../models/notification')
|
|
|
|
const APUser = require('../models/ap_user')
|
|
|
|
|
2019-10-20 14:22:55 +02:00
|
|
|
const exportController = require('./export')
|
2020-01-31 14:56:31 +01:00
|
|
|
|
2019-09-11 23:17:12 +02:00
|
|
|
const debug = require('debug')('controller:event')
|
2019-04-03 00:25:12 +02:00
|
|
|
|
|
|
|
const eventController = {
|
|
|
|
|
2020-01-27 00:47:03 +01:00
|
|
|
async _getMeta () {
|
2019-05-30 12:04:14 +02:00
|
|
|
const places = await Place.findAll({
|
2020-08-31 16:51:12 +02:00
|
|
|
where: { confirmed: true },
|
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']],
|
2020-01-21 01:24:32 +01:00
|
|
|
exclude: ['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({
|
2020-08-31 16:51:12 +02:00
|
|
|
where: { confirmed: true },
|
2020-01-15 23:51:57 +01:00
|
|
|
raw: true,
|
2019-06-07 17:02:33 +02:00
|
|
|
order: [['weigth', 'DESC']],
|
2019-05-30 12:04:14 +02:00
|
|
|
attributes: {
|
2020-01-21 01:24:32 +01:00
|
|
|
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
|
|
|
|
2020-01-27 00:47:03 +01:00
|
|
|
return { places, tags }
|
|
|
|
},
|
|
|
|
|
|
|
|
async getMeta (req, res) {
|
|
|
|
res.json(await eventController._getMeta())
|
2019-04-03 00:25:12 +02:00
|
|
|
},
|
|
|
|
|
2019-10-02 21:04:03 +02:00
|
|
|
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) {
|
2020-01-21 01:24:32 +01:00
|
|
|
const m = _.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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-10-02 21:04:03 +02:00
|
|
|
|
2020-01-21 01:24:32 +01:00
|
|
|
const notifications = await Notification.findAll({ where: { action }, include: [Event] })
|
2019-04-03 00:25:12 +02:00
|
|
|
|
|
|
|
// get notification that matches with selected event
|
2019-10-02 21:04:03 +02:00
|
|
|
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 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-09-11 19:12:24 +02:00
|
|
|
async get (req, res) {
|
2019-10-20 14:22:55 +02:00
|
|
|
const format = req.params.format || 'json'
|
2019-07-04 01:09:35 +02:00
|
|
|
const is_admin = req.user && req.user.is_admin
|
2020-01-15 23:51:57 +01:00
|
|
|
const id = Number(req.params.event_id)
|
2020-01-30 12:37:19 +01:00
|
|
|
let event
|
2020-06-03 22:52:10 +02:00
|
|
|
|
2020-01-30 12:37:19 +01:00
|
|
|
try {
|
|
|
|
event = await Event.findByPk(id, {
|
|
|
|
attributes: {
|
2020-02-05 00:48:55 +01:00
|
|
|
exclude: ['createdAt', 'updatedAt', 'placeId']
|
2020-01-30 12:37:19 +01:00
|
|
|
},
|
|
|
|
include: [
|
2020-02-05 00:48:55 +01:00
|
|
|
{ model: Tag, required: false, attributes: ['tag', 'weigth'], through: { attributes: [] } },
|
2020-02-11 11:53:32 +01:00
|
|
|
{ model: Place, attributes: ['name', 'address', 'id'] },
|
2020-02-05 00:48:55 +01:00
|
|
|
{
|
|
|
|
model: Resource,
|
|
|
|
where: !is_admin && { hidden: false },
|
|
|
|
include: [{ model: APUser, required: false, attributes: ['object', 'ap_id'] }],
|
|
|
|
required: false,
|
|
|
|
attributes: ['id', 'activitypub_id', 'data', 'hidden']
|
|
|
|
},
|
2020-02-10 10:30:38 +01:00
|
|
|
{ model: Event, required: false, as: 'parent', attributes: ['id', 'recurrent', 'is_visible'] }
|
2020-01-30 12:37:19 +01:00
|
|
|
],
|
|
|
|
order: [[Resource, 'id', 'DESC']]
|
|
|
|
})
|
|
|
|
} catch (e) {
|
|
|
|
return res.sendStatus(400)
|
|
|
|
}
|
2020-06-03 22:52:10 +02:00
|
|
|
|
|
|
|
if (!event) {
|
|
|
|
return res.sendStatus(400)
|
|
|
|
}
|
|
|
|
|
|
|
|
// get prev and next event
|
|
|
|
const next = await Event.findOne({
|
|
|
|
attributes: ['id'],
|
|
|
|
where: {
|
|
|
|
is_visible: true,
|
2020-06-13 23:03:07 +02:00
|
|
|
recurrent: null,
|
2020-06-03 22:52:10 +02:00
|
|
|
start_datetime: { [Op.gt]: event.start_datetime }
|
|
|
|
},
|
|
|
|
order: [['start_datetime', 'ASC']]
|
|
|
|
})
|
|
|
|
|
|
|
|
const prev = await Event.findOne({
|
|
|
|
attributes: ['id'],
|
|
|
|
where: {
|
|
|
|
is_visible: true,
|
2020-06-13 23:03:07 +02:00
|
|
|
recurrent: null,
|
2020-06-03 22:52:10 +02:00
|
|
|
start_datetime: { [Op.lt]: event.start_datetime }
|
|
|
|
},
|
|
|
|
order: [['start_datetime', 'DESC']]
|
|
|
|
})
|
|
|
|
|
2019-07-04 01:02:45 +02:00
|
|
|
if (event && (event.is_visible || is_admin)) {
|
2020-02-10 01:12:49 +01:00
|
|
|
event = event.get()
|
2020-06-03 22:52:10 +02:00
|
|
|
event.next = next && next.id
|
|
|
|
event.prev = prev && prev.id
|
2019-10-26 00:27:12 +02:00
|
|
|
event.tags = event.tags.map(t => t.tag)
|
2019-10-20 14:22:55 +02:00
|
|
|
if (format === 'json') {
|
|
|
|
res.json(event)
|
|
|
|
} else if (format === 'ics') {
|
2019-11-06 11:21:00 +01:00
|
|
|
// last arg is alarms/reminder, ref: https://github.com/adamgibbons/ics#attributes (alarms)
|
|
|
|
exportController.ics(req, res, [event], [{
|
|
|
|
action: 'display',
|
|
|
|
trigger: { hours: 1, before: true }
|
|
|
|
}])
|
2019-10-20 14:22:55 +02:00
|
|
|
}
|
2019-06-12 22:26:28 +02:00
|
|
|
} else {
|
|
|
|
res.sendStatus(404)
|
|
|
|
}
|
2019-04-03 00:25:12 +02:00
|
|
|
},
|
|
|
|
|
2019-11-06 11:31:56 +01:00
|
|
|
/** confirm an anonymous event
|
2020-06-04 23:34:48 +02:00
|
|
|
* and send related notifications
|
2019-11-06 11:31:56 +01: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)
|
2020-08-31 17:38:49 +02:00
|
|
|
const event = await Event.findByPk(id, { include: [Place, Tag] })
|
2019-09-11 19:12:24 +02:00
|
|
|
if (!event) { return res.sendStatus(404) }
|
2019-10-28 17:42:21 +01:00
|
|
|
if (!req.user.is_admin && req.user.id !== event.userId) {
|
|
|
|
return res.sendStatus(403)
|
|
|
|
}
|
2019-04-03 00:25:12 +02:00
|
|
|
|
|
|
|
try {
|
2019-07-04 01:02:45 +02:00
|
|
|
event.is_visible = true
|
2020-08-31 17:38:49 +02:00
|
|
|
|
|
|
|
// confirm tag & place if needed
|
|
|
|
if (!event.place.confirmed) {
|
|
|
|
await event.place.update({ confirmed: true })
|
|
|
|
}
|
|
|
|
|
|
|
|
await Tag.update({ confirmed: true },
|
|
|
|
{ where: { confirmed: false, tag: { [Op.in]: event.tags.map(t => t.tag) } } })
|
|
|
|
|
2019-07-04 01:02:45 +02:00
|
|
|
await event.save()
|
2019-07-08 01:53:37 +02:00
|
|
|
|
2019-04-03 00:25:12 +02:00
|
|
|
res.sendStatus(200)
|
2019-09-11 19:12:24 +02:00
|
|
|
|
2019-07-08 01:53:37 +02:00
|
|
|
// send notification
|
2019-10-02 21:04:03 +02:00
|
|
|
const notifier = require('../../notifier')
|
|
|
|
notifier.notifyEvent('Create', event.id)
|
2019-04-03 00:25:12 +02:00
|
|
|
} catch (e) {
|
2020-06-02 00:02:02 +02:00
|
|
|
debug(e)
|
2019-04-03 00:25:12 +02:00
|
|
|
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-10-28 17:33:20 +01:00
|
|
|
if (!event) { return req.sendStatus(404) }
|
2019-10-28 17:42:21 +01:00
|
|
|
if (!req.user.is_admin && req.user.id !== event.userId) {
|
|
|
|
return res.sendStatus(403)
|
|
|
|
}
|
2019-04-03 00:25:12 +02:00
|
|
|
|
|
|
|
try {
|
2020-01-30 12:37:19 +01:00
|
|
|
await event.update({ is_visible: false })
|
2019-04-03 00:25:12 +02:00
|
|
|
res.sendStatus(200)
|
|
|
|
} catch (e) {
|
2020-06-02 00:02:02 +02:00
|
|
|
debug(e)
|
2019-04-03 00:25:12 +02:00
|
|
|
res.sendStatus(404)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2019-11-06 11:31:56 +01:00
|
|
|
/** get all unconfirmed events */
|
2019-09-11 19:12:24 +02:00
|
|
|
async getUnconfirmed (req, res) {
|
2020-06-02 00:02:02 +02:00
|
|
|
try {
|
|
|
|
const events = await Event.findAll({
|
|
|
|
where: {
|
|
|
|
parentId: null,
|
|
|
|
is_visible: false,
|
2020-10-25 00:34:22 +02:00
|
|
|
start_datetime: { [Op.gt]: dayjs().unix() }
|
2020-06-02 00:02:02 +02:00
|
|
|
},
|
|
|
|
order: [['start_datetime', 'ASC']],
|
|
|
|
include: [{ model: Tag, required: false }, Place]
|
|
|
|
})
|
|
|
|
res.json(events)
|
|
|
|
} catch (e) {
|
|
|
|
debug(e)
|
|
|
|
res.sendStatus(400)
|
|
|
|
}
|
2019-04-03 00:25:12 +02:00
|
|
|
},
|
|
|
|
|
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 {
|
2020-02-20 20:58:49 +01:00
|
|
|
const notification = await Notification.findOne({ where: { remove_code } })
|
2019-04-03 00:25:12 +02:00
|
|
|
await notification.destroy()
|
|
|
|
} catch (e) {
|
|
|
|
return res.sendStatus(404)
|
|
|
|
}
|
|
|
|
res.sendStatus(200)
|
|
|
|
},
|
|
|
|
|
2020-01-31 14:56:31 +01:00
|
|
|
async add (req, res) {
|
|
|
|
// req.err comes from multer streaming error
|
|
|
|
if (req.err) {
|
|
|
|
debug(req.err)
|
|
|
|
return res.status(400).json(req.err.toString())
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
const body = req.body
|
|
|
|
const recurrent = body.recurrent ? JSON.parse(body.recurrent) : null
|
|
|
|
|
|
|
|
const eventDetails = {
|
|
|
|
title: body.title,
|
|
|
|
// remove html tags
|
2020-02-11 12:08:15 +01:00
|
|
|
description: helpers.sanitizeHTML(linkifyHtml(body.description)),
|
2020-01-31 14:56:31 +01:00
|
|
|
multidate: body.multidate,
|
|
|
|
start_datetime: body.start_datetime,
|
|
|
|
end_datetime: body.end_datetime,
|
|
|
|
recurrent,
|
|
|
|
// publish this event only if authenticated
|
|
|
|
is_visible: !!req.user
|
|
|
|
}
|
|
|
|
|
|
|
|
if (req.file) {
|
|
|
|
eventDetails.image_path = req.file.filename
|
2020-05-14 22:36:58 +02:00
|
|
|
} else if (body.image_url) {
|
|
|
|
eventDetails.image_path = await helpers.getImageFromURL(body.image_url)
|
2020-01-31 14:56:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
const event = await Event.create(eventDetails)
|
|
|
|
|
2020-07-05 23:50:10 +02:00
|
|
|
const [place] = await Place.findOrCreate({
|
2020-01-31 14:56:31 +01:00
|
|
|
where: { name: body.place_name },
|
2020-08-31 16:47:33 +02:00
|
|
|
defaults: {
|
|
|
|
address: body.place_address,
|
|
|
|
confirmed: !!req.user
|
|
|
|
}
|
2020-07-05 23:50:10 +02:00
|
|
|
})
|
2020-03-31 16:44:20 +02:00
|
|
|
|
2020-01-31 14:56:31 +01:00
|
|
|
await event.setPlace(place)
|
|
|
|
event.place = place
|
|
|
|
|
|
|
|
// create/assign tags
|
|
|
|
if (body.tags) {
|
2020-08-31 16:47:33 +02:00
|
|
|
await Tag.bulkCreate(body.tags.map(t => ({ tag: t, confirmed: !!req.user })), { ignoreDuplicates: true })
|
2020-01-31 14:56:31 +01:00
|
|
|
const tags = await Tag.findAll({ where: { tag: { [Op.in]: body.tags } } })
|
|
|
|
await Promise.all(tags.map(t => t.update({ weigth: Number(t.weigth) + 1 })))
|
|
|
|
await event.addTags(tags)
|
|
|
|
event.tags = tags
|
|
|
|
}
|
|
|
|
|
|
|
|
// associate user to event and reverse
|
|
|
|
if (req.user) {
|
|
|
|
await req.user.addEvent(event)
|
|
|
|
await event.setUser(req.user)
|
|
|
|
}
|
|
|
|
|
2020-06-27 02:10:10 +02:00
|
|
|
// return created event to the client
|
|
|
|
res.json(event)
|
|
|
|
|
2020-01-31 14:56:31 +01:00
|
|
|
// create recurrent instances of event if needed
|
|
|
|
// without waiting for the task manager
|
|
|
|
if (event.recurrent) {
|
|
|
|
eventController._createRecurrent()
|
2020-07-08 00:57:28 +02:00
|
|
|
} else {
|
|
|
|
// send notifications (mastodon / email)
|
|
|
|
const notifier = require('../../notifier')
|
|
|
|
notifier.notifyEvent('Create', event.id)
|
2020-01-31 14:56:31 +01:00
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
debug(e)
|
2020-06-02 00:02:02 +02:00
|
|
|
res.sendStatus(400)
|
2020-01-31 14:56:31 +01:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
async update (req, res) {
|
|
|
|
if (req.err) {
|
|
|
|
return res.status(400).json(req.err.toString())
|
|
|
|
}
|
|
|
|
const body = req.body
|
|
|
|
const event = await Event.findByPk(body.id)
|
2020-06-01 18:10:17 +02:00
|
|
|
if (!event) { return res.sendStatus(404) }
|
2020-01-31 14:56:31 +01:00
|
|
|
if (!req.user.is_admin && event.userId !== req.user.id) {
|
|
|
|
return res.sendStatus(403)
|
|
|
|
}
|
|
|
|
|
2020-02-10 12:01:22 +01:00
|
|
|
const recurrent = body.recurrent ? JSON.parse(body.recurrent) : null
|
|
|
|
const eventDetails = {
|
|
|
|
title: body.title,
|
|
|
|
// remove html tags
|
2020-02-11 12:08:15 +01:00
|
|
|
description: helpers.sanitizeHTML(linkifyHtml(body.description)),
|
2020-02-10 12:01:22 +01:00
|
|
|
multidate: body.multidate,
|
|
|
|
start_datetime: body.start_datetime,
|
|
|
|
end_datetime: body.end_datetime,
|
|
|
|
recurrent
|
|
|
|
}
|
|
|
|
|
2020-01-31 14:56:31 +01:00
|
|
|
if (req.file) {
|
2020-02-10 12:01:22 +01:00
|
|
|
if (event.image_path && !event.recurrent) {
|
2020-01-31 14:56:31 +01:00
|
|
|
const old_path = path.resolve(config.upload_path, event.image_path)
|
|
|
|
const old_thumb_path = path.resolve(config.upload_path, 'thumb', event.image_path)
|
2020-02-10 12:01:22 +01:00
|
|
|
try {
|
|
|
|
await fs.unlinkSync(old_path)
|
|
|
|
await fs.unlinkSync(old_thumb_path)
|
|
|
|
} catch (e) {
|
|
|
|
debug(e.toString())
|
|
|
|
}
|
2020-01-31 14:56:31 +01:00
|
|
|
}
|
2020-02-10 12:01:22 +01:00
|
|
|
eventDetails.image_path = req.file.filename
|
2020-05-14 22:36:58 +02:00
|
|
|
} else if (body.image_url) {
|
|
|
|
eventDetails.image_path = await helpers.getImageFromURL(body.image_url)
|
2020-01-31 14:56:31 +01:00
|
|
|
}
|
|
|
|
|
2020-02-10 12:01:22 +01:00
|
|
|
await event.update(eventDetails)
|
2020-07-05 23:50:10 +02:00
|
|
|
const [place] = await Place.findOrCreate({
|
|
|
|
where: { name: body.place_name },
|
|
|
|
defaults: { address: body.place_address }
|
|
|
|
})
|
|
|
|
|
2020-01-31 14:56:31 +01:00
|
|
|
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: [Tag, Place] })
|
|
|
|
res.json(newEvent)
|
2020-02-10 12:01:22 +01:00
|
|
|
|
|
|
|
// create recurrent instances of event if needed
|
|
|
|
// without waiting for the task manager
|
|
|
|
if (event.recurrent) {
|
|
|
|
eventController._createRecurrent()
|
2020-07-08 00:57:28 +02:00
|
|
|
} else {
|
|
|
|
const notifier = require('../../notifier')
|
|
|
|
notifier.notifyEvent('Update', event.id)
|
2020-02-10 12:01:22 +01:00
|
|
|
}
|
2020-01-31 14:56:31 +01:00
|
|
|
},
|
|
|
|
|
|
|
|
async remove (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)) {
|
2020-02-10 12:01:22 +01:00
|
|
|
if (event.image_path && !event.recurrent) {
|
2020-01-31 14:56:31 +01:00
|
|
|
const old_path = path.join(config.upload_path, event.image_path)
|
|
|
|
const old_thumb_path = path.join(config.upload_path, 'thumb', event.image_path)
|
|
|
|
try {
|
|
|
|
fs.unlinkSync(old_thumb_path)
|
|
|
|
fs.unlinkSync(old_path)
|
|
|
|
} catch (e) {
|
2020-02-10 12:01:22 +01:00
|
|
|
debug(e.toString())
|
2020-01-31 14:56:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
const notifier = require('../../notifier')
|
|
|
|
await notifier.notifyEvent('Delete', event.id)
|
|
|
|
await event.destroy()
|
|
|
|
res.sendStatus(200)
|
|
|
|
} else {
|
|
|
|
res.sendStatus(403)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2020-10-25 00:34:22 +02:00
|
|
|
async _select ({ start, end, tags, places }) {
|
|
|
|
debug('_select start: %s, end: %s, tags: %s', dayjs.unix(start), end, tags)
|
2020-01-21 01:24:32 +01:00
|
|
|
const where = {
|
|
|
|
// confirmed event only
|
2020-01-30 12:37:19 +01:00
|
|
|
recurrent: null,
|
2020-01-21 01:24:32 +01:00
|
|
|
is_visible: true,
|
2020-10-25 00:34:22 +02:00
|
|
|
end_datetime: { [Op.gt]: start }
|
2020-10-17 00:41:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (end) {
|
2020-10-25 00:34:22 +02:00
|
|
|
where.end_datetime = { [Op.lt]: end }
|
2020-10-17 00:41:21 +02:00
|
|
|
}
|
2020-10-25 00:34:22 +02:00
|
|
|
|
2020-10-17 00:41:21 +02:00
|
|
|
if (places) {
|
|
|
|
where.placeId = places.split(',')
|
|
|
|
}
|
|
|
|
|
|
|
|
let where_tags = {}
|
|
|
|
if (tags) {
|
|
|
|
where_tags = { where: { tag: tags.split(',') } }
|
2020-01-15 23:51:57 +01:00
|
|
|
}
|
|
|
|
|
2020-01-27 00:47:03 +01:00
|
|
|
const events = await Event.findAll({
|
2020-01-15 23:51:57 +01:00
|
|
|
where,
|
|
|
|
attributes: {
|
2020-02-10 01:12:49 +01:00
|
|
|
exclude: ['slug', 'likes', 'boost', 'userId', 'is_visible', 'createdAt', 'updatedAt', 'placeId']
|
2020-01-15 23:51:57 +01:00
|
|
|
// include: [[Sequelize.fn('COUNT', Sequelize.col('activitypub_id')), 'ressources']]
|
|
|
|
},
|
|
|
|
order: ['start_datetime', [Tag, 'weigth', 'DESC']],
|
|
|
|
include: [
|
|
|
|
{ model: Resource, required: false, attributes: ['id'] },
|
2020-10-25 00:34:22 +02:00
|
|
|
{ model: Tag, attributes: ['tag'], required: !!tags, ...where_tags, through: { attributes: [] } },
|
2019-05-30 12:12:51 +02:00
|
|
|
{ model: Place, required: false, attributes: ['id', 'name', 'address'] }
|
2019-04-29 00:27:29 +02:00
|
|
|
]
|
2019-04-03 00:25:12 +02:00
|
|
|
})
|
2019-07-11 23:31:37 +02:00
|
|
|
|
2020-02-10 01:12:49 +01:00
|
|
|
return events.map(e => {
|
2020-01-27 00:47:03 +01:00
|
|
|
e = e.get()
|
|
|
|
e.tags = e.tags ? e.tags.map(t => t && t.tag) : []
|
2020-01-21 01:24:32 +01:00
|
|
|
return e
|
2019-07-13 01:02:11 +02:00
|
|
|
})
|
2020-01-27 00:47:03 +01:00
|
|
|
},
|
2020-01-21 01:24:32 +01:00
|
|
|
|
2020-01-27 00:47:03 +01:00
|
|
|
/**
|
|
|
|
* Select events based on params
|
|
|
|
*/
|
|
|
|
async select (req, res) {
|
2020-10-17 00:41:21 +02:00
|
|
|
const start = req.query.start
|
|
|
|
const end = req.query.end
|
|
|
|
const tags = req.query.tags
|
|
|
|
const places = req.query.places
|
|
|
|
|
|
|
|
res.json(await eventController._select({
|
|
|
|
start, end, places, tags
|
|
|
|
}))
|
2020-01-30 12:37:19 +01:00
|
|
|
},
|
2020-01-21 01:24:32 +01:00
|
|
|
|
2020-01-30 12:37:19 +01:00
|
|
|
/**
|
2020-02-10 01:12:49 +01:00
|
|
|
* Ensure we have the next instances of recurrent events
|
2020-01-30 12:37:19 +01:00
|
|
|
*/
|
|
|
|
_createRecurrentOccurrence (e) {
|
|
|
|
const event = {
|
|
|
|
parentId: e.id,
|
|
|
|
title: e.title,
|
|
|
|
description: e.description,
|
|
|
|
image_path: e.image_path,
|
2020-02-10 01:12:49 +01:00
|
|
|
is_visible: true,
|
2020-01-30 12:37:19 +01:00
|
|
|
userId: e.userId,
|
|
|
|
placeId: e.placeId
|
|
|
|
}
|
|
|
|
|
|
|
|
const recurrent = e.recurrent
|
2020-10-25 00:34:22 +02:00
|
|
|
const cursor = dayjs()
|
2020-02-10 01:12:49 +01:00
|
|
|
// let cursor = start.startOf('week')
|
2020-10-25 00:34:22 +02:00
|
|
|
const start_date = dayjs.unix(e.start_datetime)
|
|
|
|
const duration = dayjs.unix(e.end_datetime).diff(start_date, 's')
|
2020-01-30 12:37:19 +01:00
|
|
|
const frequency = recurrent.frequency
|
|
|
|
const days = recurrent.days
|
|
|
|
const type = recurrent.type
|
|
|
|
|
|
|
|
// default frequency is '1d' => each day
|
|
|
|
const toAdd = { n: 1, unit: 'day' }
|
|
|
|
|
|
|
|
// each week or 2 (search for the first specified day)
|
|
|
|
if (frequency === '1w' || frequency === '2w') {
|
2020-02-10 01:12:49 +01:00
|
|
|
// cursor.add(days[0] - 1, 'day')
|
2020-01-30 12:37:19 +01:00
|
|
|
if (frequency === '2w') {
|
|
|
|
const nWeeks = cursor.diff(e.start_datetime, 'w') % 2
|
|
|
|
if (!nWeeks) { cursor.add(1, 'week') }
|
|
|
|
}
|
|
|
|
toAdd.n = Number(frequency[0])
|
|
|
|
toAdd.unit = 'week'
|
|
|
|
}
|
|
|
|
|
|
|
|
cursor.set('hour', start_date.hour()).set('minute', start_date.minutes())
|
|
|
|
|
|
|
|
// each month or 2
|
|
|
|
if (frequency === '1m' || frequency === '2m') {
|
|
|
|
// find first match
|
|
|
|
toAdd.n = 1
|
|
|
|
toAdd.unit = 'month'
|
|
|
|
if (type === 'weekday') {
|
|
|
|
|
|
|
|
} else if (type === 'ordinal') {
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// add event at specified frequency
|
2020-02-10 01:12:49 +01:00
|
|
|
// const first_event_of_week = cursor.clone()
|
|
|
|
days.forEach(d => {
|
|
|
|
if (type === 'ordinal') {
|
|
|
|
cursor.date(d)
|
|
|
|
} else {
|
|
|
|
cursor.day(d - 1)
|
2020-10-25 00:34:22 +02:00
|
|
|
if (cursor.isBefore(dayjs())) {
|
2020-02-10 12:01:22 +01:00
|
|
|
cursor.day(d - 1 + 7)
|
|
|
|
}
|
2020-02-10 01:12:49 +01:00
|
|
|
}
|
|
|
|
event.start_datetime = cursor.unix()
|
|
|
|
event.end_datetime = event.start_datetime + duration
|
|
|
|
Event.create(event)
|
|
|
|
cursor.set('hour', start_date.hour()).set('minute', start_date.minutes())
|
|
|
|
})
|
|
|
|
// cursor = first_event_of_week.add(toAdd.n, toAdd.unit)
|
2020-01-30 12:37:19 +01:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create instances of recurrent events
|
|
|
|
*/
|
2020-10-25 00:34:22 +02:00
|
|
|
async _createRecurrent (start_datetime = dayjs().unix()) {
|
2020-01-30 12:37:19 +01:00
|
|
|
// select recurrent events
|
|
|
|
const events = await Event.findAll({
|
|
|
|
where: { is_visible: true, recurrent: { [Op.ne]: null } },
|
2020-02-10 01:12:49 +01:00
|
|
|
include: [{ model: Event, as: 'child', required: false, where: { start_datetime: { [Op.gte]: start_datetime } } }],
|
2020-01-30 12:37:19 +01:00
|
|
|
order: ['start_datetime']
|
|
|
|
})
|
|
|
|
|
2020-02-10 01:12:49 +01:00
|
|
|
const creations = events
|
|
|
|
.filter(e => e.child.length === 0)
|
|
|
|
.map(eventController._createRecurrentOccurrence)
|
2020-01-30 12:37:19 +01:00
|
|
|
|
|
|
|
return Promise.all(creations)
|
|
|
|
}
|
2019-04-03 00:25:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = eventController
|