From acb82fe7b643519411673fbab5157f5d8ebf4fa6 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 9 Feb 2019 12:04:03 +0900 Subject: フォロー処理のリファクタリング (#4196) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix #4185 * Fix bug --- src/services/following/create.ts | 128 +++++++++++++++++------------- src/services/following/requests/accept.ts | 62 +-------------- 2 files changed, 78 insertions(+), 112 deletions(-) (limited to 'src/services') diff --git a/src/services/following/create.ts b/src/services/following/create.ts index 05f4632582..e6c95a72a4 100644 --- a/src/services/following/create.ts +++ b/src/services/following/create.ts @@ -13,58 +13,13 @@ import perUserFollowingChart from '../../services/chart/per-user-following'; import { registerOrFetchInstanceDoc } from '../register-or-fetch-instance-doc'; import Instance from '../../models/instance'; import instanceChart from '../../services/chart/instance'; +import Logger from '../../misc/logger'; +import FollowRequest from '../../models/follow-request'; -export default async function(follower: IUser, followee: IUser, requestId?: string) { - // check blocking - const [blocking, blocked] = await Promise.all([ - Blocking.findOne({ - blockerId: follower._id, - blockeeId: followee._id, - }), - Blocking.findOne({ - blockerId: followee._id, - blockeeId: follower._id, - }) - ]); +const logger = new Logger('following/create'); - if (isRemoteUser(follower) && isLocalUser(followee) && blocked) { - // リモートフォローを受けてブロックしていた場合は、エラーにするのではなくRejectを送り返しておしまい。 - const content = renderActivity(renderReject(renderFollow(follower, followee, requestId), followee)); - deliver(followee , content, follower.inbox); - return; - } else if (isRemoteUser(follower) && isLocalUser(followee) && blocking) { - // リモートフォローを受けてブロックされているはずの場合だったら、ブロック解除しておく。 - await Blocking.remove({ - _id: blocking._id - }); - } else { - // それ以外は単純に例外 - if (blocking != null) throw new Error('blocking'); - if (blocked != null) throw new Error('blocked'); - } - - // フォロー対象が鍵アカウントである or - // フォロワーがBotであり、フォロー対象がBotからのフォローに慎重である or - // フォロワーがローカルユーザーであり、フォロー対象がリモートユーザーである - // 上記のいずれかに当てはまる場合はすぐフォローせずにフォローリクエストを発行しておく - if (followee.isLocked || (followee.carefulBot && follower.isBot) || (isLocalUser(follower) && isRemoteUser(followee))) { - let autoAccept = false; - - // フォローしているユーザーは自動承認オプション - if (isLocalUser(followee) && followee.autoAcceptFollowed) { - const followed = await Following.findOne({ - followerId: followee._id, - followeeId: follower._id - }); - - if (followed) autoAccept = true; - } - - if (!autoAccept) { - await createFollowRequest(follower, followee, requestId); - return; - } - } +export async function insertFollowingDoc(followee: IUser, follower: IUser) { + let alreadyFollowed = false; await Following.insert({ createdAt: new Date(), @@ -82,17 +37,29 @@ export default async function(follower: IUser, followee: IUser, requestId?: stri inbox: isRemoteUser(followee) ? followee.inbox : undefined, sharedInbox: isRemoteUser(followee) ? followee.sharedInbox : undefined } + }).catch(e => { + if (e.code === 11000 && isRemoteUser(follower) && isLocalUser(followee)) { + logger.info(`Insert duplicated ignore. ${follower._id} => ${followee._id}`); + alreadyFollowed = true; + } else { + throw e; + } + }); + + await FollowRequest.remove({ + followeeId: followee._id, + followerId: follower._id }); - //#region Increment following count + if (alreadyFollowed) return; + + //#region Increment counts User.update({ _id: follower._id }, { $inc: { followingCount: 1 } }); - //#endregion - //#region Increment followers count User.update({ _id: followee._id }, { $inc: { followersCount: 1 @@ -140,6 +107,61 @@ export default async function(follower: IUser, followee: IUser, requestId?: stri // 通知を作成 notify(followee._id, follower._id, 'follow'); } +} + +export default async function(follower: IUser, followee: IUser, requestId?: string) { + // check blocking + const [blocking, blocked] = await Promise.all([ + Blocking.findOne({ + blockerId: follower._id, + blockeeId: followee._id, + }), + Blocking.findOne({ + blockerId: followee._id, + blockeeId: follower._id, + }) + ]); + + if (isRemoteUser(follower) && isLocalUser(followee) && blocked) { + // リモートフォローを受けてブロックしていた場合は、エラーにするのではなくRejectを送り返しておしまい。 + const content = renderActivity(renderReject(renderFollow(follower, followee, requestId), followee)); + deliver(followee , content, follower.inbox); + return; + } else if (isRemoteUser(follower) && isLocalUser(followee) && blocking) { + // リモートフォローを受けてブロックされているはずの場合だったら、ブロック解除しておく。 + await Blocking.remove({ + _id: blocking._id + }); + } else { + // それ以外は単純に例外 + if (blocking != null) throw new Error('blocking'); + if (blocked != null) throw new Error('blocked'); + } + + // フォロー対象が鍵アカウントである or + // フォロワーがBotであり、フォロー対象がBotからのフォローに慎重である or + // フォロワーがローカルユーザーであり、フォロー対象がリモートユーザーである + // 上記のいずれかに当てはまる場合はすぐフォローせずにフォローリクエストを発行しておく + if (followee.isLocked || (followee.carefulBot && follower.isBot) || (isLocalUser(follower) && isRemoteUser(followee))) { + let autoAccept = false; + + // フォローしているユーザーは自動承認オプション + if (isLocalUser(followee) && followee.autoAcceptFollowed) { + const followed = await Following.findOne({ + followerId: followee._id, + followeeId: follower._id + }); + + if (followed) autoAccept = true; + } + + if (!autoAccept) { + await createFollowRequest(follower, followee, requestId); + return; + } + } + + await insertFollowingDoc(followee, follower); if (isRemoteUser(follower) && isLocalUser(followee)) { const content = renderActivity(renderAccept(renderFollow(follower, followee, requestId), followee)); diff --git a/src/services/following/requests/accept.ts b/src/services/following/requests/accept.ts index 34c7036d19..81ecc74ab7 100644 --- a/src/services/following/requests/accept.ts +++ b/src/services/following/requests/accept.ts @@ -1,43 +1,14 @@ -import User, { IUser, isRemoteUser, ILocalUser, pack as packUser, isLocalUser } from '../../../models/user'; +import User, { IUser, isRemoteUser, ILocalUser, pack as packUser } from '../../../models/user'; import FollowRequest from '../../../models/follow-request'; import { renderActivity } from '../../../remote/activitypub/renderer'; import renderFollow from '../../../remote/activitypub/renderer/follow'; import renderAccept from '../../../remote/activitypub/renderer/accept'; import { deliver } from '../../../queue'; -import Following from '../../../models/following'; import { publishMainStream } from '../../stream'; -import perUserFollowingChart from '../../../services/chart/per-user-following'; -import Logger from '../../../misc/logger'; - -const logger = new Logger('following/requests/accept'); +import { insertFollowingDoc } from '../create'; export default async function(followee: IUser, follower: IUser) { - let incremented = 1; - - await Following.insert({ - createdAt: new Date(), - followerId: follower._id, - followeeId: followee._id, - - // 非正規化 - _follower: { - host: follower.host, - inbox: isRemoteUser(follower) ? follower.inbox : undefined, - sharedInbox: isRemoteUser(follower) ? follower.sharedInbox : undefined - }, - _followee: { - host: followee.host, - inbox: isRemoteUser(followee) ? followee.inbox : undefined, - sharedInbox: isRemoteUser(followee) ? followee.sharedInbox : undefined - } - }).catch(e => { - if (e.code === 11000 && isRemoteUser(follower) && isLocalUser(followee)) { - logger.info(`Accept => Insert duplicated ignore. ${follower._id} => ${followee._id}`); - incremented = 0; - } else { - throw e; - } - }); + await insertFollowingDoc(followee, follower); if (isRemoteUser(follower)) { const request = await FollowRequest.findOne({ @@ -49,29 +20,6 @@ export default async function(followee: IUser, follower: IUser) { deliver(followee as ILocalUser, content, follower.inbox); } - await FollowRequest.remove({ - followeeId: followee._id, - followerId: follower._id - }); - - //#region Increment following count - await User.update({ _id: follower._id }, { - $inc: { - followingCount: incremented - } - }); - //#endregion - - //#region Increment followers count - await User.update({ _id: followee._id }, { - $inc: { - followersCount: incremented - } - }); - //#endregion - - perUserFollowingChart.update(follower, followee, true); - await User.update({ _id: followee._id }, { $inc: { pendingReceivedFollowRequestsCount: -1 @@ -81,8 +29,4 @@ export default async function(followee: IUser, follower: IUser) { packUser(followee, followee, { detail: true }).then(packed => publishMainStream(followee._id, 'meUpdated', packed)); - - packUser(followee, follower, { - detail: true - }).then(packed => publishMainStream(follower._id, 'follow', packed)); } -- cgit v1.2.3-freya