diff --git a/packages/backend/src/core/FanoutTimelineEndpointService.ts b/packages/backend/src/core/FanoutTimelineEndpointService.ts index 97b617096a..1a9c668568 100644 --- a/packages/backend/src/core/FanoutTimelineEndpointService.ts +++ b/packages/backend/src/core/FanoutTimelineEndpointService.ts @@ -151,6 +151,7 @@ export class FanoutTimelineEndpointService { }; if (!ps.ignoreAuthorFromUserSuspension) { if (note.user!.isSuspended) return false; + if (note.user!.isRemoteSuspended) return false; } if (note.userId !== note.renoteUserId && noteJoined.renoteUser?.isSuspended) return false; if (note.userId !== note.replyUserId && noteJoined.replyUser?.isSuspended) return false; diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts index 314f7e221a..a54e105c80 100644 --- a/packages/backend/src/core/RoleService.ts +++ b/packages/backend/src/core/RoleService.ts @@ -254,7 +254,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit { } // サスペンド済みユーザである case 'isSuspended': { - return user.isSuspended; + return this.userEntityService.isSuspendedEither(user); } // 鍵アカウントユーザである case 'isLocked': { diff --git a/packages/backend/src/core/UserSearchService.ts b/packages/backend/src/core/UserSearchService.ts index 4be7bd9bdb..8c243a5368 100644 --- a/packages/backend/src/core/UserSearchService.ts +++ b/packages/backend/src/core/UserSearchService.ts @@ -207,7 +207,7 @@ export class UserSearchService { } } - userQuery.andWhere('user.isSuspended = FALSE'); + userQuery.andWhere('user.isSuspended = FALSE').andWhere('user.isRemoteSuspended = FALSE'); return userQuery; } @@ -243,7 +243,8 @@ export class UserSearchService { .where('user.updatedAt IS NULL') .orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold }); })) - .andWhere('user.isSuspended = FALSE'); + .andWhere('user.isSuspended = FALSE') + .andWhere('user.isRemoteSuspended = FALSE'); if (mutingQuery) { nameQuery.andWhere(`user.id NOT IN (${mutingQuery.getQuery()})`); @@ -286,6 +287,7 @@ export class UserSearchService { .orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold }); })) .andWhere('user.isSuspended = FALSE') + .andWhere('user.isRemoteSuspended = FALSE') .setParameters(profQuery.getParameters()); users = users.concat(await userQuery diff --git a/packages/backend/src/core/entities/NotificationEntityService.ts b/packages/backend/src/core/entities/NotificationEntityService.ts index e91fb9eb51..199bb9bf25 100644 --- a/packages/backend/src/core/entities/NotificationEntityService.ts +++ b/packages/backend/src/core/entities/NotificationEntityService.ts @@ -290,7 +290,7 @@ export class NotificationEntityService implements OnModuleInit { if (notifier == null) return false; if (notifier.host && userMutedInstances.has(notifier.host)) return false; - if (notifier.isSuspended) return false; + if (this.userEntityService.isSuspendedEither(notifier)) return false; return true; } diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index d4769d24d4..18fd88d288 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -69,6 +69,10 @@ function isRemoteUser(user: MiUser | { host: MiUser['host'] }): boolean { return !isLocalUser(user); } +function isSuspendedEither(user: MiUser): boolean { + return user.isSuspended || user.isRemoteSuspended; +} + export type UserRelation = { id: MiUser['id'] following: MiFollowing | null, @@ -163,6 +167,7 @@ export class UserEntityService implements OnModuleInit { public isLocalUser = isLocalUser; public isRemoteUser = isRemoteUser; + public isSuspendedEither = isSuspendedEither; @bindThis public async getRelation(me: MiUser['id'], target: MiUser['id']): Promise { @@ -537,7 +542,7 @@ export class UserEntityService implements OnModuleInit { bannerBlurhash: user.bannerId == null ? null : user.bannerBlurhash, isLocked: user.isLocked, isSilenced: this.roleService.getUserPolicies(user.id).then(r => !r.canPublicNote), - isSuspended: user.isSuspended, + isSuspended: this.isSuspendedEither(user), description: profile!.description, location: profile!.location, birthday: profile!.birthday, diff --git a/packages/backend/src/server/ServerService.ts b/packages/backend/src/server/ServerService.ts index 23c085ee27..8356f1073c 100644 --- a/packages/backend/src/server/ServerService.ts +++ b/packages/backend/src/server/ServerService.ts @@ -215,6 +215,7 @@ export class ServerService implements OnApplicationShutdown { usernameLower: username.toLowerCase(), host: (host == null) || (host === this.config.host) ? IsNull() : host, isSuspended: false, + isRemoteSuspended: false, }, }); diff --git a/packages/backend/src/server/api/endpoints/admin/show-user.ts b/packages/backend/src/server/api/endpoints/admin/show-user.ts index 1ba6853dbe..8364a9613b 100644 --- a/packages/backend/src/server/api/endpoints/admin/show-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/show-user.ts @@ -124,6 +124,10 @@ export const meta = { type: 'boolean', optional: false, nullable: false, }, + isRemoteSuspended: { + type: 'boolean', + optional: false, nullable: false, + }, isHibernated: { type: 'boolean', optional: false, nullable: false, @@ -246,6 +250,7 @@ export default class extends Endpoint { // eslint- isModerator: isModerator, isSilenced: isSilenced, isSuspended: user.isSuspended, + isRemoteSuspended: user.isRemoteSuspended, isHibernated: user.isHibernated, lastActiveDate: user.lastActiveDate ? user.lastActiveDate.toISOString() : null, moderationNote: profile.moderationNote ?? '', diff --git a/packages/backend/src/server/api/endpoints/admin/show-users.ts b/packages/backend/src/server/api/endpoints/admin/show-users.ts index 2b2c8c60ab..d8e4a636c4 100644 --- a/packages/backend/src/server/api/endpoints/admin/show-users.ts +++ b/packages/backend/src/server/api/endpoints/admin/show-users.ts @@ -61,7 +61,7 @@ export default class extends Endpoint { // eslint- const query = this.usersRepository.createQueryBuilder('user'); switch (ps.state) { - case 'available': query.where('user.isSuspended = FALSE'); break; + case 'available': query.where('user.isSuspended = FALSE').andWhere('user.isRemoteSuspended = FALSE'); break; case 'alive': query.where('user.updatedAt > :date', { date: new Date(Date.now() - 1000 * 60 * 60 * 24 * 5) }); break; case 'suspended': query.where('user.isSuspended = TRUE'); break; case 'admin': { diff --git a/packages/backend/src/server/api/endpoints/hashtags/users.ts b/packages/backend/src/server/api/endpoints/hashtags/users.ts index 30f0c1b0c8..d5a1ecdaed 100644 --- a/packages/backend/src/server/api/endpoints/hashtags/users.ts +++ b/packages/backend/src/server/api/endpoints/hashtags/users.ts @@ -51,7 +51,8 @@ export default class extends Endpoint { // eslint- if (!safeForSql(normalizeForSearch(ps.tag))) throw new Error('Injection'); const query = this.usersRepository.createQueryBuilder('user') .where(':tag <@ user.tags', { tag: [normalizeForSearch(ps.tag)] }) - .andWhere('user.isSuspended = FALSE'); + .andWhere('user.isSuspended = FALSE') + .andWhere('user.isRemoteSuspended = FALSE'); const recent = new Date(Date.now() - (1000 * 60 * 60 * 24 * 5)); diff --git a/packages/backend/src/server/api/endpoints/users/show.ts b/packages/backend/src/server/api/endpoints/users/show.ts index 5ff3a63d6a..04dd3f7dd4 100644 --- a/packages/backend/src/server/api/endpoints/users/show.ts +++ b/packages/backend/src/server/api/endpoints/users/show.ts @@ -138,6 +138,7 @@ export default class extends Endpoint { // eslint- } : { id: In(ps.userIds), isSuspended: false, + isRemoteSuspended: false, }); // リクエストされた通りに並べ替え diff --git a/packages/backend/src/server/web/ClientServerService.ts b/packages/backend/src/server/web/ClientServerService.ts index 8ca61a497d..e261d5be58 100644 --- a/packages/backend/src/server/web/ClientServerService.ts +++ b/packages/backend/src/server/web/ClientServerService.ts @@ -451,6 +451,7 @@ export class ClientServerService { usernameLower: username.toLowerCase(), host: host ?? IsNull(), isSuspended: false, + isRemoteSuspended: false, requireSigninToViewContents: false, }); @@ -510,6 +511,7 @@ export class ClientServerService { usernameLower: username.toLowerCase(), host: host ?? IsNull(), isSuspended: false, + isRemoteSuspended: false, }); vary(reply.raw, 'Accept'); @@ -559,6 +561,7 @@ export class ClientServerService { id: request.params.user, host: IsNull(), isSuspended: false, + isRemoteSuspended: false, }); if (user == null) { diff --git a/packages/frontend/src/pages/admin-user.vue b/packages/frontend/src/pages/admin-user.vue index a194b9a94f..e853829782 100644 --- a/packages/frontend/src/pages/admin-user.vue +++ b/packages/frontend/src/pages/admin-user.vue @@ -15,6 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only @{{ acct(user) }} Suspended + Suspended in Remote Silenced Moderator @@ -254,6 +255,7 @@ const ap = ref(null); const moderator = ref(false); const silenced = ref(false); const suspended = ref(false); +const remoteSuspended = ref(false); const isSystem = ref(false); const moderationNote = ref(''); const filesPaginator = markRaw(new Paginator('admin/drive/files', { @@ -288,6 +290,7 @@ function createFetcher() { moderator.value = info.value.isModerator; silenced.value = info.value.isSilenced; suspended.value = info.value.isSuspended; + remoteSuspended.value = info.value.isRemoteSuspended; moderationNote.value = info.value.moderationNote; isSystem.value = user.value.host == null && user.value.username.includes('.'); diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts index df6a22ec41..40932afee3 100644 --- a/packages/misskey-js/src/autogen/types.ts +++ b/packages/misskey-js/src/autogen/types.ts @@ -11586,6 +11586,7 @@ export interface operations { isModerator: boolean; isSilenced: boolean; isSuspended: boolean; + isRemoteSuspended: boolean; isHibernated: boolean; lastActiveDate: string | null; moderationNote: string;