mirror of
				https://github.com/NodeBB/NodeBB.git
				synced 2025-10-30 18:46:01 +01:00 
			
		
		
		
	fix: issues related to adding new reply chains to an existing topic, resolveId method in notes module
This commit is contained in:
		| @@ -8,24 +8,32 @@ const posts = require('../posts'); | ||||
| const activitypub = module.parent.exports; | ||||
| const Notes = module.exports; | ||||
|  | ||||
| Notes.resolveId = async (uid, id) => { | ||||
| 	({ id } = await activitypub.get(uid, id)); | ||||
| 	return id; | ||||
| }; | ||||
|  | ||||
| // todo: when asserted, notes aren't added to a global sorted set | ||||
| // also, db.exists call is probably expensive | ||||
| Notes.assert = async (uid, input) => { | ||||
| 	// Ensures that each note has been saved to the database | ||||
| 	await Promise.all(input.map(async (item) => { | ||||
| 		const id = activitypub.helpers.isUri(item) ? item : item.id; | ||||
| 		const id = activitypub.helpers.isUri(item) ? item : item.pid; | ||||
| 		const key = `post:${id}`; | ||||
| 		const exists = await db.exists(key); | ||||
| 		winston.verbose(`[activitypub/notes.assert] Asserting note id ${id}`); | ||||
|  | ||||
| 		let postData; | ||||
| 		if (!exists) { | ||||
| 			let postData; | ||||
| 			winston.verbose(`[activitypub/notes.assert] Not found, saving note to database`); | ||||
| 			const object = activitypub.helpers.isUri(item) ? await activitypub.get(uid, item) : item; | ||||
| 			if (activitypub.helpers.isUri(item)) { | ||||
| 				const object = await activitypub.get(uid, item); | ||||
| 				postData = await activitypub.mocks.post(object); | ||||
| 			if (postData) { | ||||
| 				await db.setObject(key, postData); | ||||
| 			} else { | ||||
| 				postData = item; | ||||
| 			} | ||||
|  | ||||
| 			await db.setObject(key, postData); | ||||
| 		} | ||||
| 	})); | ||||
| }; | ||||
| @@ -59,21 +67,41 @@ Notes.getParentChain = async (uid, input) => { | ||||
| 	return chain; | ||||
| }; | ||||
|  | ||||
| Notes.assertParentChain = async (chain) => { | ||||
| 	const data = []; | ||||
| 	chain.reduce((child, parent) => { | ||||
| 		data.push([`pid:${parent.pid}:replies`, child.timestamp, child.pid]); | ||||
| 		return parent; | ||||
| 	}); | ||||
|  | ||||
| 	await db.sortedSetAddBulk(data); | ||||
| }; | ||||
|  | ||||
| Notes.assertTopic = async (uid, id) => { | ||||
| 	// Given the id of any post, traverses up (and soon, down) to cache the entire threaded context | ||||
| 	/** | ||||
| 	 * Given the id of any post, traverses up to cache the entire threaded context | ||||
| 	 * | ||||
| 	 * Unfortunately, due to limitations and fragmentation of the existing ActivityPub landscape, | ||||
| 	 * retrieving the entire reply tree is not possible at this time. | ||||
| 	 */ | ||||
|  | ||||
| 	const chain = Array.from(await Notes.getParentChain(uid, id)); | ||||
| 	const tid = chain[chain.length - 1].pid; | ||||
|  | ||||
| 	const sorted = chain.sort((a, b) => a.timestamp - b.timestamp); | ||||
| 	const [ids, timestamps] = [ | ||||
| 		sorted.map(n => n.id), | ||||
| 		sorted.map(n => n.timestamp), | ||||
| 	]; | ||||
| 	const members = await db.isSortedSetMembers(`tidRemote:${tid}:posts`, chain.map(p => p.pid)); | ||||
| 	if (members.every(Boolean)) { | ||||
| 		// All cached, return early. | ||||
| 		winston.info('[notes/assertTopic] No new notes to process.'); | ||||
| 		return tid; | ||||
| 	} | ||||
|  | ||||
| 	const postercount = chain.reduce((set, cur) => { | ||||
| 		set.add(cur.uid); | ||||
| 		return set; | ||||
| 	}, new Set()); | ||||
| 	const unprocessed = chain.filter((p, idx) => !members[idx]); | ||||
| 	winston.info(`[notes/assertTopic] ${unprocessed.length} new notes found.`); | ||||
|  | ||||
| 	const [ids, timestamps] = [ | ||||
| 		unprocessed.map(n => n.pid), | ||||
| 		unprocessed.map(n => n.timestamp), | ||||
| 	]; | ||||
|  | ||||
| 	await Promise.all([ | ||||
| 		db.setObject(`topicRemote:${tid}`, { | ||||
| @@ -83,16 +111,32 @@ Notes.assertTopic = async (uid, id) => { | ||||
| 			mainPid: tid, | ||||
| 			title: 'TBD', | ||||
| 			slug: `remote?resource=${encodeURIComponent(tid)}`, | ||||
| 			postcount: sorted.length, | ||||
| 			postercount, | ||||
| 		}), | ||||
| 		db.sortedSetAdd(`tidRemote:${tid}:posts`, timestamps, ids), | ||||
| 		Notes.assert(uid, chain), | ||||
| 		Notes.assert(uid, unprocessed), | ||||
| 	]); | ||||
| 	await Promise.all([ // must be done after .assert() | ||||
| 		Notes.assertParentChain(chain), | ||||
| 		Notes.updateTopicCounts(tid), | ||||
| 	]); | ||||
|  | ||||
| 	return tid; | ||||
| }; | ||||
|  | ||||
| Notes.updateTopicCounts = async function (tid) { | ||||
| 	const pids = await db.getSortedSetMembers(`tidRemote:${tid}:posts`); | ||||
| 	let uids = await db.getObjectsFields(pids.map(p => `post:${p}`), ['uid']); | ||||
| 	uids = uids.reduce((set, { uid }) => { | ||||
| 		set.add(uid); | ||||
| 		return set; | ||||
| 	}, new Set()); | ||||
|  | ||||
| 	db.setObject(`topicRemote:${tid}`, { | ||||
| 		postercount: uids.size, | ||||
| 		postcount: pids.length, | ||||
| 	}); | ||||
| }; | ||||
|  | ||||
| Notes.getTopicPosts = async (tid, uid, start, stop) => { | ||||
| 	const pids = await db.getSortedSetRange(`tidRemote:${tid}:posts`, start, stop); | ||||
| 	return await posts.getPostsByPids(pids, uid); | ||||
|   | ||||
| @@ -9,10 +9,16 @@ const topics = require('../../topics'); | ||||
| const { notes } = require('../../activitypub'); | ||||
| // const helpers = require('../helpers'); | ||||
| const pagination = require('../../pagination'); | ||||
| const helpers = require('../helpers'); | ||||
|  | ||||
| const controller = module.exports; | ||||
|  | ||||
| controller.get = async function (req, res, next) { | ||||
| 	const pid = await notes.resolveId(req.uid, req.query.resource); | ||||
| 	if (pid !== req.query.resource) { | ||||
| 		return helpers.redirect(res, `/topic/remote?resource=${pid}`, true); | ||||
| 	} | ||||
|  | ||||
| 	const tid = await notes.assertTopic(req.uid, req.query.resource); | ||||
|  | ||||
| 	let postIndex = await db.sortedSetRank(`tidRemote:${tid}:posts`, req.query.resource); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user