wip
This commit is contained in:
		
							parent
							
								
									5bd1451b61
								
							
						
					
					
						commit
						77f056b4fc
					
				
					 9 changed files with 142 additions and 104 deletions
				
			
		
							
								
								
									
										82
									
								
								src/api/following/create.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								src/api/following/create.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,82 @@
 | 
				
			||||||
 | 
					import User, { isLocalUser, isRemoteUser, pack as packUser, IUser } from '../../models/user';
 | 
				
			||||||
 | 
					import Following from '../../models/following';
 | 
				
			||||||
 | 
					import FollowingLog from '../../models/following-log';
 | 
				
			||||||
 | 
					import FollowedLog from '../../models/followed-log';
 | 
				
			||||||
 | 
					import event from '../../publishers/stream';
 | 
				
			||||||
 | 
					import notify from '../../publishers/notify';
 | 
				
			||||||
 | 
					import context from '../../remote/activitypub/renderer/context';
 | 
				
			||||||
 | 
					import renderFollow from '../../remote/activitypub/renderer/follow';
 | 
				
			||||||
 | 
					import renderAccept from '../../remote/activitypub/renderer/accept';
 | 
				
			||||||
 | 
					import { createHttp } from '../../queue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default async function(follower: IUser, followee: IUser, activity?) {
 | 
				
			||||||
 | 
						const following = await Following.insert({
 | 
				
			||||||
 | 
							createdAt: new Date(),
 | 
				
			||||||
 | 
							followerId: follower._id,
 | 
				
			||||||
 | 
							followeeId: followee._id
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//#region Increment following count
 | 
				
			||||||
 | 
						User.update({ _id: follower._id }, {
 | 
				
			||||||
 | 
							$inc: {
 | 
				
			||||||
 | 
								followingCount: 1
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FollowingLog.insert({
 | 
				
			||||||
 | 
							createdAt: following.createdAt,
 | 
				
			||||||
 | 
							userId: follower._id,
 | 
				
			||||||
 | 
							count: follower.followingCount + 1
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						//#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//#region Increment followers count
 | 
				
			||||||
 | 
						User.update({ _id: followee._id }, {
 | 
				
			||||||
 | 
							$inc: {
 | 
				
			||||||
 | 
								followersCount: 1
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						FollowedLog.insert({
 | 
				
			||||||
 | 
							createdAt: following.createdAt,
 | 
				
			||||||
 | 
							userId: followee._id,
 | 
				
			||||||
 | 
							count: followee.followersCount + 1
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						//#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Publish follow event
 | 
				
			||||||
 | 
						if (isLocalUser(follower)) {
 | 
				
			||||||
 | 
							packUser(followee, follower).then(packed => event(follower._id, 'follow', packed));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Publish followed event
 | 
				
			||||||
 | 
						if (isLocalUser(followee)) {
 | 
				
			||||||
 | 
							packUser(follower, followee).then(packed => event(followee._id, 'followed', packed)),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 通知を作成
 | 
				
			||||||
 | 
							notify(followee._id, follower._id, 'follow');
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (isLocalUser(follower) && isRemoteUser(followee)) {
 | 
				
			||||||
 | 
							const content = renderFollow(follower, followee);
 | 
				
			||||||
 | 
							content['@context'] = context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							createHttp({
 | 
				
			||||||
 | 
								type: 'deliver',
 | 
				
			||||||
 | 
								user: follower,
 | 
				
			||||||
 | 
								content,
 | 
				
			||||||
 | 
								to: followee.account.inbox
 | 
				
			||||||
 | 
							}).save();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (isRemoteUser(follower) && isLocalUser(followee)) {
 | 
				
			||||||
 | 
							const content = renderAccept(activity);
 | 
				
			||||||
 | 
							content['@context'] = context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							createHttp({
 | 
				
			||||||
 | 
								type: 'deliver',
 | 
				
			||||||
 | 
								user: followee,
 | 
				
			||||||
 | 
								content,
 | 
				
			||||||
 | 
								to: follower.account.inbox
 | 
				
			||||||
 | 
							}).save();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,56 +1,63 @@
 | 
				
			||||||
import FollowedLog from '../../models/followed-log';
 | 
					import FollowedLog from '../../../models/followed-log';
 | 
				
			||||||
import Following from '../../models/following';
 | 
					import Following from '../../../models/following';
 | 
				
			||||||
import FollowingLog from '../../models/following-log';
 | 
					import FollowingLog from '../../../models/following-log';
 | 
				
			||||||
import User, { isRemoteUser, pack as packUser } from '../../models/user';
 | 
					import User, { isLocalUser, isRemoteUser, pack as packUser } from '../../../models/user';
 | 
				
			||||||
import stream from '../../publishers/stream';
 | 
					import stream from '../../../publishers/stream';
 | 
				
			||||||
import renderFollow from '../../remote/activitypub/renderer/follow';
 | 
					import renderFollow from '../../../remote/activitypub/renderer/follow';
 | 
				
			||||||
import renderUndo from '../../remote/activitypub/renderer/undo';
 | 
					import renderUndo from '../../../remote/activitypub/renderer/undo';
 | 
				
			||||||
import context from '../../remote/activitypub/renderer/context';
 | 
					import context from '../../../remote/activitypub/renderer/context';
 | 
				
			||||||
import request from '../../remote/request';
 | 
					import request from '../../../remote/request';
 | 
				
			||||||
 | 
					import Logger from '../../../utils/logger';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default async ({ data }) => {
 | 
					export default async ({ data }) => {
 | 
				
			||||||
	// Delete following
 | 
						const following = await Following.findOne({ _id: data.id });
 | 
				
			||||||
	const following = await Following.findOneAndDelete({ _id: data.id });
 | 
					 | 
				
			||||||
	if (following === null) {
 | 
						if (following === null) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const promisedFollower = User.findOne({ _id: following.followerId });
 | 
						const [follower, followee] = await Promise.all([
 | 
				
			||||||
	const promisedFollowee = User.findOne({ _id: following.followeeId });
 | 
							User.findOne({ _id: following.followerId }),
 | 
				
			||||||
 | 
							User.findOne({ _id: following.followeeId })
 | 
				
			||||||
 | 
						]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	await Promise.all([
 | 
						if (isLocalUser(follower) && isRemoteUser(followee)) {
 | 
				
			||||||
		// Decrement following count
 | 
							const undo = renderUndo(renderFollow(follower, followee));
 | 
				
			||||||
		User.update({ _id: following.followerId }, { $inc: { followingCount: -1 } }),
 | 
							undo['@context'] = context;
 | 
				
			||||||
		promisedFollower.then(({ followingCount }) => FollowingLog.insert({
 | 
					 | 
				
			||||||
			createdAt: new Date(),
 | 
					 | 
				
			||||||
			userId: following.followerId,
 | 
					 | 
				
			||||||
			count: followingCount - 1
 | 
					 | 
				
			||||||
		})),
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Decrement followers count
 | 
							await request(follower, followee.account.inbox, undo);
 | 
				
			||||||
		User.update({ _id: following.followeeId }, { $inc: { followersCount: -1 } }),
 | 
						}
 | 
				
			||||||
		promisedFollowee.then(({ followersCount }) => FollowedLog.insert({
 | 
					
 | 
				
			||||||
			createdAt: new Date(),
 | 
						try {
 | 
				
			||||||
			userId: following.followeeId,
 | 
							await Promise.all([
 | 
				
			||||||
			count: followersCount - 1
 | 
								// Delete following
 | 
				
			||||||
		})),
 | 
								Following.findOneAndDelete({ _id: data.id }),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Decrement following count
 | 
				
			||||||
 | 
								User.update({ _id: follower._id }, { $inc: { followingCount: -1 } }),
 | 
				
			||||||
 | 
								FollowingLog.insert({
 | 
				
			||||||
 | 
									createdAt: new Date(),
 | 
				
			||||||
 | 
									userId: follower._id,
 | 
				
			||||||
 | 
									count: follower.followingCount - 1
 | 
				
			||||||
 | 
								}),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Decrement followers count
 | 
				
			||||||
 | 
								User.update({ _id: followee._id }, { $inc: { followersCount: -1 } }),
 | 
				
			||||||
 | 
								FollowedLog.insert({
 | 
				
			||||||
 | 
									createdAt: new Date(),
 | 
				
			||||||
 | 
									userId: followee._id,
 | 
				
			||||||
 | 
									count: followee.followersCount - 1
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
							]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (isLocalUser(follower)) {
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							const promisedPackedUser = packUser(followee, follower);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Publish follow event
 | 
							// Publish follow event
 | 
				
			||||||
		Promise.all([promisedFollower, promisedFollowee]).then(async ([follower, followee]) => {
 | 
							stream(follower._id, 'unfollow', promisedPackedUser);
 | 
				
			||||||
			if (isRemoteUser(follower)) {
 | 
						} catch (error) {
 | 
				
			||||||
				return;
 | 
							Logger.error(error.toString());
 | 
				
			||||||
			}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
			const promisedPackedUser = packUser(followee, follower);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (isRemoteUser(followee)) {
 | 
					 | 
				
			||||||
				const undo = renderUndo(renderFollow(follower, followee));
 | 
					 | 
				
			||||||
				undo['@context'] = context;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				await request(follower, followee.account.inbox, undo);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			stream(follower._id, 'unfollow', promisedPackedUser);
 | 
					 | 
				
			||||||
		})
 | 
					 | 
				
			||||||
	]);
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,10 +4,10 @@ const createDOMPurify = require('dompurify');
 | 
				
			||||||
import Resolver from '../resolver';
 | 
					import Resolver from '../resolver';
 | 
				
			||||||
import DriveFile from '../../../models/drive-file';
 | 
					import DriveFile from '../../../models/drive-file';
 | 
				
			||||||
import Post from '../../../models/post';
 | 
					import Post from '../../../models/post';
 | 
				
			||||||
import uploadFromUrl from '../../../drive/upload-from-url';
 | 
					import uploadFromUrl from '../../../api/drive/upload-from-url';
 | 
				
			||||||
import createPost from '../../../post/create';
 | 
					import createPost from '../../../api/post/create';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default async (resolver: Resolver, actor, activity): Promise<void> => {
 | 
					export default async (actor, activity): Promise<void> => {
 | 
				
			||||||
	if ('actor' in activity && actor.account.uri !== activity.actor) {
 | 
						if ('actor' in activity && actor.account.uri !== activity.actor) {
 | 
				
			||||||
		throw new Error('invalid actor');
 | 
							throw new Error('invalid actor');
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -31,6 +31,8 @@ export default async (resolver: Resolver, actor, activity): Promise<void> => {
 | 
				
			||||||
		throw new Error(`already registered: ${uri}`);
 | 
							throw new Error(`already registered: ${uri}`);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const resolver = new Resolver();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const object = await resolver.resolve(activity);
 | 
						const object = await resolver.resolve(activity);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (object.type) {
 | 
						switch (object.type) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,15 +1,9 @@
 | 
				
			||||||
import { MongoError } from 'mongodb';
 | 
					 | 
				
			||||||
import parseAcct from '../../../acct/parse';
 | 
					import parseAcct from '../../../acct/parse';
 | 
				
			||||||
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 follow from '../../../api/following/create';
 | 
				
			||||||
import context from '../renderer/context';
 | 
					 | 
				
			||||||
import renderAccept from '../renderer/accept';
 | 
					 | 
				
			||||||
import request from '../../request';
 | 
					 | 
				
			||||||
import Resolver from '../resolver';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default async (resolver: Resolver, actor, activity, distribute) => {
 | 
					export default async (actor, activity): Promise<void> => {
 | 
				
			||||||
	const prefix = config.url + '/@';
 | 
						const prefix = config.url + '/@';
 | 
				
			||||||
	const id = activity.object.id || activity.object;
 | 
						const id = activity.object.id || activity.object;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,52 +21,5 @@ export default async (resolver: Resolver, actor, activity, distribute) => {
 | 
				
			||||||
		throw new Error();
 | 
							throw new Error();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!distribute) {
 | 
						await follow(actor, followee, activity);
 | 
				
			||||||
		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 request(followee, actor.account.inbox, accept);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return promisedFollowing.then(({ _id }) => ({
 | 
					 | 
				
			||||||
		resolver,
 | 
					 | 
				
			||||||
		object: { $ref: 'following', $id: _id }
 | 
					 | 
				
			||||||
	}));
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue