From 1d8fb65959a71836f06f4f87d5fc223c56122cf2 Mon Sep 17 00:00:00 2001
From: MeiMei <30769358+mei23@users.noreply.github.com>
Date: Sat, 8 Dec 2018 18:55:00 +0900
Subject: [PATCH] Fix follow duplicate (#3548)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* フォローとリクエスト両方存在しても解除する

* 既にフォローしてても承認できるように
---
 src/remote/activitypub/kernel/undo/follow.ts | 10 +++++++++-
 src/services/following/requests/accept.ts    | 15 ++++++++++++---
 2 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/src/remote/activitypub/kernel/undo/follow.ts b/src/remote/activitypub/kernel/undo/follow.ts
index f112ee8bf..af06aa5b3 100644
--- a/src/remote/activitypub/kernel/undo/follow.ts
+++ b/src/remote/activitypub/kernel/undo/follow.ts
@@ -5,6 +5,7 @@ import unfollow from '../../../../services/following/delete';
 import cancelRequest from '../../../../services/following/requests/cancel';
 import { IFollow } from '../../type';
 import FollowRequest from '../../../../models/follow-request';
+import Following from '../../../../models/following';
 
 export default async (actor: IRemoteUser, activity: IFollow): Promise<void> => {
 	const id = typeof activity.object == 'string' ? activity.object : activity.object.id;
@@ -30,9 +31,16 @@ export default async (actor: IRemoteUser, activity: IFollow): Promise<void> => {
 		followeeId: followee._id
 	});
 
+	const following = await Following.findOne({
+		followerId: actor._id,
+		followeeId: followee._id
+	});
+
 	if (req) {
 		await cancelRequest(followee, actor);
-	} else {
+	}
+
+	if (following) {
 		await unfollow(actor, followee);
 	}
 };
diff --git a/src/services/following/requests/accept.ts b/src/services/following/requests/accept.ts
index 97cd733b2..32fc874f4 100644
--- a/src/services/following/requests/accept.ts
+++ b/src/services/following/requests/accept.ts
@@ -1,4 +1,4 @@
-import User, { IUser, isRemoteUser, ILocalUser, pack as packUser } from '../../../models/user';
+import User, { IUser, isRemoteUser, ILocalUser, pack as packUser, isLocalUser } from '../../../models/user';
 import FollowRequest from '../../../models/follow-request';
 import pack from '../../../remote/activitypub/renderer';
 import renderFollow from '../../../remote/activitypub/renderer/follow';
@@ -9,6 +9,8 @@ import { publishMainStream } from '../../../stream';
 import perUserFollowingChart from '../../../chart/per-user-following';
 
 export default async function(followee: IUser, follower: IUser) {
+	let incremented = 1;
+
 	await Following.insert({
 		createdAt: new Date(),
 		followerId: follower._id,
@@ -25,6 +27,13 @@ export default async function(followee: IUser, follower: IUser) {
 			inbox: isRemoteUser(followee) ? followee.inbox : undefined,
 			sharedInbox: isRemoteUser(followee) ? followee.sharedInbox : undefined
 		}
+	}).catch(e => {
+		if (e.code === 11000 && isRemoteUser(follower) && isLocalUser(followee)) {
+			console.log(`Accept => Insert duplicated ignore. ${follower._id} => ${followee._id}`);
+			incremented = 0;
+		} else {
+			throw e;
+		}
 	});
 
 	if (isRemoteUser(follower)) {
@@ -45,7 +54,7 @@ export default async function(followee: IUser, follower: IUser) {
 	//#region Increment following count
 	await User.update({ _id: follower._id }, {
 		$inc: {
-			followingCount: 1
+			followingCount: incremented
 		}
 	});
 	//#endregion
@@ -53,7 +62,7 @@ export default async function(followee: IUser, follower: IUser) {
 	//#region Increment followers count
 	await User.update({ _id: followee._id }, {
 		$inc: {
-			followersCount: 1
+			followersCount: incremented
 		}
 	});
 	//#endregion