mirror of
				https://github.com/NodeBB/NodeBB.git
				synced 2025-10-31 11:05:54 +01:00 
			
		
		
		
	feat: Announce(Note) and Undo(Announce)
This commit is contained in:
		| @@ -5,6 +5,7 @@ const winston = require('winston'); | ||||
| const db = require('../database'); | ||||
| const user = require('../user'); | ||||
| const posts = require('../posts'); | ||||
| const topics = require('../topics'); | ||||
| const categories = require('../categories'); | ||||
| const activitypub = require('.'); | ||||
|  | ||||
| @@ -65,6 +66,46 @@ inbox.like = async (req) => { | ||||
| 	await posts.upvote(id, actor); | ||||
| }; | ||||
|  | ||||
| inbox.announce = async (req) => { | ||||
| 	const { actor, object, published } = req.body; | ||||
| 	let timestamp = Date.now(); | ||||
| 	try { | ||||
| 		timestamp = new Date(published).getTime(); | ||||
| 	} catch (e) { | ||||
| 		// ok to fail | ||||
| 	} | ||||
|  | ||||
| 	const { type, id } = await activitypub.helpers.resolveLocalId(object); | ||||
| 	if (type !== 'post' || !(await posts.exists(id))) { | ||||
| 		throw new Error('[[error:activitypub.invalid-id]]'); | ||||
| 	} | ||||
|  | ||||
| 	const assertion = await activitypub.actors.assert(actor); | ||||
| 	if (!assertion) { | ||||
| 		throw new Error('[[error:activitypub.invalid-id]]'); | ||||
| 	} | ||||
|  | ||||
| 	const tid = await posts.getPostField(id, 'tid'); | ||||
|  | ||||
| 	// No double-announce allowed | ||||
| 	const existing = await topics.events.find(tid, { | ||||
| 		type: 'announce', | ||||
| 		uid: actor, | ||||
| 		pid: id, | ||||
| 	}); | ||||
| 	if (existing.length) { | ||||
| 		await topics.events.purge(tid, existing); | ||||
| 	} | ||||
|  | ||||
| 	await topics.events.log(tid, { | ||||
| 		type: 'announce', | ||||
| 		uid: actor, | ||||
| 		href: `/post/${id}`, | ||||
| 		pid: id, | ||||
| 		timestamp, | ||||
| 	}); | ||||
| }; | ||||
|  | ||||
| inbox.follow = async (req) => { | ||||
| 	// Sanity checks | ||||
| 	const { type, id } = await helpers.resolveLocalId(req.body.object); | ||||
| @@ -157,6 +198,10 @@ inbox.undo = async (req) => { | ||||
| 	const { actor, object } = req.body; | ||||
| 	const { type } = object; | ||||
|  | ||||
| 	if (actor !== object.actor) { | ||||
| 		throw new Error('[[error:activitypub.actor-mismatch]]'); | ||||
| 	} | ||||
|  | ||||
| 	const assertion = await activitypub.actors.assert(actor); | ||||
| 	if (!assertion) { | ||||
| 		throw new Error('[[error:activitypub.invalid-id]]'); | ||||
| @@ -202,5 +247,23 @@ inbox.undo = async (req) => { | ||||
| 			await posts.unvote(id, actor); | ||||
| 			break; | ||||
| 		} | ||||
|  | ||||
| 		case 'Announce': { | ||||
| 			const exists = await posts.exists(id); | ||||
| 			if (localType !== 'post' || !exists) { | ||||
| 				throw new Error('[[error:invalid-pid]]'); | ||||
| 			} | ||||
|  | ||||
| 			const tid = await posts.getPostField(id, 'tid'); | ||||
| 			const existing = await topics.events.find(tid, { | ||||
| 				type: 'announce', | ||||
| 				uid: actor, | ||||
| 				pid: id, | ||||
| 			}); | ||||
|  | ||||
| 			if (existing.length) { | ||||
| 				await topics.events.purge(tid, existing); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| }; | ||||
|   | ||||
| @@ -237,3 +237,15 @@ ActivityPub.send = async (type, id, targets, payload) => { | ||||
| 		} | ||||
| 	})); | ||||
| }; | ||||
|  | ||||
| setTimeout(async () => { | ||||
| 	await ActivityPub.send('uid', 1, 'https://localhost/uid/1', { | ||||
| 		// type: 'Undo', | ||||
| 		// object: { | ||||
| 		type: 'Announce', | ||||
| 		actor: `https://localhost/uid/1`, | ||||
| 		object: 'https://localhost/post/1', | ||||
| 		published: new Date().toISOString(), | ||||
| 		// }, | ||||
| 	}); | ||||
| }, 2000); | ||||
|   | ||||
| @@ -112,42 +112,11 @@ Controller.getInbox = async (req, res) => { | ||||
|  | ||||
| Controller.postInbox = async (req, res) => { | ||||
| 	// Note: underlying methods are internal use only, hence no exposure via src/api | ||||
| 	switch (req.body.type) { | ||||
| 		case 'Create': { | ||||
| 			await activitypub.inbox.create(req); | ||||
| 			break; | ||||
| 		} | ||||
|  | ||||
| 		case 'Update': { | ||||
| 			await activitypub.inbox.update(req); | ||||
| 			break; | ||||
| 		} | ||||
|  | ||||
| 		case 'Like': { | ||||
| 			await activitypub.inbox.like(req); | ||||
| 			break; | ||||
| 		} | ||||
|  | ||||
| 		case 'Follow': { | ||||
| 			await activitypub.inbox.follow(req); | ||||
| 			break; | ||||
| 		} | ||||
|  | ||||
| 		case 'Accept': { | ||||
| 			await activitypub.inbox.accept(req); | ||||
| 			break; | ||||
| 		} | ||||
|  | ||||
| 		case 'Undo': { | ||||
| 			await activitypub.inbox.undo(req); | ||||
| 			break; | ||||
| 		} | ||||
|  | ||||
| 		default: { | ||||
| 			res.sendStatus(501); | ||||
| 			break; | ||||
| 		} | ||||
| 	const method = String(req.body.type).toLowerCase(); | ||||
| 	if (req.body.hasOwnProperty(method)) { | ||||
| 		return res.sendStatus(501); | ||||
| 	} | ||||
|  | ||||
| 	await activitypub.inbox[method](req); | ||||
| 	res.sendStatus(200); | ||||
| }; | ||||
|   | ||||
| @@ -68,6 +68,10 @@ Events._types = { | ||||
| 		icon: 'fa-code-fork', | ||||
| 		translation: async (event, language) => translateEventArgs(event, language, 'topic:user-forked-topic', renderUser(event), `${relative_path}${event.href}`, renderTimeago(event)), | ||||
| 	}, | ||||
| 	announce: { | ||||
| 		icon: 'fa-share-alt', | ||||
| 		translation: async (event, language) => translateEventArgs(event, language, 'activitypub:topic-event-announce', renderUser(event), `${relative_path}${event.href}`, renderTimeago(event)), | ||||
| 	}, | ||||
| }; | ||||
|  | ||||
| Events.init = async () => { | ||||
| @@ -199,8 +203,9 @@ async function modifyEvent({ tid, uid, eventIds, timestamps, events }) { | ||||
| 		event.id = parseInt(eventIds[idx], 10); | ||||
| 		event.timestamp = timestamps[idx]; | ||||
| 		event.timestampISO = new Date(timestamps[idx]).toISOString(); | ||||
| 		event.uid = utils.isNumber(event.uid) ? parseInt(event.uid, 10) : event.uid; | ||||
| 		if (event.hasOwnProperty('uid')) { | ||||
| 			event.user = users.get(event.uid === 'system' ? 'system' : parseInt(event.uid, 10)); | ||||
| 			event.user = users.get(event.uid === 'system' ? 'system' : event.uid); | ||||
| 		} | ||||
| 		if (event.hasOwnProperty('fromCid')) { | ||||
| 			event.fromCategory = fromCategories[event.fromCid]; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user