194 lines
5.9 KiB
JavaScript
194 lines
5.9 KiB
JavaScript
const log = require('../log')
|
|
const helpers = require('../helpers')
|
|
const linkifyHtml = require('linkify-html')
|
|
const dayjs = require('dayjs')
|
|
const { Event, User, Tag, Place, APUser, Resource, EventNotification } = require('../api/models/models')
|
|
const tagController = require('../api/controller/tag')
|
|
const Helpers = require('./helpers')
|
|
|
|
module.exports = {
|
|
|
|
async get (req, res) {
|
|
const { preferHTML } = require('../helpers')
|
|
const event_id = req.params.event_id
|
|
const json = req.params.json
|
|
if (preferHTML(req) && !json) {
|
|
return res.redirect(302, `/event/${event_id}`)
|
|
}
|
|
const event = await Event.findByPk(req.params.event_id, { include: [User, Tag, Place] })
|
|
if (!event) {
|
|
log.debug(`[FEDI] Event not found - ${req.path}`)
|
|
return res.status(404).send('Not found')
|
|
}
|
|
|
|
log.debug(`[FEDI] Get event details - ${event.slug}`)
|
|
const eventAp = event.toAP(res.locals.settings)
|
|
eventAp['@context'] = [
|
|
'https://www.w3.org/ns/activitystreams',
|
|
'https://w3id.org/security/v1',
|
|
{
|
|
toot: 'http://joinmastodon.org/ns#',
|
|
|
|
// A property-value pair, e.g. representing a feature of a product or place. We use this to publish this very same instance
|
|
// https://docs.joinmastodon.org/spec/activitypub/#PropertyValue
|
|
schema: 'http://schema.org#',
|
|
ProperyValue: 'schema:PropertyValue',
|
|
value: 'schema:value',
|
|
|
|
// https://docs.joinmastodon.org/spec/activitypub/#discoverable
|
|
"discoverable": "toot:discoverable",
|
|
|
|
// https://docs.joinmastodon.org/spec/activitypub/#Hashtag
|
|
"Hashtag": "https://www.w3.org/ns/activitystreams#Hashtag",
|
|
|
|
manuallyApprovesFollowers: 'as:manuallyApprovesFollowers',
|
|
|
|
// focal point - https://docs.joinmastodon.org/spec/activitypub/#focalPoint
|
|
"focalPoint": {
|
|
"@container": "@list",
|
|
"@id": "toot:focalPoint"
|
|
}
|
|
}
|
|
]
|
|
|
|
res.type('application/activity+json; charset=utf-8')
|
|
return res.json(eventAp)
|
|
},
|
|
|
|
// create an Event from AP
|
|
async create (req, res) {
|
|
|
|
try {
|
|
await Helpers.parseAPEvent(req.body, res.locals.fedi_user)
|
|
} catch (e) {
|
|
log.error('[FEDI] Error parsing AP Event: %s', e?.message ?? e)
|
|
return res.status(400).send("Error parsing AP Event")
|
|
}
|
|
|
|
return res.sendStatus(201)
|
|
|
|
},
|
|
|
|
// update an event from AP
|
|
async update (req, res) {
|
|
const APEvent = req.body?.object
|
|
|
|
// check if this event is new
|
|
const ap_id = APEvent?.id ?? APEvent
|
|
|
|
if (!ap_id) {
|
|
log.warn('[FEDI] id not found in body.object')
|
|
return res.sendStatus(404)
|
|
}
|
|
|
|
const event = await Event.findOne({ where: { ap_id }, include: [APUser]})
|
|
if (!event) {
|
|
log.warn('[FEDI] Event with this ap_id not found: %s', ap_id)
|
|
return res.sendStatus(404)
|
|
}
|
|
|
|
// is the owner the same?
|
|
if (res.locals.fedi_user.ap_id !== event?.ap_user?.ap_id) {
|
|
log.error('[FEDI] Event %s updated not from the owner! %s != %s', ap_id, res.locals.fedi_user.ap_id, event?.ap_user?.ap_id)
|
|
}
|
|
|
|
const [ place, online_locations ] = await Place.parseAPEvent(APEvent)
|
|
|
|
let media = []
|
|
const image_url = APEvent?.attachment?.find(a => a?.mediaType.includes('image') && a.url)?.url
|
|
if (image_url) {
|
|
|
|
const file = await helpers.getImageFromURL(image_url)
|
|
log.debug('[FEDI] Download attachment for event %s', image_url)
|
|
|
|
media = [{
|
|
url: file.filename,
|
|
height: file.height,
|
|
width: file.width,
|
|
name: APEvent.attachment[0]?.name || APEvent.name.trim() || '',
|
|
size: file.size || 0,
|
|
focalpoint: APEvent.attachment[0]?.focalPoint
|
|
}]
|
|
}
|
|
|
|
// create it
|
|
event.update({
|
|
title: APEvent.name.trim(),
|
|
start_datetime: dayjs(APEvent.startTime).unix(),
|
|
end_datetime: APEvent?.endTime ? dayjs(APEvent.endTime).unix() : null,
|
|
description: helpers.sanitizeHTML(linkifyHtml(APEvent?.content ?? '', { target: '_blank', render: { email: ctx => ctx.content }})),
|
|
online_locations,
|
|
media,
|
|
is_visible: true,
|
|
ap_id,
|
|
ap_object: APEvent,
|
|
apUserApId: req.body.actor,
|
|
})
|
|
|
|
await event.setPlace(place)
|
|
|
|
// create/assign tags
|
|
let tags = []
|
|
if (APEvent.tag) {
|
|
tags = await tagController._findOrCreate(APEvent.tag.map(t => t?.name.substr(1)))
|
|
await event.setTags(tags)
|
|
}
|
|
|
|
return res.status(201).send()
|
|
|
|
},
|
|
|
|
// remove an event from AP
|
|
async remove (req, res) {
|
|
const APEvent = req.body?.object
|
|
const ap_id = APEvent?.id ?? APEvent
|
|
|
|
if (!ap_id) {
|
|
log.warn('[FEDI] Remove Event: missing id')
|
|
return res.sendStatus(404)
|
|
}
|
|
|
|
const event = await Event.findOne({ where: { ap_id }, include: [APUser]})
|
|
if (!event) {
|
|
log.error('[FEDI] Event not found: %s', APEvent?.id ?? APEvent)
|
|
return res.sendStatus(404)
|
|
}
|
|
|
|
// is the owner the same?
|
|
if (res.locals.fedi_user.ap_id !== event?.ap_user?.ap_id) {
|
|
log.error('[FEDI] Event %s updated not from the owner! %s != %s', ap_id, res.locales.fedi_user.ap_id, event)
|
|
}
|
|
|
|
if (event.media && event.media.length && !event.recurrent) {
|
|
try {
|
|
const old_path = path.join(config.upload_path, event.media[0].url)
|
|
const old_thumb_path = path.join(config.upload_path, 'thumb', event.media[0].url)
|
|
await fs.unlink(old_thumb_path)
|
|
await fs.unlink(old_path)
|
|
} catch (e) {
|
|
log.info(e.toString())
|
|
}
|
|
}
|
|
|
|
if (event.recurrent) {
|
|
await Event.update({ parentId: null }, { where: { parentId: event.id } })
|
|
}
|
|
|
|
log.debug('[EVENT REMOVED] ' + event.title)
|
|
try {
|
|
// remove related resources
|
|
await Resource.destroy({ where: { eventId: event.id }})
|
|
|
|
await EventNotification.destroy({ where: { eventId: event.id }})
|
|
// and finally remove the event
|
|
await event.destroy()
|
|
} catch (e) {
|
|
log.error('[FEDI] Error removing event: %s', String(e))
|
|
return res.sendStatus(500)
|
|
}
|
|
|
|
return res.sendStatus(201)
|
|
|
|
}
|
|
|
|
} |