2025-02-15 22:42:25 +01:00

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)
}
}