From a6fb4f2e33b5bcbda5c9461d3c55e3d1c956b2c9 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Fri, 6 Apr 2018 04:04:50 +0900
Subject: [PATCH] wip

---
 src/models/post.ts          | 14 ++++++
 src/services/post/create.ts | 98 +++++++++++++++++++++----------------
 2 files changed, 69 insertions(+), 43 deletions(-)

diff --git a/src/models/post.ts b/src/models/post.ts
index 2f2b51b946..68a638fa2f 100644
--- a/src/models/post.ts
+++ b/src/models/post.ts
@@ -52,6 +52,20 @@ export type IPost = {
 		speed: number;
 	};
 	uri: string;
+
+	_reply?: {
+		userId: mongo.ObjectID;
+	};
+	_repost?: {
+		userId: mongo.ObjectID;
+	};
+	_user: {
+		host: string;
+		hostLower: string;
+		account: {
+			inbox?: string;
+		};
+	};
 };
 
 /**
diff --git a/src/services/post/create.ts b/src/services/post/create.ts
index 405e4a2f7b..745683b518 100644
--- a/src/services/post/create.ts
+++ b/src/services/post/create.ts
@@ -1,5 +1,5 @@
 import Post, { pack, IPost } from '../../models/post';
-import User, { isLocalUser, IUser } from '../../models/user';
+import User, { isLocalUser, IUser, isRemoteUser } from '../../models/user';
 import stream from '../../publishers/stream';
 import Following from '../../models/following';
 import { deliver } from '../../queue';
@@ -17,7 +17,7 @@ import parse from '../../text/parse';
 import html from '../../text/html';
 import { IApp } from '../../models/app';
 
-export default async (user: IUser, content: {
+export default async (user: IUser, data: {
 	createdAt?: Date;
 	text?: string;
 	reply?: IPost;
@@ -32,16 +32,16 @@ export default async (user: IUser, content: {
 	uri?: string;
 	app?: IApp;
 }, silent = false) => new Promise<IPost>(async (res, rej) => {
-	if (content.createdAt == null) content.createdAt = new Date();
-	if (content.visibility == null) content.visibility = 'public';
+	if (data.createdAt == null) data.createdAt = new Date();
+	if (data.visibility == null) data.visibility = 'public';
 
-	const tags = content.tags || [];
+	const tags = data.tags || [];
 
 	let tokens = null;
 
-	if (content.text) {
+	if (data.text) {
 		// Analyze
-		tokens = parse(content.text);
+		tokens = parse(data.text);
 
 		// Extract hashtags
 		const hashtags = tokens
@@ -55,31 +55,38 @@ export default async (user: IUser, content: {
 		});
 	}
 
-	const data: any = {
-		createdAt: content.createdAt,
-		mediaIds: content.media ? content.media.map(file => file._id) : [],
-		replyId: content.reply ? content.reply._id : null,
-		repostId: content.repost ? content.repost._id : null,
-		text: content.text,
+	const insert: any = {
+		createdAt: data.createdAt,
+		mediaIds: data.media ? data.media.map(file => file._id) : [],
+		replyId: data.reply ? data.reply._id : null,
+		repostId: data.repost ? data.repost._id : null,
+		text: data.text,
 		textHtml: tokens === null ? null : html(tokens),
-		poll: content.poll,
-		cw: content.cw,
+		poll: data.poll,
+		cw: data.cw,
 		tags,
 		userId: user._id,
-		viaMobile: content.viaMobile,
-		geo: content.geo || null,
-		appId: content.app ? content.app._id : null,
-		visibility: content.visibility,
+		viaMobile: data.viaMobile,
+		geo: data.geo || null,
+		appId: data.app ? data.app._id : null,
+		visibility: data.visibility,
 
 		// 以下非正規化データ
-		_reply: content.reply ? { userId: content.reply.userId } : null,
-		_repost: content.repost ? { userId: content.repost.userId } : null,
+		_reply: data.reply ? { userId: data.reply.userId } : null,
+		_repost: data.repost ? { userId: data.repost.userId } : null,
+		_user: {
+			host: user.host,
+			hostLower: user.hostLower,
+			account: isLocalUser(user) ? {} : {
+				inbox: user.account.inbox
+			}
+		}
 	};
 
-	if (content.uri != null) data.uri = content.uri;
+	if (data.uri != null) insert.uri = data.uri;
 
 	// 投稿を作成
-	const post = await Post.insert(data);
+	const post = await Post.insert(insert);
 
 	res(post);
 
@@ -125,6 +132,11 @@ export default async (user: IUser, content: {
 			const content = renderCreate(note);
 			content['@context'] = context;
 
+			// 投稿がリプライかつ投稿者がローカルユーザーかつリプライ先の投稿の投稿者がリモートユーザーなら配送
+			if (data.reply && isLocalUser(user) && isRemoteUser(data.reply._user)) {
+				deliver(user, content, data.reply._user.account.inbox).save();
+			}
+
 			Promise.all(followers.map(follower => {
 				follower = follower.user[0];
 
@@ -199,22 +211,22 @@ export default async (user: IUser, content: {
 	}
 
 	// If has in reply to post
-	if (content.reply) {
+	if (data.reply) {
 		// Increment replies count
-		Post.update({ _id: content.reply._id }, {
+		Post.update({ _id: data.reply._id }, {
 			$inc: {
 				repliesCount: 1
 			}
 		});
 
 		// (自分自身へのリプライでない限りは)通知を作成
-		notify(content.reply.userId, user._id, 'reply', {
+		notify(data.reply.userId, user._id, 'reply', {
 			postId: post._id
 		});
 
 		// Fetch watchers
 		PostWatching.find({
-			postId: content.reply._id,
+			postId: data.reply._id,
 			userId: { $ne: user._id },
 			// 削除されたドキュメントは除く
 			deletedAt: { $exists: false }
@@ -232,24 +244,24 @@ export default async (user: IUser, content: {
 
 		// この投稿をWatchする
 		if (isLocalUser(user) && user.account.settings.autoWatch !== false) {
-			watch(user._id, content.reply);
+			watch(user._id, data.reply);
 		}
 
 		// Add mention
-		addMention(content.reply.userId, 'reply');
+		addMention(data.reply.userId, 'reply');
 	}
 
 	// If it is repost
-	if (content.repost) {
+	if (data.repost) {
 		// Notify
-		const type = content.text ? 'quote' : 'repost';
-		notify(content.repost.userId, user._id, type, {
+		const type = data.text ? 'quote' : 'repost';
+		notify(data.repost.userId, user._id, type, {
 			post_id: post._id
 		});
 
 		// Fetch watchers
 		PostWatching.find({
-			postId: content.repost._id,
+			postId: data.repost._id,
 			userId: { $ne: user._id },
 			// 削除されたドキュメントは除く
 			deletedAt: { $exists: false }
@@ -267,24 +279,24 @@ export default async (user: IUser, content: {
 
 		// この投稿をWatchする
 		if (isLocalUser(user) && user.account.settings.autoWatch !== false) {
-			watch(user._id, content.repost);
+			watch(user._id, data.repost);
 		}
 
 		// If it is quote repost
-		if (content.text) {
+		if (data.text) {
 			// Add mention
-			addMention(content.repost.userId, 'quote');
+			addMention(data.repost.userId, 'quote');
 		} else {
 			// Publish event
-			if (!user._id.equals(content.repost.userId)) {
-				event(content.repost.userId, 'repost', postObj);
+			if (!user._id.equals(data.repost.userId)) {
+				event(data.repost.userId, 'repost', postObj);
 			}
 		}
 
 		// 今までで同じ投稿をRepostしているか
 		const existRepost = await Post.findOne({
 			userId: user._id,
-			repostId: content.repost._id,
+			repostId: data.repost._id,
 			_id: {
 				$ne: post._id
 			}
@@ -292,7 +304,7 @@ export default async (user: IUser, content: {
 
 		if (!existRepost) {
 			// Update repostee status
-			Post.update({ _id: content.repost._id }, {
+			Post.update({ _id: data.repost._id }, {
 				$inc: {
 					repostCount: 1
 				}
@@ -301,7 +313,7 @@ export default async (user: IUser, content: {
 	}
 
 	// If has text content
-	if (content.text) {
+	if (data.text) {
 		// Extract an '@' mentions
 		const atMentions = tokens
 			.filter(t => t.type == 'mention')
@@ -322,8 +334,8 @@ export default async (user: IUser, content: {
 			if (mentionee == null) return;
 
 			// 既に言及されたユーザーに対する返信や引用repostの場合も無視
-			if (content.reply && content.reply.userId.equals(mentionee._id)) return;
-			if (content.repost && content.repost.userId.equals(mentionee._id)) return;
+			if (data.reply && data.reply.userId.equals(mentionee._id)) return;
+			if (data.repost && data.repost.userId.equals(mentionee._id)) return;
 
 			// Add mention
 			addMention(mentionee._id, 'mention');