summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/backend/src/core/UserSuspendService.ts84
1 files changed, 64 insertions, 20 deletions
diff --git a/packages/backend/src/core/UserSuspendService.ts b/packages/backend/src/core/UserSuspendService.ts
index f375dff862..ddadab7022 100644
--- a/packages/backend/src/core/UserSuspendService.ts
+++ b/packages/backend/src/core/UserSuspendService.ts
@@ -6,7 +6,7 @@
import { Inject, Injectable } from '@nestjs/common';
import { Not, IsNull } from 'typeorm';
import type { FollowingsRepository, FollowRequestsRepository, UsersRepository } from '@/models/_.js';
-import type { MiUser } from '@/models/User.js';
+import { MiUser } from '@/models/User.js';
import { QueueService } from '@/core/QueueService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { DI } from '@/di-symbols.js';
@@ -17,9 +17,15 @@ import { RelationshipJobData } from '@/queue/types.js';
import { ModerationLogService } from '@/core/ModerationLogService.js';
import { isSystemAccount } from '@/misc/is-system-account.js';
import { CacheService } from '@/core/CacheService.js';
+import { LoggerService } from '@/core/LoggerService.js';
+import type Logger from '@/logger.js';
+import { renderInlineError } from '@/misc/render-inline-error.js';
+import { trackPromise } from '@/misc/promise-tracker.js';
@Injectable()
export class UserSuspendService {
+ private readonly logger: Logger;
+
constructor(
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
@@ -36,7 +42,10 @@ export class UserSuspendService {
private apRendererService: ApRendererService,
private moderationLogService: ModerationLogService,
private readonly cacheService: CacheService,
+
+ loggerService: LoggerService,
) {
+ this.logger = loggerService.getLogger('user-suspend');
}
@bindThis
@@ -47,16 +56,16 @@ export class UserSuspendService {
isSuspended: true,
});
- this.moderationLogService.log(moderator, 'suspend', {
+ await this.moderationLogService.log(moderator, 'suspend', {
userId: user.id,
userUsername: user.username,
userHost: user.host,
});
- (async () => {
- await this.postSuspend(user).catch(e => {});
- await this.unFollowAll(user).catch(e => {});
- })();
+ trackPromise((async () => {
+ await this.postSuspend(user);
+ await this.freezeAll(user);
+ })().catch(e => this.logger.error(`Error suspending user ${user.id}: ${renderInlineError(e)}`)));
}
@bindThis
@@ -65,33 +74,36 @@ export class UserSuspendService {
isSuspended: false,
});
- this.moderationLogService.log(moderator, 'unsuspend', {
+ await this.moderationLogService.log(moderator, 'unsuspend', {
userId: user.id,
userUsername: user.username,
userHost: user.host,
});
- (async () => {
- await this.postUnsuspend(user).catch(e => {});
- })();
+ trackPromise((async () => {
+ await this.postUnsuspend(user);
+ await this.unFreezeAll(user);
+ })().catch(e => this.logger.error(`Error un-suspending for user ${user.id}: ${renderInlineError(e)}`)));
}
@bindThis
private async postSuspend(user: { id: MiUser['id']; host: MiUser['host'] }): Promise<void> {
this.globalEventService.publishInternalEvent('userChangeSuspendedState', { id: user.id, isSuspended: true });
+ /*
this.followRequestsRepository.delete({
followeeId: user.id,
});
this.followRequestsRepository.delete({
followerId: user.id,
});
+ */
if (this.userEntityService.isLocalUser(user)) {
// 知り得る全SharedInboxにDelete配信
const content = this.apRendererService.addContext(this.apRendererService.renderDelete(this.userEntityService.genLocalUserUri(user.id), user));
- const queue: string[] = [];
+ const queue = new Map<string, boolean>();
const followings = await this.followingsRepository.find({
where: [
@@ -104,12 +116,12 @@ export class UserSuspendService {
const inboxes = followings.map(x => x.followerSharedInbox ?? x.followeeSharedInbox);
for (const inbox of inboxes) {
- if (inbox != null && !queue.includes(inbox)) queue.push(inbox);
+ if (inbox != null) {
+ queue.set(inbox, true);
+ }
}
- for (const inbox of queue) {
- this.queueService.deliver(user, content, inbox, true);
- }
+ await this.queueService.deliverMany(user, content, queue);
}
}
@@ -121,7 +133,7 @@ export class UserSuspendService {
// 知り得る全SharedInboxにUndo Delete配信
const content = this.apRendererService.addContext(this.apRendererService.renderUndo(this.apRendererService.renderDelete(this.userEntityService.genLocalUserUri(user.id), user), user));
- const queue: string[] = [];
+ const queue = new Map<string, boolean>();
const followings = await this.followingsRepository.find({
where: [
@@ -134,12 +146,12 @@ export class UserSuspendService {
const inboxes = followings.map(x => x.followerSharedInbox ?? x.followeeSharedInbox);
for (const inbox of inboxes) {
- if (inbox != null && !queue.includes(inbox)) queue.push(inbox);
+ if (inbox != null) {
+ queue.set(inbox, true);
+ }
}
- for (const inbox of queue) {
- this.queueService.deliver(user as any, content, inbox, true);
- }
+ await this.queueService.deliverMany(user, content, queue);
}
}
@@ -160,4 +172,36 @@ export class UserSuspendService {
}
this.queueService.createUnfollowJob(jobs);
}
+
+ @bindThis
+ private async freezeAll(user: MiUser): Promise<void> {
+ // Freeze follow relations with all remote users
+ await this.followingsRepository
+ .createQueryBuilder('following')
+ .orWhere({
+ followeeId: user.id,
+ followerHost: Not(IsNull()),
+ })
+ .update({
+ isFollowerHibernated: true,
+ })
+ .execute();
+ }
+
+ @bindThis
+ private async unFreezeAll(user: MiUser): Promise<void> {
+ // Restore follow relations with all remote users
+ await this.followingsRepository
+ .createQueryBuilder('following')
+ .innerJoin(MiUser, 'follower', 'user.id = following.followerId')
+ .andWhere('follower.isHibernated = false') // Don't unfreeze if the follower is *actually* frozen
+ .andWhere({
+ followeeId: user.id,
+ followerHost: Not(IsNull()),
+ })
+ .update({
+ isFollowerHibernated: false,
+ })
+ .execute();
+ }
}