From f937f2d3c677c6634c29d28de1e5f8dbe15d1176 Mon Sep 17 00:00:00 2001 From: Hazelnoot Date: Wed, 23 Jul 2025 15:45:32 -0400 Subject: [PATCH 1/3] fix error in UserSuspendService.freezeAll and UserSuspendService.unFreezeAll caused by TypeORM bug --- packages/backend/src/core/UserSuspendService.ts | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/backend/src/core/UserSuspendService.ts b/packages/backend/src/core/UserSuspendService.ts index ddadab7022..0a592e5024 100644 --- a/packages/backend/src/core/UserSuspendService.ts +++ b/packages/backend/src/core/UserSuspendService.ts @@ -178,10 +178,8 @@ export class UserSuspendService { // Freeze follow relations with all remote users await this.followingsRepository .createQueryBuilder('following') - .orWhere({ - followeeId: user.id, - followerHost: Not(IsNull()), - }) + .andWhere('following."followeeId" = :id', { id: user.id }) + .andWhere('following."followerHost" IS NOT NULL') .update({ isFollowerHibernated: true, }) @@ -195,10 +193,8 @@ export class UserSuspendService { .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()), - }) + .andWhere('following."followeeId" = :id', { id: user.id }) + .andWhere('following."followerHost" IS NOT NULL') .update({ isFollowerHibernated: false, }) From 73f2ee4fb3209471869b9d1f5e7b4d438214d886 Mon Sep 17 00:00:00 2001 From: Hazelnoot Date: Wed, 23 Jul 2025 16:10:00 -0400 Subject: [PATCH 2/3] fix user suspension / unsuspension not updating caches --- packages/backend/src/core/UserSuspendService.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/backend/src/core/UserSuspendService.ts b/packages/backend/src/core/UserSuspendService.ts index 0a592e5024..1b54fb5e8a 100644 --- a/packages/backend/src/core/UserSuspendService.ts +++ b/packages/backend/src/core/UserSuspendService.ts @@ -21,6 +21,7 @@ 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'; +import { InternalEventService } from '@/core/InternalEventService.js'; @Injectable() export class UserSuspendService { @@ -42,6 +43,7 @@ export class UserSuspendService { private apRendererService: ApRendererService, private moderationLogService: ModerationLogService, private readonly cacheService: CacheService, + private readonly internalEventService: InternalEventService, loggerService: LoggerService, ) { @@ -56,6 +58,8 @@ export class UserSuspendService { isSuspended: true, }); + await this.internalEventService.emit(user.host == null ? 'localUserUpdated' : 'remoteUserUpdated', { id: user.id }); + await this.moderationLogService.log(moderator, 'suspend', { userId: user.id, userUsername: user.username, @@ -74,6 +78,8 @@ export class UserSuspendService { isSuspended: false, }); + await this.internalEventService.emit(user.host == null ? 'localUserUpdated' : 'remoteUserUpdated', { id: user.id }); + await this.moderationLogService.log(moderator, 'unsuspend', { userId: user.id, userUsername: user.username, From ea9335bcc8f59b187140f7c9ea876389ac0af9a4 Mon Sep 17 00:00:00 2001 From: Hazelnoot Date: Wed, 23 Jul 2025 16:10:14 -0400 Subject: [PATCH 3/3] fix more freeze / unfreeze errors caused by TypeORM bugs --- .../backend/src/core/UserSuspendService.ts | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/packages/backend/src/core/UserSuspendService.ts b/packages/backend/src/core/UserSuspendService.ts index 1b54fb5e8a..5868ba6678 100644 --- a/packages/backend/src/core/UserSuspendService.ts +++ b/packages/backend/src/core/UserSuspendService.ts @@ -4,7 +4,7 @@ */ import { Inject, Injectable } from '@nestjs/common'; -import { Not, IsNull } from 'typeorm'; +import { Not, IsNull, DataSource } from 'typeorm'; import type { FollowingsRepository, FollowRequestsRepository, UsersRepository } from '@/models/_.js'; import { MiUser } from '@/models/User.js'; import { QueueService } from '@/core/QueueService.js'; @@ -37,6 +37,9 @@ export class UserSuspendService { @Inject(DI.followRequestsRepository) private followRequestsRepository: FollowRequestsRepository, + @Inject(DI.db) + private db: DataSource, + private userEntityService: UserEntityService, private queueService: QueueService, private globalEventService: GlobalEventService, @@ -184,26 +187,29 @@ export class UserSuspendService { // Freeze follow relations with all remote users await this.followingsRepository .createQueryBuilder('following') - .andWhere('following."followeeId" = :id', { id: user.id }) - .andWhere('following."followerHost" IS NOT NULL') .update({ isFollowerHibernated: true, }) + .where({ + followeeId: user.id, + followerHost: Not(IsNull()), + }) .execute(); } @bindThis private async unFreezeAll(user: MiUser): Promise { // 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('following."followeeId" = :id', { id: user.id }) - .andWhere('following."followerHost" IS NOT NULL') - .update({ - isFollowerHibernated: false, - }) - .execute(); + + // TypeORM does not support UPDATE with JOIN: https://github.com/typeorm/typeorm/issues/564#issuecomment-310331468 + await this.db.query(` + UPDATE "following" + SET "isFollowerHibernated" = false + FROM "user" + WHERE "user"."id" = "following"."followerId" + AND "user"."isHibernated" = false -- Don't unfreeze if the follower is *actually* frozen + AND "followeeId" = $1 + AND "followeeHost" IS NOT NULL + `, [user.id]); } }