enhance: リモートのフォロワーから再度Followが来た場合、acceptを返してあげる (#13388)
* enhance: リモートのフォロワーから再度Followが来た場合、acceptを返してあげる * nanka meccha kaeta * ブロックチェックの後にフォロー関係の存在チェックをする
This commit is contained in:
		
							parent
							
								
									a861f913a7
								
							
						
					
					
						commit
						600d91beda
					
				
					 3 changed files with 52 additions and 23 deletions
				
			
		| 
						 | 
				
			
			@ -30,6 +30,7 @@ import type { Config } from '@/config.js';
 | 
			
		|||
import { AccountMoveService } from '@/core/AccountMoveService.js';
 | 
			
		||||
import { UtilityService } from '@/core/UtilityService.js';
 | 
			
		||||
import { FanoutTimelineService } from '@/core/FanoutTimelineService.js';
 | 
			
		||||
import type { ThinUser } from '@/queue/types.js';
 | 
			
		||||
import Logger from '../logger.js';
 | 
			
		||||
 | 
			
		||||
const logger = new Logger('following/create');
 | 
			
		||||
| 
						 | 
				
			
			@ -94,20 +95,43 @@ export class UserFollowingService implements OnModuleInit {
 | 
			
		|||
		this.userBlockingService = this.moduleRef.get('UserBlockingService');
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@bindThis
 | 
			
		||||
	public async deliverAccept(follower: MiRemoteUser, followee: MiPartialLocalUser, requestId?: string) {
 | 
			
		||||
		const content = this.apRendererService.addContext(this.apRendererService.renderAccept(this.apRendererService.renderFollow(follower, followee, requestId), followee));
 | 
			
		||||
		this.queueService.deliver(followee, content, follower.inbox, false);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * ThinUserでなくともユーザーの情報が最新でない場合はこちらを使うべき
 | 
			
		||||
	 */
 | 
			
		||||
	@bindThis
 | 
			
		||||
	public async followByThinUser(
 | 
			
		||||
		_follower: ThinUser,
 | 
			
		||||
		_followee: ThinUser,
 | 
			
		||||
		options: Parameters<typeof this.follow>[2] = {},
 | 
			
		||||
	) {
 | 
			
		||||
		const [follower, followee] = await Promise.all([
 | 
			
		||||
			this.usersRepository.findOneByOrFail({ id: _follower.id }),
 | 
			
		||||
			this.usersRepository.findOneByOrFail({ id: _followee.id }),
 | 
			
		||||
		]) as [MiLocalUser | MiRemoteUser, MiLocalUser | MiRemoteUser];
 | 
			
		||||
 | 
			
		||||
		await this.follow(follower, followee, options);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@bindThis
 | 
			
		||||
	public async follow(
 | 
			
		||||
		_follower: { id: MiUser['id'] },
 | 
			
		||||
		_followee: { id: MiUser['id'] },
 | 
			
		||||
		follower: MiLocalUser | MiRemoteUser,
 | 
			
		||||
		followee: MiLocalUser | MiRemoteUser,
 | 
			
		||||
		{ requestId, silent = false, withReplies }: {
 | 
			
		||||
			requestId?: string,
 | 
			
		||||
			silent?: boolean,
 | 
			
		||||
			withReplies?: boolean,
 | 
			
		||||
		} = {},
 | 
			
		||||
	): Promise<void> {
 | 
			
		||||
		const [follower, followee] = await Promise.all([
 | 
			
		||||
			this.usersRepository.findOneByOrFail({ id: _follower.id }),
 | 
			
		||||
			this.usersRepository.findOneByOrFail({ id: _followee.id }),
 | 
			
		||||
		]) as [MiLocalUser | MiRemoteUser, MiLocalUser | MiRemoteUser];
 | 
			
		||||
		if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isRemoteUser(followee)) {
 | 
			
		||||
			// What?
 | 
			
		||||
			throw new Error('Remote user cannot follow remote user.');
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// check blocking
 | 
			
		||||
		const [blocking, blocked] = await Promise.all([
 | 
			
		||||
| 
						 | 
				
			
			@ -129,6 +153,24 @@ export class UserFollowingService implements OnModuleInit {
 | 
			
		|||
			if (blocked) throw new IdentifiableError('3338392a-f764-498d-8855-db939dcf8c48', 'blocked');
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (await this.followingsRepository.exists({
 | 
			
		||||
			where: {
 | 
			
		||||
				followerId: follower.id,
 | 
			
		||||
				followeeId: followee.id,
 | 
			
		||||
			},
 | 
			
		||||
		})) {
 | 
			
		||||
			// すでにフォロー関係が存在している場合
 | 
			
		||||
			if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) {
 | 
			
		||||
				// リモート → ローカル: acceptを送り返しておしまい
 | 
			
		||||
				this.deliverAccept(follower, followee, requestId);
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
			if (this.userEntityService.isLocalUser(follower)) {
 | 
			
		||||
				// ローカル → リモート/ローカル: 例外
 | 
			
		||||
				throw new IdentifiableError('ec3f65c0-a9d1-47d9-8791-b2e7b9dcdced', 'already following');
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		const followeeProfile = await this.userProfilesRepository.findOneByOrFail({ userId: followee.id });
 | 
			
		||||
		// フォロー対象が鍵アカウントである or
 | 
			
		||||
		// フォロワーがBotであり、フォロー対象がBotからのフォローに慎重である or
 | 
			
		||||
| 
						 | 
				
			
			@ -189,8 +231,7 @@ export class UserFollowingService implements OnModuleInit {
 | 
			
		|||
		await this.insertFollowingDoc(followee, follower, silent, withReplies);
 | 
			
		||||
 | 
			
		||||
		if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) {
 | 
			
		||||
			const content = this.apRendererService.addContext(this.apRendererService.renderAccept(this.apRendererService.renderFollow(follower, followee, requestId), followee));
 | 
			
		||||
			this.queueService.deliver(followee, content, follower.inbox, false);
 | 
			
		||||
			this.deliverAccept(follower, followee, requestId);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -571,8 +612,7 @@ export class UserFollowingService implements OnModuleInit {
 | 
			
		|||
		await this.insertFollowingDoc(followee, follower, false, request.withReplies);
 | 
			
		||||
 | 
			
		||||
		if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) {
 | 
			
		||||
			const content = this.apRendererService.addContext(this.apRendererService.renderAccept(this.apRendererService.renderFollow(follower, followee as MiPartialLocalUser, request.requestId!), followee));
 | 
			
		||||
			this.queueService.deliver(followee, content, follower.inbox, false);
 | 
			
		||||
			this.deliverAccept(follower, followee as MiPartialLocalUser, request.requestId ?? undefined);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		this.userEntityService.pack(followee.id, followee, {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,7 +35,7 @@ export class RelationshipProcessorService {
 | 
			
		|||
	@bindThis
 | 
			
		||||
	public async processFollow(job: Bull.Job<RelationshipJobData>): Promise<string> {
 | 
			
		||||
		this.logger.info(`${job.data.from.id} is trying to follow ${job.data.to.id} ${job.data.withReplies ? "with replies" : "without replies"}`);
 | 
			
		||||
		await this.userFollowingService.follow(job.data.from, job.data.to, {
 | 
			
		||||
		await this.userFollowingService.followByThinUser(job.data.from, job.data.to, {
 | 
			
		||||
			requestId: job.data.requestId,
 | 
			
		||||
			silent: job.data.silent,
 | 
			
		||||
			withReplies: job.data.withReplies,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -100,22 +100,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 | 
			
		|||
				throw err;
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// Check if already following
 | 
			
		||||
			const exist = await this.followingsRepository.exists({
 | 
			
		||||
				where: {
 | 
			
		||||
					followerId: follower.id,
 | 
			
		||||
					followeeId: followee.id,
 | 
			
		||||
				},
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			if (exist) {
 | 
			
		||||
				throw new ApiError(meta.errors.alreadyFollowing);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			try {
 | 
			
		||||
				await this.userFollowingService.follow(follower, followee, { withReplies: ps.withReplies });
 | 
			
		||||
			} catch (e) {
 | 
			
		||||
				if (e instanceof IdentifiableError) {
 | 
			
		||||
					if (e.id === 'ec3f65c0-a9d1-47d9-8791-b2e7b9dcdced') throw new ApiError(meta.errors.alreadyFollowing);
 | 
			
		||||
					if (e.id === '710e8fb0-b8c3-4922-be49-d5d93d8e6a6e') throw new ApiError(meta.errors.blocking);
 | 
			
		||||
					if (e.id === '3338392a-f764-498d-8855-db939dcf8c48') throw new ApiError(meta.errors.blocked);
 | 
			
		||||
				}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue