Implement unfollow by remote account
This commit is contained in:
		
							parent
							
								
									1a347ae9a0
								
							
						
					
					
						commit
						6b66ec1231
					
				
					 6 changed files with 108 additions and 37 deletions
				
			
		| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
import User from '../../models/user';
 | 
					import User from '../../models/user';
 | 
				
			||||||
import act from '../../remote/activitypub/act';
 | 
					import act from '../../remote/activitypub/act';
 | 
				
			||||||
 | 
					import Resolver from '../../remote/activitypub/resolver';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default ({ data }) => User.findOne({ _id: data.actor })
 | 
					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 User, { IRemoteUser } from '../../models/user';
 | 
				
			||||||
import act from '../../remote/activitypub/act';
 | 
					import act from '../../remote/activitypub/act';
 | 
				
			||||||
import resolvePerson from '../../remote/activitypub/resolve-person';
 | 
					import resolvePerson from '../../remote/activitypub/resolve-person';
 | 
				
			||||||
 | 
					import Resolver from '../../remote/activitypub/resolver';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default async ({ data }) => {
 | 
					export default async ({ data }) => {
 | 
				
			||||||
	const keyIdLower = data.signature.keyId.toLowerCase();
 | 
						const keyIdLower = data.signature.keyId.toLowerCase();
 | 
				
			||||||
| 
						 | 
					@ -34,5 +35,5 @@ export default async ({ data }) => {
 | 
				
			||||||
		throw 'signature verification failed';
 | 
							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 { MongoError } from 'mongodb';
 | 
				
			||||||
import parseAcct from '../../../acct/parse';
 | 
					import parseAcct from '../../../acct/parse';
 | 
				
			||||||
import Following from '../../../models/following';
 | 
					import Following, { IFollowing } from '../../../models/following';
 | 
				
			||||||
import User from '../../../models/user';
 | 
					import User from '../../../models/user';
 | 
				
			||||||
import config from '../../../config';
 | 
					import config from '../../../config';
 | 
				
			||||||
import queue from '../../../queue';
 | 
					import queue from '../../../queue';
 | 
				
			||||||
| 
						 | 
					@ -8,7 +8,7 @@ import context from '../renderer/context';
 | 
				
			||||||
import renderAccept from '../renderer/accept';
 | 
					import renderAccept from '../renderer/accept';
 | 
				
			||||||
import request from '../../request';
 | 
					import request from '../../request';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default async (actor, activity) => {
 | 
					export default async (resolver, actor, activity, distribute) => {
 | 
				
			||||||
	const prefix = config.url + '/@';
 | 
						const prefix = config.url + '/@';
 | 
				
			||||||
	const id = activity.object.id || activity.object;
 | 
						const id = activity.object.id || activity.object;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,33 +26,52 @@ export default async (actor, activity) => {
 | 
				
			||||||
		throw new Error();
 | 
							throw new Error();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const accept = renderAccept(activity);
 | 
						if (!distribute) {
 | 
				
			||||||
	accept['@context'] = context;
 | 
							const { _id } = await Following.findOne({
 | 
				
			||||||
 | 
								followerId: actor._id,
 | 
				
			||||||
 | 
								followeeId: followee._id
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	await Promise.all([
 | 
							return {
 | 
				
			||||||
		request(followee, actor.account.inbox, accept),
 | 
								resolver,
 | 
				
			||||||
 | 
								object: { $ref: 'following', $id: _id }
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Following.insert({
 | 
						const promisedFollowing = Following.insert({
 | 
				
			||||||
		createdAt: new Date(),
 | 
							createdAt: new Date(),
 | 
				
			||||||
		followerId: actor._id,
 | 
							followerId: actor._id,
 | 
				
			||||||
		followeeId: followee._id
 | 
							followeeId: followee._id
 | 
				
			||||||
	}).then(following => new Promise((resolve, reject) => {
 | 
						}).then(following => new Promise((resolve, reject) => {
 | 
				
			||||||
			queue.create('http', { type: 'follow', following: following._id }).save(error => {
 | 
							queue.create('http', {
 | 
				
			||||||
 | 
								type: 'follow',
 | 
				
			||||||
 | 
								following: following._id
 | 
				
			||||||
 | 
							}).save(error => {
 | 
				
			||||||
			if (error) {
 | 
								if (error) {
 | 
				
			||||||
				reject(error);
 | 
									reject(error);
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
					resolve();
 | 
									resolve(following);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
		}), error => {
 | 
						}) as Promise<IFollowing>, async error => {
 | 
				
			||||||
		// duplicate key error
 | 
							// duplicate key error
 | 
				
			||||||
		if (error instanceof MongoError && error.code === 11000) {
 | 
							if (error instanceof MongoError && error.code === 11000) {
 | 
				
			||||||
				return;
 | 
								return Following.findOne({
 | 
				
			||||||
 | 
									followerId: actor._id,
 | 
				
			||||||
 | 
									followeeId: followee._id
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		throw error;
 | 
							throw error;
 | 
				
			||||||
		})
 | 
						});
 | 
				
			||||||
	]);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return null;
 | 
						const accept = renderAccept(activity);
 | 
				
			||||||
 | 
						accept['@context'] = context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						await request(followee, actor.account.inbox, accept);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return promisedFollowing.then(({ _id }) => ({
 | 
				
			||||||
 | 
							resolver,
 | 
				
			||||||
 | 
							object: { $ref: 'following', $id: _id }
 | 
				
			||||||
 | 
						}));
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,23 +1,26 @@
 | 
				
			||||||
import create from './create';
 | 
					import create from './create';
 | 
				
			||||||
import follow from './follow';
 | 
					import follow from './follow';
 | 
				
			||||||
 | 
					import undo from './undo';
 | 
				
			||||||
import createObject from '../create';
 | 
					import createObject from '../create';
 | 
				
			||||||
import Resolver from '../resolver';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default (actor, value, distribute) => {
 | 
					export default (resolver, actor, value, distribute?: boolean) => {
 | 
				
			||||||
	return new Resolver().resolve(value).then(resolved => Promise.all(resolved.map(async promisedResult => {
 | 
						return resolver.resolve(value).then(resolved => Promise.all(resolved.map(async promisedResult => {
 | 
				
			||||||
		const { resolver, object } = await promisedResult;
 | 
							const result = await promisedResult;
 | 
				
			||||||
		const created = await (await createObject(resolver, actor, [object], distribute))[0];
 | 
							const created = await (await createObject(result.resolver, actor, [result.object], distribute))[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (created !== null) {
 | 
							if (created !== null) {
 | 
				
			||||||
			return created;
 | 
								return created;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		switch (object.type) {
 | 
							switch (result.object.type) {
 | 
				
			||||||
		case 'Create':
 | 
							case 'Create':
 | 
				
			||||||
			return create(resolver, actor, object, distribute);
 | 
								return create(result.resolver, actor, result.object, distribute);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case 'Follow':
 | 
							case 'Follow':
 | 
				
			||||||
			return follow(actor, object);
 | 
								return follow(result.resolver, actor, result.object, distribute);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							case 'Undo':
 | 
				
			||||||
 | 
								return undo(result.resolver, actor, result.object);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			return null;
 | 
								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
 | 
				
			||||||
 | 
							})),
 | 
				
			||||||
 | 
						]);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue