Implement unfollow by remote account
This commit is contained in:
		| @@ -1,5 +1,6 @@ | ||||
| import User from '../../models/user'; | ||||
| import act from '../../remote/activitypub/act'; | ||||
| import Resolver from '../../remote/activitypub/resolver'; | ||||
|  | ||||
| export default ({ data }) => User.findOne({ _id: data.actor }) | ||||
| 	.then(actor => act(actor, data.outbox, false)); | ||||
| 	.then(actor => act(new Resolver(), actor, data.outbox)); | ||||
|   | ||||
| @@ -3,6 +3,7 @@ import parseAcct from '../../acct/parse'; | ||||
| import User, { IRemoteUser } from '../../models/user'; | ||||
| import act from '../../remote/activitypub/act'; | ||||
| import resolvePerson from '../../remote/activitypub/resolve-person'; | ||||
| import Resolver from '../../remote/activitypub/resolver'; | ||||
|  | ||||
| export default async ({ data }) => { | ||||
| 	const keyIdLower = data.signature.keyId.toLowerCase(); | ||||
| @@ -34,5 +35,5 @@ export default async ({ data }) => { | ||||
| 		throw 'signature verification failed'; | ||||
| 	} | ||||
|  | ||||
| 	await act(user, data.inbox, true); | ||||
| 	await act(new Resolver(), user, data.inbox, true); | ||||
| }; | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import { MongoError } from 'mongodb'; | ||||
| import parseAcct from '../../../acct/parse'; | ||||
| import Following from '../../../models/following'; | ||||
| import Following, { IFollowing } from '../../../models/following'; | ||||
| import User from '../../../models/user'; | ||||
| import config from '../../../config'; | ||||
| import queue from '../../../queue'; | ||||
| @@ -8,7 +8,7 @@ import context from '../renderer/context'; | ||||
| import renderAccept from '../renderer/accept'; | ||||
| import request from '../../request'; | ||||
|  | ||||
| export default async (actor, activity) => { | ||||
| export default async (resolver, actor, activity, distribute) => { | ||||
| 	const prefix = config.url + '/@'; | ||||
| 	const id = activity.object.id || activity.object; | ||||
|  | ||||
| @@ -26,33 +26,52 @@ export default async (actor, activity) => { | ||||
| 		throw new Error(); | ||||
| 	} | ||||
|  | ||||
| 	if (!distribute) { | ||||
| 		const { _id } = await Following.findOne({ | ||||
| 			followerId: actor._id, | ||||
| 			followeeId: followee._id | ||||
| 		}) | ||||
|  | ||||
| 		return { | ||||
| 			resolver, | ||||
| 			object: { $ref: 'following', $id: _id } | ||||
| 		}; | ||||
| 	} | ||||
|  | ||||
| 	const promisedFollowing = Following.insert({ | ||||
| 		createdAt: new Date(), | ||||
| 		followerId: actor._id, | ||||
| 		followeeId: followee._id | ||||
| 	}).then(following => new Promise((resolve, reject) => { | ||||
| 		queue.create('http', { | ||||
| 			type: 'follow', | ||||
| 			following: following._id | ||||
| 		}).save(error => { | ||||
| 			if (error) { | ||||
| 				reject(error); | ||||
| 			} else { | ||||
| 				resolve(following); | ||||
| 			} | ||||
| 		}); | ||||
| 	}) as Promise<IFollowing>, async error => { | ||||
| 		// duplicate key error | ||||
| 		if (error instanceof MongoError && error.code === 11000) { | ||||
| 			return Following.findOne({ | ||||
| 				followerId: actor._id, | ||||
| 				followeeId: followee._id | ||||
| 			}); | ||||
| 		} | ||||
|  | ||||
| 		throw error; | ||||
| 	}); | ||||
|  | ||||
| 	const accept = renderAccept(activity); | ||||
| 	accept['@context'] = context; | ||||
|  | ||||
| 	await Promise.all([ | ||||
| 		request(followee, actor.account.inbox, accept), | ||||
| 	await request(followee, actor.account.inbox, accept); | ||||
|  | ||||
| 		Following.insert({ | ||||
| 			createdAt: new Date(), | ||||
| 			followerId: actor._id, | ||||
| 			followeeId: followee._id | ||||
| 		}).then(following => new Promise((resolve, reject) => { | ||||
| 			queue.create('http', { type: 'follow', following: following._id }).save(error => { | ||||
| 				if (error) { | ||||
| 					reject(error); | ||||
| 				} else { | ||||
| 					resolve(); | ||||
| 				} | ||||
| 			}); | ||||
| 		}), error => { | ||||
| 			// duplicate key error | ||||
| 			if (error instanceof MongoError && error.code === 11000) { | ||||
| 				return; | ||||
| 			} | ||||
|  | ||||
| 			throw error; | ||||
| 		}) | ||||
| 	]); | ||||
|  | ||||
| 	return null; | ||||
| 	return promisedFollowing.then(({ _id }) => ({ | ||||
| 		resolver, | ||||
| 		object: { $ref: 'following', $id: _id } | ||||
| 	})); | ||||
| }; | ||||
|   | ||||
| @@ -1,23 +1,26 @@ | ||||
| import create from './create'; | ||||
| import follow from './follow'; | ||||
| import undo from './undo'; | ||||
| import createObject from '../create'; | ||||
| import Resolver from '../resolver'; | ||||
|  | ||||
| export default (actor, value, distribute) => { | ||||
| 	return new Resolver().resolve(value).then(resolved => Promise.all(resolved.map(async promisedResult => { | ||||
| 		const { resolver, object } = await promisedResult; | ||||
| 		const created = await (await createObject(resolver, actor, [object], distribute))[0]; | ||||
| export default (resolver, actor, value, distribute?: boolean) => { | ||||
| 	return resolver.resolve(value).then(resolved => Promise.all(resolved.map(async promisedResult => { | ||||
| 		const result = await promisedResult; | ||||
| 		const created = await (await createObject(result.resolver, actor, [result.object], distribute))[0]; | ||||
|  | ||||
| 		if (created !== null) { | ||||
| 			return created; | ||||
| 		} | ||||
|  | ||||
| 		switch (object.type) { | ||||
| 		switch (result.object.type) { | ||||
| 		case 'Create': | ||||
| 			return create(resolver, actor, object, distribute); | ||||
| 			return create(result.resolver, actor, result.object, distribute); | ||||
|  | ||||
| 		case 'Follow': | ||||
| 			return follow(actor, object); | ||||
| 			return follow(result.resolver, actor, result.object, distribute); | ||||
|  | ||||
| 		case 'Undo': | ||||
| 			return undo(result.resolver, actor, result.object); | ||||
|  | ||||
| 		default: | ||||
| 			return null; | ||||
|   | ||||
							
								
								
									
										23
									
								
								src/remote/activitypub/act/undo/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/remote/activitypub/act/undo/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| import act from '../../act'; | ||||
| import unfollow from './unfollow'; | ||||
|  | ||||
| export default async (resolver, actor, activity) => { | ||||
| 	if ('actor' in activity && actor.account.uri !== activity.actor) { | ||||
| 		throw new Error(); | ||||
| 	} | ||||
|  | ||||
| 	const results = await act(resolver, actor, activity.object); | ||||
|  | ||||
| 	await Promise.all(results.map(async result => { | ||||
| 		if (result === null) { | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		switch (result.object.$ref) { | ||||
| 		case 'following': | ||||
| 			await unfollow(result.resolver, result.object); | ||||
| 		} | ||||
| 	})); | ||||
|  | ||||
| 	return null; | ||||
| }; | ||||
							
								
								
									
										24
									
								
								src/remote/activitypub/act/undo/unfollow.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/remote/activitypub/act/undo/unfollow.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| import FollowedLog from '../../../../models/followed-log'; | ||||
| import Following from '../../../../models/following'; | ||||
| import FollowingLog from '../../../../models/following-log'; | ||||
| import User from '../../../../models/user'; | ||||
|  | ||||
| export default async (resolver, { $id }) => { | ||||
| 	const following = await Following.findOneAndDelete({ _id: $id }); | ||||
| 	if (following === null) { | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	await Promise.all([ | ||||
| 		User.update({ _id: following.followerId }, { $inc: { followingCount: -1 } }), | ||||
| 		User.findOne({ _id: following.followerId }).then(({ followingCount }) => FollowingLog.insert({ | ||||
| 			userId: following.followerId, | ||||
| 			count: followingCount - 1 | ||||
| 		})), | ||||
| 		User.update({ _id: following.followeeId }, { $inc: { followersCount: -1 } }), | ||||
| 		User.findOne({ _id: following.followeeId }).then(({ followersCount }) => FollowedLog.insert({ | ||||
| 			userId: following.followeeId, | ||||
| 			count: followersCount - 1 | ||||
| 		})), | ||||
| 	]); | ||||
| }; | ||||
		Reference in New Issue
	
	Block a user
	 Akihiko Odaki
					Akihiko Odaki