enhance: リモートのフォロワーから再度Followが来た場合、acceptを返してあげる (#13388)
* enhance: リモートのフォロワーから再度Followが来た場合、acceptを返してあげる * nanka meccha kaeta * ブロックチェックの後にフォロー関係の存在チェックをする
This commit is contained in:
parent
a861f913a7
commit
600d91beda
|
@ -30,6 +30,7 @@ import type { Config } from '@/config.js';
|
||||||
import { AccountMoveService } from '@/core/AccountMoveService.js';
|
import { AccountMoveService } from '@/core/AccountMoveService.js';
|
||||||
import { UtilityService } from '@/core/UtilityService.js';
|
import { UtilityService } from '@/core/UtilityService.js';
|
||||||
import { FanoutTimelineService } from '@/core/FanoutTimelineService.js';
|
import { FanoutTimelineService } from '@/core/FanoutTimelineService.js';
|
||||||
|
import type { ThinUser } from '@/queue/types.js';
|
||||||
import Logger from '../logger.js';
|
import Logger from '../logger.js';
|
||||||
|
|
||||||
const logger = new Logger('following/create');
|
const logger = new Logger('following/create');
|
||||||
|
@ -94,20 +95,43 @@ export class UserFollowingService implements OnModuleInit {
|
||||||
this.userBlockingService = this.moduleRef.get('UserBlockingService');
|
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
|
@bindThis
|
||||||
public async follow(
|
public async follow(
|
||||||
_follower: { id: MiUser['id'] },
|
follower: MiLocalUser | MiRemoteUser,
|
||||||
_followee: { id: MiUser['id'] },
|
followee: MiLocalUser | MiRemoteUser,
|
||||||
{ requestId, silent = false, withReplies }: {
|
{ requestId, silent = false, withReplies }: {
|
||||||
requestId?: string,
|
requestId?: string,
|
||||||
silent?: boolean,
|
silent?: boolean,
|
||||||
withReplies?: boolean,
|
withReplies?: boolean,
|
||||||
} = {},
|
} = {},
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const [follower, followee] = await Promise.all([
|
if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isRemoteUser(followee)) {
|
||||||
this.usersRepository.findOneByOrFail({ id: _follower.id }),
|
// What?
|
||||||
this.usersRepository.findOneByOrFail({ id: _followee.id }),
|
throw new Error('Remote user cannot follow remote user.');
|
||||||
]) as [MiLocalUser | MiRemoteUser, MiLocalUser | MiRemoteUser];
|
}
|
||||||
|
|
||||||
// check blocking
|
// check blocking
|
||||||
const [blocking, blocked] = await Promise.all([
|
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 (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 });
|
const followeeProfile = await this.userProfilesRepository.findOneByOrFail({ userId: followee.id });
|
||||||
// フォロー対象が鍵アカウントである or
|
// フォロー対象が鍵アカウントである or
|
||||||
// フォロワーがBotであり、フォロー対象がBotからのフォローに慎重である or
|
// フォロワーがBotであり、フォロー対象がBotからのフォローに慎重である or
|
||||||
|
@ -189,8 +231,7 @@ export class UserFollowingService implements OnModuleInit {
|
||||||
await this.insertFollowingDoc(followee, follower, silent, withReplies);
|
await this.insertFollowingDoc(followee, follower, silent, withReplies);
|
||||||
|
|
||||||
if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) {
|
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.deliverAccept(follower, followee, requestId);
|
||||||
this.queueService.deliver(followee, content, follower.inbox, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -571,8 +612,7 @@ export class UserFollowingService implements OnModuleInit {
|
||||||
await this.insertFollowingDoc(followee, follower, false, request.withReplies);
|
await this.insertFollowingDoc(followee, follower, false, request.withReplies);
|
||||||
|
|
||||||
if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) {
|
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.deliverAccept(follower, followee as MiPartialLocalUser, request.requestId ?? undefined);
|
||||||
this.queueService.deliver(followee, content, follower.inbox, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.userEntityService.pack(followee.id, followee, {
|
this.userEntityService.pack(followee.id, followee, {
|
||||||
|
|
|
@ -35,7 +35,7 @@ export class RelationshipProcessorService {
|
||||||
@bindThis
|
@bindThis
|
||||||
public async processFollow(job: Bull.Job<RelationshipJobData>): Promise<string> {
|
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"}`);
|
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,
|
requestId: job.data.requestId,
|
||||||
silent: job.data.silent,
|
silent: job.data.silent,
|
||||||
withReplies: job.data.withReplies,
|
withReplies: job.data.withReplies,
|
||||||
|
|
|
@ -100,22 +100,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
throw err;
|
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 {
|
try {
|
||||||
await this.userFollowingService.follow(follower, followee, { withReplies: ps.withReplies });
|
await this.userFollowingService.follow(follower, followee, { withReplies: ps.withReplies });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof IdentifiableError) {
|
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 === '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);
|
if (e.id === '3338392a-f764-498d-8855-db939dcf8c48') throw new ApiError(meta.errors.blocked);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue