Implement like
This commit is contained in:
		
							parent
							
								
									321f61f1cb
								
							
						
					
					
						commit
						c5f23bce78
					
				|  | @ -1,9 +1,10 @@ | |||
| import { Object } from '../type'; | ||||
| import { IRemoteUser } from '../../../models/user'; | ||||
| import create from './create'; | ||||
| import performDeleteActivity from './delete'; | ||||
| import follow from './follow'; | ||||
| import undo from './undo'; | ||||
| import { Object } from '../type'; | ||||
| import { IRemoteUser } from '../../../models/user'; | ||||
| import like from './like'; | ||||
| 
 | ||||
| const self = async (actor: IRemoteUser, activity: Object): Promise<void> => { | ||||
| 	switch (activity.type) { | ||||
|  | @ -23,6 +24,10 @@ const self = async (actor: IRemoteUser, activity: Object): Promise<void> => { | |||
| 		// noop
 | ||||
| 		break; | ||||
| 
 | ||||
| 	case 'Like': | ||||
| 		await like(actor, activity); | ||||
| 		break; | ||||
| 
 | ||||
| 	case 'Undo': | ||||
| 		await undo(actor, activity); | ||||
| 		break; | ||||
|  | @ -33,7 +38,7 @@ const self = async (actor: IRemoteUser, activity: Object): Promise<void> => { | |||
| 		break; | ||||
| 
 | ||||
| 	default: | ||||
| 		console.warn(`unknown activity type: ${activity.type}`); | ||||
| 		console.warn(`unknown activity type: ${(activity as any).type}`); | ||||
| 		return null; | ||||
| 	} | ||||
| }; | ||||
|  |  | |||
|  | @ -1,10 +1,10 @@ | |||
| import { MongoError } from 'mongodb'; | ||||
| import Reaction, { IPostReaction } from '../../../models/post-reaction'; | ||||
| import Post from '../../../models/post'; | ||||
| import queue from '../../../queue'; | ||||
| import { IRemoteUser } from '../../../models/user'; | ||||
| import { ILike } from '../type'; | ||||
| import create from '../../../services/post/reaction/create'; | ||||
| 
 | ||||
| export default async (resolver, actor, activity, distribute) => { | ||||
| 	const id = activity.object.id || activity.object; | ||||
| export default async (actor: IRemoteUser, activity: ILike) => { | ||||
| 	const id = typeof activity.object == 'string' ? activity.object : activity.object.id; | ||||
| 
 | ||||
| 	// Transform:
 | ||||
| 	// https://misskey.ex/@syuilo/xxxx to
 | ||||
|  | @ -16,48 +16,5 @@ export default async (resolver, actor, activity, distribute) => { | |||
| 		throw new Error(); | ||||
| 	} | ||||
| 
 | ||||
| 	if (!distribute) { | ||||
| 		const { _id } = await Reaction.findOne({ | ||||
| 			userId: actor._id, | ||||
| 			postId: post._id | ||||
| 		}); | ||||
| 
 | ||||
| 		return { | ||||
| 			resolver, | ||||
| 			object: { $ref: 'postPeactions', $id: _id } | ||||
| 		}; | ||||
| 	} | ||||
| 
 | ||||
| 	const promisedReaction = Reaction.insert({ | ||||
| 		createdAt: new Date(), | ||||
| 		userId: actor._id, | ||||
| 		postId: post._id, | ||||
| 		reaction: 'pudding' | ||||
| 	}).then(reaction => new Promise<IPostReaction>((resolve, reject) => { | ||||
| 		queue.create('http', { | ||||
| 			type: 'reaction', | ||||
| 			reactionId: reaction._id | ||||
| 		}).save(error => { | ||||
| 			if (error) { | ||||
| 				reject(error); | ||||
| 			} else { | ||||
| 				resolve(reaction); | ||||
| 			} | ||||
| 		}); | ||||
| 	}), async error => { | ||||
| 		// duplicate key error
 | ||||
| 		if (error instanceof MongoError && error.code === 11000) { | ||||
| 			return Reaction.findOne({ | ||||
| 				userId: actor._id, | ||||
| 				postId: post._id | ||||
| 			}); | ||||
| 		} | ||||
| 
 | ||||
| 		throw error; | ||||
| 	}); | ||||
| 
 | ||||
| 	return promisedReaction.then(({ _id }) => ({ | ||||
| 		resolver, | ||||
| 		object: { $ref: 'postPeactions', $id: _id } | ||||
| 	})); | ||||
| 	await create(actor, post, 'pudding'); | ||||
| }; | ||||
|  |  | |||
|  | @ -0,0 +1,9 @@ | |||
| import config from '../../../config'; | ||||
| 
 | ||||
| export default (user, post) => { | ||||
| 	return { | ||||
| 		type: 'Like', | ||||
| 		actor: `${config.url}/@${user.username}`, | ||||
| 		object: post.uri ? post.uri : `${config.url}/posts/${post._id}` | ||||
| 	}; | ||||
| }; | ||||
|  | @ -23,7 +23,7 @@ export default async (user: IUser, post: IPost) => { | |||
| 			}); | ||||
| 
 | ||||
| 			if (inReplyToUser !== null) { | ||||
| 				inReplyTo = inReplyToPost.uri || `${config.url}/@${inReplyToUser.username}/${inReplyToPost._id}`; | ||||
| 				inReplyTo = inReplyToPost.uri || `${config.url}/posts/${inReplyToPost._id}`; | ||||
| 			} | ||||
| 		} | ||||
| 	} else { | ||||
|  | @ -33,7 +33,7 @@ export default async (user: IUser, post: IPost) => { | |||
| 	const attributedTo = `${config.url}/@${user.username}`; | ||||
| 
 | ||||
| 	return { | ||||
| 		id: `${attributedTo}/${post._id}`, | ||||
| 		id: `${config.url}/posts/${post._id}`, | ||||
| 		type: 'Note', | ||||
| 		attributedTo, | ||||
| 		content: post.textHtml, | ||||
|  |  | |||
|  | @ -55,6 +55,10 @@ export interface IAccept extends IActivity { | |||
| 	type: 'Accept'; | ||||
| } | ||||
| 
 | ||||
| export interface ILike extends IActivity { | ||||
| 	type: 'Like'; | ||||
| } | ||||
| 
 | ||||
| export type Object = | ||||
| 	ICollection | | ||||
| 	IOrderedCollection | | ||||
|  | @ -62,4 +66,5 @@ export type Object = | |||
| 	IDelete | | ||||
| 	IUndo | | ||||
| 	IFollow | | ||||
| 	IAccept; | ||||
| 	IAccept | | ||||
| 	ILike; | ||||
|  |  | |||
|  | @ -3,20 +3,11 @@ | |||
|  */ | ||||
| import $ from 'cafy'; | ||||
| import Reaction from '../../../../../models/post-reaction'; | ||||
| import Post, { pack as packPost } from '../../../../../models/post'; | ||||
| import { pack as packUser } from '../../../../../models/user'; | ||||
| import Watching from '../../../../../models/post-watching'; | ||||
| import watch from '../../../../../post/watch'; | ||||
| import { publishPostStream } from '../../../../../publishers/stream'; | ||||
| import notify from '../../../../../publishers/notify'; | ||||
| import pushSw from '../../../../../publishers/push-sw'; | ||||
| import Post from '../../../../../models/post'; | ||||
| import create from '../../../../../services/post/reaction/create'; | ||||
| 
 | ||||
| /** | ||||
|  * React to a post | ||||
|  * | ||||
|  * @param {any} params | ||||
|  * @param {any} user | ||||
|  * @return {Promise<any>} | ||||
|  */ | ||||
| module.exports = (params, user) => new Promise(async (res, rej) => { | ||||
| 	// Get 'postId' parameter
 | ||||
|  | @ -46,78 +37,11 @@ module.exports = (params, user) => new Promise(async (res, rej) => { | |||
| 		return rej('post not found'); | ||||
| 	} | ||||
| 
 | ||||
| 	// Myself
 | ||||
| 	if (post.userId.equals(user._id)) { | ||||
| 		return rej('cannot react to my post'); | ||||
| 	try { | ||||
| 		await create(user, post, reaction); | ||||
| 	} catch (e) { | ||||
| 		rej(e); | ||||
| 	} | ||||
| 
 | ||||
| 	// if already reacted
 | ||||
| 	const exist = await Reaction.findOne({ | ||||
| 		postId: post._id, | ||||
| 		userId: user._id, | ||||
| 		deletedAt: { $exists: false } | ||||
| 	}); | ||||
| 
 | ||||
| 	if (exist !== null) { | ||||
| 		return rej('already reacted'); | ||||
| 	} | ||||
| 
 | ||||
| 	// Create reaction
 | ||||
| 	await Reaction.insert({ | ||||
| 		createdAt: new Date(), | ||||
| 		postId: post._id, | ||||
| 		userId: user._id, | ||||
| 		reaction: reaction | ||||
| 	}); | ||||
| 
 | ||||
| 	// Send response
 | ||||
| 	res(); | ||||
| 
 | ||||
| 	const inc = {}; | ||||
| 	inc[`reactionCounts.${reaction}`] = 1; | ||||
| 
 | ||||
| 	// Increment reactions count
 | ||||
| 	await Post.update({ _id: post._id }, { | ||||
| 		$inc: inc | ||||
| 	}); | ||||
| 
 | ||||
| 	publishPostStream(post._id, 'reacted'); | ||||
| 
 | ||||
| 	// Notify
 | ||||
| 	notify(post.userId, user._id, 'reaction', { | ||||
| 		postId: post._id, | ||||
| 		reaction: reaction | ||||
| 	}); | ||||
| 
 | ||||
| 	pushSw(post.userId, 'reaction', { | ||||
| 		user: await packUser(user, post.userId), | ||||
| 		post: await packPost(post, post.userId), | ||||
| 		reaction: reaction | ||||
| 	}); | ||||
| 
 | ||||
| 	// Fetch watchers
 | ||||
| 	Watching | ||||
| 		.find({ | ||||
| 			postId: post._id, | ||||
| 			userId: { $ne: user._id }, | ||||
| 			// 削除されたドキュメントは除く
 | ||||
| 			deletedAt: { $exists: false } | ||||
| 		}, { | ||||
| 			fields: { | ||||
| 				userId: true | ||||
| 			} | ||||
| 		}) | ||||
| 		.then(watchers => { | ||||
| 			watchers.forEach(watcher => { | ||||
| 				notify(watcher.userId, user._id, 'reaction', { | ||||
| 					postId: post._id, | ||||
| 					reaction: reaction | ||||
| 				}); | ||||
| 			}); | ||||
| 		}); | ||||
| 
 | ||||
| 	// この投稿をWatchする
 | ||||
| 	if (user.account.settings.autoWatch !== false) { | ||||
| 		watch(user._id, post); | ||||
| 	} | ||||
| }); | ||||
|  |  | |||
|  | @ -0,0 +1,94 @@ | |||
| import { IUser, pack as packUser, isLocalUser, isRemoteUser } from '../../../models/user'; | ||||
| import Post, { IPost, pack as packPost } from '../../../models/post'; | ||||
| import PostReaction from '../../../models/post-reaction'; | ||||
| import { publishPostStream } from '../../../publishers/stream'; | ||||
| import notify from '../../../publishers/notify'; | ||||
| import pushSw from '../../../publishers/push-sw'; | ||||
| import PostWatching from '../../../models/post-watching'; | ||||
| import watch from '../watch'; | ||||
| import renderLike from '../../../remote/activitypub/renderer/like'; | ||||
| import { deliver } from '../../../queue'; | ||||
| import context from '../../../remote/activitypub/renderer/context'; | ||||
| 
 | ||||
| export default async (user: IUser, post: IPost, reaction: string) => new Promise(async (res, rej) => { | ||||
| 	// Myself
 | ||||
| 	if (post.userId.equals(user._id)) { | ||||
| 		return rej('cannot react to my post'); | ||||
| 	} | ||||
| 
 | ||||
| 	// if already reacted
 | ||||
| 	const exist = await PostReaction.findOne({ | ||||
| 		postId: post._id, | ||||
| 		userId: user._id | ||||
| 	}); | ||||
| 
 | ||||
| 	if (exist !== null) { | ||||
| 		return rej('already reacted'); | ||||
| 	} | ||||
| 
 | ||||
| 	// Create reaction
 | ||||
| 	await PostReaction.insert({ | ||||
| 		createdAt: new Date(), | ||||
| 		postId: post._id, | ||||
| 		userId: user._id, | ||||
| 		reaction | ||||
| 	}); | ||||
| 
 | ||||
| 	res(); | ||||
| 
 | ||||
| 	const inc = {}; | ||||
| 	inc[`reactionCounts.${reaction}`] = 1; | ||||
| 
 | ||||
| 	// Increment reactions count
 | ||||
| 	await Post.update({ _id: post._id }, { | ||||
| 		$inc: inc | ||||
| 	}); | ||||
| 
 | ||||
| 	publishPostStream(post._id, 'reacted'); | ||||
| 
 | ||||
| 	// Notify
 | ||||
| 	notify(post.userId, user._id, 'reaction', { | ||||
| 		postId: post._id, | ||||
| 		reaction: reaction | ||||
| 	}); | ||||
| 
 | ||||
| 	pushSw(post.userId, 'reaction', { | ||||
| 		user: await packUser(user, post.userId), | ||||
| 		post: await packPost(post, post.userId), | ||||
| 		reaction: reaction | ||||
| 	}); | ||||
| 
 | ||||
| 	// Fetch watchers
 | ||||
| 	PostWatching | ||||
| 		.find({ | ||||
| 			postId: post._id, | ||||
| 			userId: { $ne: user._id } | ||||
| 		}, { | ||||
| 			fields: { | ||||
| 				userId: true | ||||
| 			} | ||||
| 		}) | ||||
| 		.then(watchers => { | ||||
| 			watchers.forEach(watcher => { | ||||
| 				notify(watcher.userId, user._id, 'reaction', { | ||||
| 					postId: post._id, | ||||
| 					reaction: reaction | ||||
| 				}); | ||||
| 			}); | ||||
| 		}); | ||||
| 
 | ||||
| 	// ユーザーがローカルユーザーかつ自動ウォッチ設定がオンならばこの投稿をWatchする
 | ||||
| 	if (isLocalUser(user) && user.account.settings.autoWatch !== false) { | ||||
| 		watch(user._id, post); | ||||
| 	} | ||||
| 
 | ||||
| 	//#region 配信
 | ||||
| 	const content = renderLike(user, post); | ||||
| 	content['@context'] = context; | ||||
| 
 | ||||
| 	// リアクターがローカルユーザーかつリアクション対象がリモートユーザーの投稿なら配送
 | ||||
| 	if (isLocalUser(user) && isRemoteUser(post._user)) { | ||||
| 		deliver(user, content, post._user.account.inbox).save(); | ||||
| 	} | ||||
| 	//#endregion
 | ||||
| }); | ||||
		Loading…
	
		Reference in New Issue