| 
									
										
										
										
											2024-05-09 15:48:58 -04:00
										 |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const assert = require('assert'); | 
					
						
							| 
									
										
										
										
											2025-02-26 12:29:36 -05:00
										 |  |  | const nconf = require('nconf'); | 
					
						
							| 
									
										
										
										
											2024-05-09 15:48:58 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-28 13:36:54 -05:00
										 |  |  | const db = require('../mocks/databasemock'); | 
					
						
							| 
									
										
										
										
											2025-02-25 14:24:56 -05:00
										 |  |  | const meta = require('../../src/meta'); | 
					
						
							|  |  |  | const install = require('../../src/install'); | 
					
						
							| 
									
										
										
										
											2024-05-09 15:48:58 -04:00
										 |  |  | const user = require('../../src/user'); | 
					
						
							|  |  |  | const categories = require('../../src/categories'); | 
					
						
							| 
									
										
										
										
											2025-02-26 12:29:36 -05:00
										 |  |  | const posts = require('../../src/posts'); | 
					
						
							| 
									
										
										
										
											2024-05-09 15:48:58 -04:00
										 |  |  | const topics = require('../../src/topics'); | 
					
						
							| 
									
										
										
										
											2025-03-17 14:52:52 -04:00
										 |  |  | const api = require('../../src/api'); | 
					
						
							| 
									
										
										
										
											2024-05-09 15:48:58 -04:00
										 |  |  | const activitypub = require('../../src/activitypub'); | 
					
						
							|  |  |  | const utils = require('../../src/utils'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-26 12:29:36 -05:00
										 |  |  | const helpers = require('./helpers'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-09 15:48:58 -04:00
										 |  |  | describe('Notes', () => { | 
					
						
							| 
									
										
										
										
											2025-03-21 14:16:33 -04:00
										 |  |  | 	before(async () => { | 
					
						
							|  |  |  | 		meta.config.activitypubEnabled = 1; | 
					
						
							|  |  |  | 		await install.giveWorldPrivileges(); | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2025-02-25 14:24:56 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-21 14:16:33 -04:00
										 |  |  | 	describe('Assertion', () => { | 
					
						
							| 
									
										
										
										
											2025-03-17 14:52:52 -04:00
										 |  |  | 		describe('Public objects', () => { | 
					
						
							| 
									
										
										
										
											2025-02-26 12:29:36 -05:00
										 |  |  | 			it('should pull a remote root-level object by its id and create a new topic', async () => { | 
					
						
							|  |  |  | 				const { id } = helpers.mocks.note(); | 
					
						
							| 
									
										
										
										
											2025-02-26 13:06:31 -05:00
										 |  |  | 				const assertion = await activitypub.notes.assert(0, id, { skipChecks: true }); | 
					
						
							|  |  |  | 				assert(assertion); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				const { tid, count } = assertion; | 
					
						
							|  |  |  | 				assert(tid); | 
					
						
							| 
									
										
										
										
											2025-02-26 12:29:36 -05:00
										 |  |  | 				assert.strictEqual(count, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				const exists = await topics.exists(tid); | 
					
						
							|  |  |  | 				assert(exists); | 
					
						
							| 
									
										
										
										
											2025-02-25 14:24:56 -05:00
										 |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-26 12:29:36 -05:00
										 |  |  | 			it('should assert if the cc property is missing', async () => { | 
					
						
							|  |  |  | 				const { id } = helpers.mocks.note({ cc: 'remove' }); | 
					
						
							| 
									
										
										
										
											2025-02-26 13:06:31 -05:00
										 |  |  | 				const assertion = await activitypub.notes.assert(0, id, { skipChecks: true }); | 
					
						
							|  |  |  | 				assert(assertion); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				const { tid, count } = assertion; | 
					
						
							|  |  |  | 				assert(tid); | 
					
						
							|  |  |  | 				assert.strictEqual(count, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				const exists = await topics.exists(tid); | 
					
						
							|  |  |  | 				assert(exists); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			it('should assert if the object is of type Video', async () => { | 
					
						
							|  |  |  | 				const { id } = helpers.mocks.note({ | 
					
						
							|  |  |  | 					type: 'Video', | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 				const assertion = await activitypub.notes.assert(0, id, { skipChecks: true }); | 
					
						
							|  |  |  | 				assert(assertion); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				const { tid, count } = assertion; | 
					
						
							|  |  |  | 				assert(tid); | 
					
						
							| 
									
										
										
										
											2025-02-26 12:29:36 -05:00
										 |  |  | 				assert.strictEqual(count, 1); | 
					
						
							| 
									
										
										
										
											2025-02-25 14:24:56 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-26 12:29:36 -05:00
										 |  |  | 				const exists = await topics.exists(tid); | 
					
						
							|  |  |  | 				assert(exists); | 
					
						
							|  |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2025-03-17 12:02:43 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-17 14:52:52 -04:00
										 |  |  | 			describe('Category-specific behaviours', () => { | 
					
						
							|  |  |  | 				it('should slot newly created topic in local category if addressed', async () => { | 
					
						
							|  |  |  | 					const { cid } = await categories.create({ name: utils.generateUUID() }); | 
					
						
							|  |  |  | 					const { id } = helpers.mocks.note({ | 
					
						
							|  |  |  | 						cc: [`${nconf.get('url')}/category/${cid}`], | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					const assertion = await activitypub.notes.assert(0, id); | 
					
						
							|  |  |  | 					assert(assertion); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					const { tid, count } = assertion; | 
					
						
							|  |  |  | 					assert(tid); | 
					
						
							|  |  |  | 					assert.strictEqual(count, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					const topic = await topics.getTopicData(tid); | 
					
						
							|  |  |  | 					assert.strictEqual(topic.cid, cid); | 
					
						
							| 
									
										
										
										
											2025-03-17 12:02:43 -04:00
										 |  |  | 				}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-20 13:02:30 -04:00
										 |  |  | 				it('should add a remote category topic to a user\'s inbox if they are following the category', async () => { | 
					
						
							|  |  |  | 					const { id: cid, actor } = helpers.mocks.group(); | 
					
						
							|  |  |  | 					await activitypub.actors.assertGroup([cid]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					const uid = await user.create({ username: utils.generateUUID() }); | 
					
						
							|  |  |  | 					await api.categories.setWatchState({ uid }, { cid, state: categories.watchStates.tracking }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					const { id } = helpers.mocks.note({ | 
					
						
							|  |  |  | 						cc: [cid], | 
					
						
							|  |  |  | 					}); | 
					
						
							| 
									
										
										
										
											2025-05-13 13:59:34 -04:00
										 |  |  | 					const { tid } = await activitypub.notes.assert(0, id, { cid }); | 
					
						
							| 
									
										
										
										
											2025-03-20 13:02:30 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 					const inInbox = await db.isSortedSetMember(`uid:${uid}:inbox`, tid); | 
					
						
							|  |  |  | 					assert(inInbox); | 
					
						
							|  |  |  | 				}); | 
					
						
							| 
									
										
										
										
											2025-03-17 12:02:43 -04:00
										 |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-17 14:52:52 -04:00
										 |  |  | 			describe('User-specific behaviours', () => { | 
					
						
							|  |  |  | 				let remoteCid; | 
					
						
							|  |  |  | 				let uid; | 
					
						
							| 
									
										
										
										
											2025-03-17 12:02:43 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-17 14:52:52 -04:00
										 |  |  | 				before(async () => { | 
					
						
							|  |  |  | 					// Remote
 | 
					
						
							|  |  |  | 					const { id, actor } = helpers.mocks.group(); | 
					
						
							|  |  |  | 					remoteCid = id; | 
					
						
							|  |  |  | 					await activitypub.actors.assertGroup([id]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// User
 | 
					
						
							|  |  |  | 					uid = await user.create({ username: utils.generateUUID() }); | 
					
						
							|  |  |  | 					await topics.markAllRead(uid); | 
					
						
							| 
									
										
										
										
											2025-03-17 12:02:43 -04:00
										 |  |  | 				}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-17 14:52:52 -04:00
										 |  |  | 				it('should not show up in my unread if it is in cid -1', async () => { | 
					
						
							|  |  |  | 					const { id } = helpers.mocks.note(); | 
					
						
							|  |  |  | 					const assertion = await activitypub.notes.assert(0, id, { skipChecks: 1 }); | 
					
						
							|  |  |  | 					assert(assertion); | 
					
						
							| 
									
										
										
										
											2025-03-17 12:02:43 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-17 14:52:52 -04:00
										 |  |  | 					const unread = await topics.getTotalUnread(uid); | 
					
						
							|  |  |  | 					assert.strictEqual(unread, 0); | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				it('should show up in my recent/unread if I am tracking the remote category', async () => { | 
					
						
							|  |  |  | 					await api.categories.setWatchState({ uid }, { | 
					
						
							|  |  |  | 						cid: remoteCid, | 
					
						
							|  |  |  | 						state: categories.watchStates.tracking, | 
					
						
							|  |  |  | 						uid, | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					const { id } = helpers.mocks.note({ | 
					
						
							|  |  |  | 						cc: [remoteCid], | 
					
						
							|  |  |  | 					}); | 
					
						
							| 
									
										
										
										
											2025-05-13 13:59:34 -04:00
										 |  |  | 					const assertion = await activitypub.notes.assert(0, id, { cid: remoteCid }); | 
					
						
							| 
									
										
										
										
											2025-03-17 14:52:52 -04:00
										 |  |  | 					assert(assertion); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					const unread = await topics.getTotalUnread(uid); | 
					
						
							|  |  |  | 					assert.strictEqual(unread, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					await topics.markAllRead(uid); | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				it('should show up in recent/unread and notify me if I am watching the remote category', async () => { | 
					
						
							|  |  |  | 					await api.categories.setWatchState({ uid }, { | 
					
						
							|  |  |  | 						cid: remoteCid, | 
					
						
							|  |  |  | 						state: categories.watchStates.watching, | 
					
						
							|  |  |  | 						uid, | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					const { id, note } = helpers.mocks.note({ | 
					
						
							|  |  |  | 						cc: [remoteCid], | 
					
						
							|  |  |  | 					}); | 
					
						
							| 
									
										
										
										
											2025-05-13 13:59:34 -04:00
										 |  |  | 					const assertion = await activitypub.notes.assert(0, id, { cid: remoteCid }); | 
					
						
							| 
									
										
										
										
											2025-03-17 14:52:52 -04:00
										 |  |  | 					assert(assertion); | 
					
						
							| 
									
										
										
										
											2025-03-17 12:02:43 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-17 14:52:52 -04:00
										 |  |  | 					const unread = await topics.getTotalUnread(uid); | 
					
						
							|  |  |  | 					assert.strictEqual(unread, 1); | 
					
						
							| 
									
										
										
										
											2025-03-17 12:02:43 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-17 14:52:52 -04:00
										 |  |  | 					// Notification inbox delivery is async so can't test directly
 | 
					
						
							|  |  |  | 					const exists = await db.exists(`notifications:new_topic:tid:${assertion.tid}:uid:${note.attributedTo}`); | 
					
						
							|  |  |  | 					assert(exists); | 
					
						
							| 
									
										
										
										
											2025-03-17 12:02:43 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-17 14:52:52 -04:00
										 |  |  | 					await topics.markAllRead(uid); | 
					
						
							| 
									
										
										
										
											2025-03-17 12:02:43 -04:00
										 |  |  | 				}); | 
					
						
							| 
									
										
										
										
											2025-03-25 10:44:39 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				it('should not show up in recent/unread if I am ignoring the remote category', async () => { | 
					
						
							|  |  |  | 					await api.categories.setWatchState({ uid }, { | 
					
						
							|  |  |  | 						cid: remoteCid, | 
					
						
							|  |  |  | 						state: categories.watchStates.ignoring, | 
					
						
							|  |  |  | 						uid, | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					const { id, note } = helpers.mocks.note({ | 
					
						
							|  |  |  | 						cc: [remoteCid], | 
					
						
							|  |  |  | 					}); | 
					
						
							| 
									
										
										
										
											2025-05-13 13:59:34 -04:00
										 |  |  | 					const assertion = await activitypub.notes.assert(0, id, { cid: remoteCid }); | 
					
						
							| 
									
										
										
										
											2025-03-25 10:44:39 -04:00
										 |  |  | 					assert(assertion); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					const unread = await topics.getTotalUnread(uid); | 
					
						
							|  |  |  | 					assert.strictEqual(unread, 0); | 
					
						
							| 
									
										
										
										
											2025-04-23 12:47:16 -04:00
										 |  |  | 				}); | 
					
						
							| 
									
										
										
										
											2025-03-17 12:02:43 -04:00
										 |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2025-02-25 14:24:56 -05:00
										 |  |  | 		}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-26 12:29:36 -05:00
										 |  |  | 		describe('Private objects', () => { | 
					
						
							|  |  |  | 			let recipientUid; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			before(async () => { | 
					
						
							|  |  |  | 				recipientUid = await user.create({ username: utils.generateUUID().slice(0, 8) }); | 
					
						
							| 
									
										
										
										
											2025-02-25 14:24:56 -05:00
										 |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-26 12:29:36 -05:00
										 |  |  | 			it('should NOT create a new topic or post when asserting a private note', async () => { | 
					
						
							|  |  |  | 				const { id, note } = helpers.mocks.note({ | 
					
						
							|  |  |  | 					to: [`${nconf.get('url')}/uid/${recipientUid}`], | 
					
						
							|  |  |  | 					cc: [], | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 				const { activity } = helpers.mocks.create(note); | 
					
						
							|  |  |  | 				const { roomId } = await activitypub.inbox.create({ body: activity }); | 
					
						
							|  |  |  | 				assert(roomId); | 
					
						
							|  |  |  | 				assert(utils.isNumber(roomId)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				const exists = await posts.exists(id); | 
					
						
							|  |  |  | 				assert(!exists); | 
					
						
							|  |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2025-02-25 14:24:56 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-26 12:29:36 -05:00
										 |  |  | 			it('should still assert if the cc property is missing', async () => { | 
					
						
							|  |  |  | 				const { id, note } = helpers.mocks.note({ | 
					
						
							|  |  |  | 					to: [`${nconf.get('url')}/uid/${recipientUid}`], | 
					
						
							|  |  |  | 					cc: 'remove', | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 				const { activity } = helpers.mocks.create(note); | 
					
						
							|  |  |  | 				const { roomId } = await activitypub.inbox.create({ body: activity }); | 
					
						
							|  |  |  | 				assert(roomId); | 
					
						
							|  |  |  | 				assert(utils.isNumber(roomId)); | 
					
						
							|  |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2025-02-25 14:24:56 -05:00
										 |  |  | 		}); | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-21 14:16:33 -04:00
										 |  |  | 	describe('Creation', () => { | 
					
						
							|  |  |  | 		let uid; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		before(async () => { | 
					
						
							|  |  |  | 			uid = await user.create({ username: utils.generateUUID() }); | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		describe('Local categories', () => { | 
					
						
							|  |  |  | 			let cid; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			before(async () => { | 
					
						
							|  |  |  | 				({ cid } = await categories.create({ name: utils.generateUUID() })); | 
					
						
							| 
									
										
										
										
											2025-04-15 10:12:53 -04:00
										 |  |  | 				activitypub._sent.clear(); | 
					
						
							| 
									
										
										
										
											2025-03-21 14:16:33 -04:00
										 |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			afterEach(() => { | 
					
						
							|  |  |  | 				activitypub._sent.clear(); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			describe('new topics', () => { | 
					
						
							|  |  |  | 				let activity; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				before(async () => { | 
					
						
							|  |  |  | 					const { tid } = await api.topics.create({ uid }, { | 
					
						
							|  |  |  | 						cid, | 
					
						
							|  |  |  | 						title: utils.generateUUID(), | 
					
						
							|  |  |  | 						content: utils.generateUUID(), | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					assert(tid); | 
					
						
							|  |  |  | 					assert.strictEqual(activitypub._sent.size, 1); | 
					
						
							|  |  |  | 					const key = Array.from(activitypub._sent.keys())[0]; | 
					
						
							|  |  |  | 					activity = activitypub._sent.get(key); | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				it('should federate out a Create activity', () => { | 
					
						
							|  |  |  | 					assert(activity && activity.to); | 
					
						
							|  |  |  | 					assert.strictEqual(activity.type, 'Create'); | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				it('should have the local category addressed', () => { | 
					
						
							|  |  |  | 					const addressees = new Set([ | 
					
						
							|  |  |  | 						...(activity.to || []), | 
					
						
							|  |  |  | 						...(activity.cc || []), | 
					
						
							|  |  |  | 						...(activity.bcc || []), | 
					
						
							|  |  |  | 						...(activity.object.to || []), | 
					
						
							|  |  |  | 						...(activity.object.cc || []), | 
					
						
							|  |  |  | 						...(activity.object.bcc || []), | 
					
						
							|  |  |  | 					]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					assert(addressees.has(`${nconf.get('url')}/category/${cid}`)); | 
					
						
							|  |  |  | 				}); | 
					
						
							| 
									
										
										
										
											2025-04-17 16:41:00 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				it('should federate out an activity with object of type "Article"', () => { | 
					
						
							|  |  |  | 					assert(activity.object && activity.object.type); | 
					
						
							|  |  |  | 					assert.strictEqual(activity.object.type, 'Article'); | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			describe('new reply', () => { | 
					
						
							|  |  |  | 				let activity; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				before(async () => { | 
					
						
							|  |  |  | 					const { tid } = await api.topics.create({ uid }, { | 
					
						
							|  |  |  | 						cid, | 
					
						
							|  |  |  | 						title: utils.generateUUID(), | 
					
						
							|  |  |  | 						content: utils.generateUUID(), | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 					activitypub._sent.clear(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					const { pid } = await api.topics.reply({ uid }, { | 
					
						
							|  |  |  | 						tid, | 
					
						
							|  |  |  | 						content: utils.generateUUID(), | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					const key = Array.from(activitypub._sent.keys())[0]; | 
					
						
							|  |  |  | 					activity = activitypub._sent.get(key); | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				it('should federate out an activity with object of type "Note"', () => { | 
					
						
							|  |  |  | 					assert(activity.object && activity.object.type); | 
					
						
							|  |  |  | 					assert.strictEqual(activity.object.type, 'Note'); | 
					
						
							| 
									
										
										
										
											2025-04-23 12:47:16 -04:00
										 |  |  | 				}); | 
					
						
							| 
									
										
										
										
											2025-03-21 14:16:33 -04:00
										 |  |  | 			}); | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		describe('Remote Categories', () => { | 
					
						
							|  |  |  | 			let cid; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			before(async () => { | 
					
						
							|  |  |  | 				({ id: cid } = helpers.mocks.group()); | 
					
						
							|  |  |  | 				await activitypub.actors.assert([cid]); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			afterEach(() => { | 
					
						
							|  |  |  | 				activitypub._sent.clear(); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			describe('new topics', () => { | 
					
						
							|  |  |  | 				it('should federate out a Create activity with the remote community addressed', async () => { | 
					
						
							|  |  |  | 					const { tid } = await api.topics.create({ uid }, { | 
					
						
							|  |  |  | 						cid, | 
					
						
							|  |  |  | 						title: utils.generateUUID(), | 
					
						
							|  |  |  | 						content: utils.generateUUID(), | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					assert(tid); | 
					
						
							|  |  |  | 					assert.strictEqual(activitypub._sent.size, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					const key = Array.from(activitypub._sent.keys())[0]; | 
					
						
							|  |  |  | 					const activity = activitypub._sent.get(key); | 
					
						
							|  |  |  | 					assert(activity && activity.to); | 
					
						
							|  |  |  | 					assert.strictEqual(activity.type, 'Create'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					const addressees = new Set([ | 
					
						
							|  |  |  | 						...(activity.to || []), | 
					
						
							|  |  |  | 						...(activity.cc || []), | 
					
						
							|  |  |  | 						...(activity.bcc || []), | 
					
						
							|  |  |  | 						...(activity.object.to || []), | 
					
						
							|  |  |  | 						...(activity.object.cc || []), | 
					
						
							|  |  |  | 						...(activity.object.bcc || []), | 
					
						
							|  |  |  | 					]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					assert(addressees.has(cid)); | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2025-03-21 14:22:22 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			describe('replies', () => { | 
					
						
							|  |  |  | 				it('should federate out a Create activity with the remote community addressed', async () => { | 
					
						
							|  |  |  | 					const { tid } = await api.topics.create({ uid }, { | 
					
						
							|  |  |  | 						cid, | 
					
						
							|  |  |  | 						title: utils.generateUUID(), | 
					
						
							|  |  |  | 						content: utils.generateUUID(), | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					activitypub._sent.clear(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					const postData = await api.topics.reply({ uid }, { | 
					
						
							|  |  |  | 						tid, | 
					
						
							|  |  |  | 						content: utils.generateUUID(), | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					assert(postData); | 
					
						
							|  |  |  | 					assert.strictEqual(activitypub._sent.size, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					const key = Array.from(activitypub._sent.keys())[0]; | 
					
						
							|  |  |  | 					const activity = activitypub._sent.get(key); | 
					
						
							|  |  |  | 					assert(activity && activity.to); | 
					
						
							|  |  |  | 					assert.strictEqual(activity.type, 'Create'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					const addressees = new Set([ | 
					
						
							|  |  |  | 						...(activity.to || []), | 
					
						
							|  |  |  | 						...(activity.cc || []), | 
					
						
							|  |  |  | 						...(activity.bcc || []), | 
					
						
							|  |  |  | 						...(activity.object.to || []), | 
					
						
							|  |  |  | 						...(activity.object.cc || []), | 
					
						
							|  |  |  | 						...(activity.object.bcc || []), | 
					
						
							|  |  |  | 					]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					assert(addressees.has(cid)); | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2025-03-21 14:16:33 -04:00
										 |  |  | 		}); | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-23 13:17:10 -04:00
										 |  |  | 	describe('Inbox handling', () => { | 
					
						
							| 
									
										
										
										
											2025-04-23 12:47:16 -04:00
										 |  |  | 		describe('helper self-check', () => { | 
					
						
							|  |  |  | 			it('should generate a Like activity', () => { | 
					
						
							|  |  |  | 				const object = utils.generateUUID(); | 
					
						
							|  |  |  | 				const { id: actor } = helpers.mocks.person(); | 
					
						
							|  |  |  | 				const { activity } = helpers.mocks.like({ | 
					
						
							|  |  |  | 					object, | 
					
						
							|  |  |  | 					actor, | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				assert.deepStrictEqual(activity, { | 
					
						
							|  |  |  | 					'@context': 'https://www.w3.org/ns/activitystreams', | 
					
						
							|  |  |  | 					id: `${helpers.mocks._baseUrl}/like/${encodeURIComponent(object)}`, | 
					
						
							|  |  |  | 					type: 'Like', | 
					
						
							|  |  |  | 					actor, | 
					
						
							|  |  |  | 					object, | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			it('should generate an Announce activity wrapping a Like activity', () => { | 
					
						
							|  |  |  | 				const object = utils.generateUUID(); | 
					
						
							|  |  |  | 				const { id: actor } = helpers.mocks.person(); | 
					
						
							|  |  |  | 				const { activity: like } = helpers.mocks.like({ | 
					
						
							|  |  |  | 					object, | 
					
						
							|  |  |  | 					actor, | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 				const { id: gActor } = helpers.mocks.group(); | 
					
						
							|  |  |  | 				const { activity } = helpers.mocks.announce({ | 
					
						
							|  |  |  | 					actor: gActor, | 
					
						
							|  |  |  | 					object: like, | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				assert.deepStrictEqual(activity, { | 
					
						
							|  |  |  | 					'@context': 'https://www.w3.org/ns/activitystreams', | 
					
						
							|  |  |  | 					id: `${helpers.mocks._baseUrl}/announce/${encodeURIComponent(like.id)}`, | 
					
						
							|  |  |  | 					type: 'Announce', | 
					
						
							|  |  |  | 					to: [ 'https://www.w3.org/ns/activitystreams#Public' ], | 
					
						
							|  |  |  | 					cc: [ | 
					
						
							|  |  |  | 						`${gActor}/followers`, | 
					
						
							|  |  |  | 					], | 
					
						
							|  |  |  | 					actor: gActor, | 
					
						
							|  |  |  | 					object: like, | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-13 13:59:34 -04:00
										 |  |  | 		describe('Create', () => { | 
					
						
							|  |  |  | 			let uid; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			before(async () => { | 
					
						
							|  |  |  | 				uid = await user.create({ username: utils.generateUUID() }); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			describe('(Note)', () => { | 
					
						
							|  |  |  | 				it('should create a new topic in cid -1', async () => { | 
					
						
							|  |  |  | 					const { note, id } = helpers.mocks.note(); | 
					
						
							|  |  |  | 					const { activity } = helpers.mocks.create(note); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					await db.sortedSetAdd(`followersRemote:${note.attributedTo}`, Date.now(), uid); | 
					
						
							|  |  |  | 					await activitypub.inbox.create({ body: activity }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					assert(await posts.exists(id)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					const cid = await posts.getCidByPid(id); | 
					
						
							|  |  |  | 					assert.strictEqual(cid, -1); | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				it('should create a new topic in cid -1 even if a remote category is addressed', async () => { | 
					
						
							|  |  |  | 					const { id: remoteCid } = helpers.mocks.group(); | 
					
						
							|  |  |  | 					const { note, id } = helpers.mocks.note({ | 
					
						
							|  |  |  | 						audience: [remoteCid], | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 					const { activity } = helpers.mocks.create(note); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					await activitypub.inbox.create({ body: activity }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					assert(await posts.exists(id)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					const cid = await posts.getCidByPid(id); | 
					
						
							|  |  |  | 					assert.strictEqual(cid, -1); | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-23 12:47:16 -04:00
										 |  |  | 		describe('Announce', () => { | 
					
						
							|  |  |  | 			let cid; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			before(async () => { | 
					
						
							|  |  |  | 				({ cid } = await categories.create({ name: utils.generateUUID().slice(0, 8) })); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-13 13:59:34 -04:00
										 |  |  | 			describe('(Create)', () => { | 
					
						
							|  |  |  | 				it('should create a new topic in a remote category if addressed', async () => { | 
					
						
							|  |  |  | 					const { id: remoteCid } = helpers.mocks.group(); | 
					
						
							|  |  |  | 					const { id, note } = helpers.mocks.note({ | 
					
						
							|  |  |  | 						audience: [remoteCid], | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 					let { activity } = helpers.mocks.create(note); | 
					
						
							|  |  |  | 					({ activity } = helpers.mocks.announce({ actor: remoteCid, object: activity })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					await activitypub.inbox.announce({ body: activity }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					assert(await posts.exists(id)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					const cid = await posts.getCidByPid(id); | 
					
						
							|  |  |  | 					assert.strictEqual(cid, remoteCid); | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-23 12:47:16 -04:00
										 |  |  | 			describe('(Note)', () => { | 
					
						
							|  |  |  | 				it('should create a new topic in cid -1 if category not addressed', async () => { | 
					
						
							|  |  |  | 					const { note } = helpers.mocks.note(); | 
					
						
							|  |  |  | 					await activitypub.actors.assert([note.attributedTo]); | 
					
						
							|  |  |  | 					const { activity } = helpers.mocks.announce({ | 
					
						
							|  |  |  | 						object: note, | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 					const uid = await user.create({ username: utils.generateUUID().slice(0, 10) }); | 
					
						
							|  |  |  | 					await db.sortedSetAdd(`followersRemote:${activity.actor}`, Date.now(), uid); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					const beforeCount = await db.sortedSetCard(`cid:-1:tids`); | 
					
						
							|  |  |  | 					await activitypub.inbox.announce({ body: activity }); | 
					
						
							|  |  |  | 					const count = await db.sortedSetCard(`cid:-1:tids`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					assert.strictEqual(count, beforeCount + 1); | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				it('should create a new topic in local category', async () => { | 
					
						
							|  |  |  | 					const { note } = helpers.mocks.note({ | 
					
						
							|  |  |  | 						cc: [`${nconf.get('url')}/category/${cid}`], | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 					await activitypub.actors.assert([note.attributedTo]); | 
					
						
							|  |  |  | 					const { activity } = helpers.mocks.announce({ | 
					
						
							|  |  |  | 						object: note, | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 					const uid = await user.create({ username: utils.generateUUID().slice(0, 10) }); | 
					
						
							|  |  |  | 					await db.sortedSetAdd(`followersRemote:${activity.actor}`, Date.now(), uid); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					const beforeCount = await db.sortedSetCard(`cid:${cid}:tids`); | 
					
						
							|  |  |  | 					await activitypub.inbox.announce({ body: activity }); | 
					
						
							|  |  |  | 					const count = await db.sortedSetCard(`cid:${cid}:tids`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					assert.strictEqual(count, beforeCount + 1); | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			describe('(Like)', () => { | 
					
						
							|  |  |  | 				it('should upvote a local post', async () => { | 
					
						
							|  |  |  | 					const uid = await user.create({ username: utils.generateUUID().slice(0, 10) }); | 
					
						
							|  |  |  | 					const { postData } = await topics.post({ | 
					
						
							|  |  |  | 						cid, | 
					
						
							|  |  |  | 						uid, | 
					
						
							|  |  |  | 						title: utils.generateUUID(), | 
					
						
							|  |  |  | 						content: utils.generateUUID(), | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					const { activity: like } = helpers.mocks.like({ | 
					
						
							|  |  |  | 						object: `${nconf.get('url')}/post/${postData.pid}`, | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 					const { activity } = helpers.mocks.announce({ | 
					
						
							|  |  |  | 						object: like, | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					let { upvotes } = await posts.getPostFields(postData.pid, 'upvotes'); | 
					
						
							|  |  |  | 					assert.strictEqual(upvotes, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					await activitypub.inbox.announce({ body: activity }); | 
					
						
							|  |  |  | 					({ upvotes } = await posts.getPostFields(postData.pid, 'upvotes')); | 
					
						
							|  |  |  | 					assert.strictEqual(upvotes, 1); | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				it('should upvote an asserted remote post', async () => { | 
					
						
							|  |  |  | 					const { id } = helpers.mocks.note(); | 
					
						
							|  |  |  | 					await activitypub.notes.assert(0, [id], { skipChecks: true }); | 
					
						
							|  |  |  | 					const { activity: like } = helpers.mocks.like({ | 
					
						
							|  |  |  | 						object: id, | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 					const { activity } = helpers.mocks.announce({ | 
					
						
							|  |  |  | 						object: like, | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					let { upvotes } = await posts.getPostFields(id, 'upvotes'); | 
					
						
							|  |  |  | 					assert.strictEqual(upvotes, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					await activitypub.inbox.announce({ body: activity }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					({ upvotes } = await posts.getPostFields(id, 'upvotes')); | 
					
						
							|  |  |  | 					assert.strictEqual(upvotes, 1); | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2025-04-23 13:17:10 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			describe('(Update)', () => { | 
					
						
							|  |  |  | 				it('should update a note\'s content', async () => { | 
					
						
							|  |  |  | 					const { id: actor } = helpers.mocks.person(); | 
					
						
							|  |  |  | 					const { id, note } = helpers.mocks.note({ attributedTo: actor }); | 
					
						
							|  |  |  | 					await activitypub.notes.assert(0, [id], { skipChecks: true }); | 
					
						
							|  |  |  | 					note.content = utils.generateUUID(); | 
					
						
							|  |  |  | 					const { activity: update } = helpers.mocks.update({ object: note }); | 
					
						
							|  |  |  | 					const { activity } = helpers.mocks.announce({ object: update }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					await activitypub.inbox.announce({ body: activity }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					const content = await posts.getPostField(id, 'content'); | 
					
						
							|  |  |  | 					assert.strictEqual(content, note.content); | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2025-04-23 12:47:16 -04:00
										 |  |  | 		}); | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-09 15:48:58 -04:00
										 |  |  | 	describe('Inbox Synchronization', () => { | 
					
						
							|  |  |  | 		let cid; | 
					
						
							|  |  |  | 		let uid; | 
					
						
							|  |  |  | 		let topicData; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		before(async () => { | 
					
						
							|  |  |  | 			({ cid } = await categories.create({ name: utils.generateUUID().slice(0, 8) })); | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		beforeEach(async () => { | 
					
						
							|  |  |  | 			uid = await user.create({ username: utils.generateUUID().slice(0, 10) }); | 
					
						
							|  |  |  | 			({ topicData } = await topics.post({ | 
					
						
							|  |  |  | 				cid, | 
					
						
							|  |  |  | 				uid, | 
					
						
							|  |  |  | 				title: utils.generateUUID(), | 
					
						
							|  |  |  | 				content: utils.generateUUID(), | 
					
						
							|  |  |  | 			})); | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		it('should add a topic to a user\'s inbox if user is a recipient in OP', async () => { | 
					
						
							|  |  |  | 			await db.setAdd(`post:${topicData.mainPid}:recipients`, [uid]); | 
					
						
							|  |  |  | 			await activitypub.notes.syncUserInboxes(topicData.tid); | 
					
						
							|  |  |  | 			const inboxed = await db.isSortedSetMember(`uid:${uid}:inbox`, topicData.tid); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			assert.strictEqual(inboxed, true); | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		it('should add a topic to a user\'s inbox if a user is a recipient in a reply', async () => { | 
					
						
							|  |  |  | 			const uid = await user.create({ username: utils.generateUUID().slice(0, 10) }); | 
					
						
							|  |  |  | 			const { pid } = await topics.reply({ | 
					
						
							|  |  |  | 				tid: topicData.tid, | 
					
						
							|  |  |  | 				uid, | 
					
						
							|  |  |  | 				content: utils.generateUUID(), | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 			await db.setAdd(`post:${pid}:recipients`, [uid]); | 
					
						
							|  |  |  | 			await activitypub.notes.syncUserInboxes(topicData.tid); | 
					
						
							|  |  |  | 			const inboxed = await db.isSortedSetMember(`uid:${uid}:inbox`, topicData.tid); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			assert.strictEqual(inboxed, true); | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		it('should maintain a list of recipients at the topic level', async () => { | 
					
						
							|  |  |  | 			await db.setAdd(`post:${topicData.mainPid}:recipients`, [uid]); | 
					
						
							|  |  |  | 			await activitypub.notes.syncUserInboxes(topicData.tid); | 
					
						
							|  |  |  | 			const [isRecipient, count] = await Promise.all([ | 
					
						
							|  |  |  | 				db.isSetMember(`tid:${topicData.tid}:recipients`, uid), | 
					
						
							|  |  |  | 				db.setCount(`tid:${topicData.tid}:recipients`), | 
					
						
							|  |  |  | 			]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			assert(isRecipient); | 
					
						
							|  |  |  | 			assert.strictEqual(count, 1); | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		it('should add topic to a user\'s inbox if it is explicitly passed in as an argument', async () => { | 
					
						
							|  |  |  | 			await activitypub.notes.syncUserInboxes(topicData.tid, uid); | 
					
						
							|  |  |  | 			const inboxed = await db.isSortedSetMember(`uid:${uid}:inbox`, topicData.tid); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			assert.strictEqual(inboxed, true); | 
					
						
							|  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2024-07-05 12:00:19 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		it('should remove a topic from a user\'s inbox if that user is no longer a recipient in any contained posts', async () => { | 
					
						
							|  |  |  | 			await activitypub.notes.syncUserInboxes(topicData.tid, uid); | 
					
						
							|  |  |  | 			await activitypub.notes.syncUserInboxes(topicData.tid); | 
					
						
							|  |  |  | 			const inboxed = await db.isSortedSetMember(`uid:${uid}:inbox`, topicData.tid); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			assert.strictEqual(inboxed, false); | 
					
						
							|  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2024-05-09 15:48:58 -04:00
										 |  |  | 	}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	describe('Deletion', () => { | 
					
						
							|  |  |  | 		let cid; | 
					
						
							|  |  |  | 		let uid; | 
					
						
							|  |  |  | 		let topicData; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		before(async () => { | 
					
						
							|  |  |  | 			({ cid } = await categories.create({ name: utils.generateUUID().slice(0, 8) })); | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		beforeEach(async () => { | 
					
						
							|  |  |  | 			uid = await user.create({ username: utils.generateUUID().slice(0, 10) }); | 
					
						
							|  |  |  | 			({ topicData } = await topics.post({ | 
					
						
							|  |  |  | 				cid, | 
					
						
							|  |  |  | 				uid, | 
					
						
							|  |  |  | 				title: utils.generateUUID(), | 
					
						
							|  |  |  | 				content: utils.generateUUID(), | 
					
						
							|  |  |  | 			})); | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		it('should clean up recipient sets for the post', async () => { | 
					
						
							|  |  |  | 			const { pid } = await topics.reply({ | 
					
						
							|  |  |  | 				pid: `https://example.org/${utils.generateUUID().slice(0, 8)}`, | 
					
						
							|  |  |  | 				tid: topicData.tid, | 
					
						
							|  |  |  | 				uid, | 
					
						
							|  |  |  | 				content: utils.generateUUID(), | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 			await db.setAdd(`post:${pid}:recipients`, [uid]); | 
					
						
							|  |  |  | 			await activitypub.notes.delete([pid]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			const inboxed = await db.isSetMember(`post:${pid}:recipients`, uid); | 
					
						
							|  |  |  | 			assert(!inboxed); | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | }); |