From cd210001e6ffd6232678cbc74f06f8e6d05a1d15 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Wed, 14 Aug 2024 18:08:51 +0900 Subject: [PATCH 01/40] =?UTF-8?q?enhance(backend):=20=E5=87=8D=E7=B5=90?= =?UTF-8?q?=E3=81=95=E3=82=8C=E3=81=9F=E3=82=A2=E3=82=AB=E3=82=A6=E3=83=B3?= =?UTF-8?q?=E3=83=88=E3=81=AE=E3=83=95=E3=82=A9=E3=83=AD=E3=83=BC=E3=83=AA?= =?UTF-8?q?=E3=82=AF=E3=82=A8=E3=82=B9=E3=83=88=E3=82=92=E8=A1=A8=E7=A4=BA?= =?UTF-8?q?=E3=81=97=E3=81=AA=E3=81=84=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + .../backend/src/core/UserSuspendService.ts | 79 ++++++++++++++++++- .../api/endpoints/admin/suspend-user.ts | 51 +----------- .../api/endpoints/admin/unsuspend-user.ts | 14 +--- 4 files changed, 81 insertions(+), 64 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 89c90bb663..a3abadfe3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - Fix: mCaptchaを使用していてもbotプロテクションに関する警告が消えないのを修正 ### Server +- Enhance: 凍結されたアカウントのフォローリクエストを表示しないように - Fix: WSの`readAllNotifications` メッセージが `body` を持たない場合に動作しない問題 #14374 - 通知ページや通知カラム(デッキ)を開いている状態において、新たに発生した通知が既読されない問題が修正されます。 - これにより、プッシュ通知が有効な同条件下の環境において、プッシュ通知が常に発生してしまう問題も修正されます。 diff --git a/packages/backend/src/core/UserSuspendService.ts b/packages/backend/src/core/UserSuspendService.ts index d594a223f4..7920e58e36 100644 --- a/packages/backend/src/core/UserSuspendService.ts +++ b/packages/backend/src/core/UserSuspendService.ts @@ -5,7 +5,7 @@ import { Inject, Injectable } from '@nestjs/common'; import { Not, IsNull } from 'typeorm'; -import type { FollowingsRepository } from '@/models/_.js'; +import type { FollowingsRepository, FollowRequestsRepository, UsersRepository } from '@/models/_.js'; import type { MiUser } from '@/models/User.js'; import { QueueService } from '@/core/QueueService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; @@ -13,24 +13,75 @@ import { DI } from '@/di-symbols.js'; import { ApRendererService } from '@/core/activitypub/ApRendererService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { bindThis } from '@/decorators.js'; +import { RelationshipJobData } from '@/queue/types.js'; +import { ModerationLogService } from '@/core/ModerationLogService.js'; @Injectable() export class UserSuspendService { constructor( + @Inject(DI.usersRepository) + private usersRepository: UsersRepository, + @Inject(DI.followingsRepository) private followingsRepository: FollowingsRepository, + @Inject(DI.followRequestsRepository) + private followRequestsRepository: FollowRequestsRepository, + private userEntityService: UserEntityService, private queueService: QueueService, private globalEventService: GlobalEventService, private apRendererService: ApRendererService, + private moderationLogService: ModerationLogService, ) { } @bindThis - public async doPostSuspend(user: { id: MiUser['id']; host: MiUser['host'] }): Promise { + public async suspend(user: MiUser, moderator: MiUser): Promise { + await this.usersRepository.update(user.id, { + isSuspended: true, + }); + + 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 => {}); + })(); + } + + @bindThis + public async unsuspend(user: MiUser, moderator: MiUser): Promise { + await this.usersRepository.update(user.id, { + isSuspended: false, + }); + + this.moderationLogService.log(moderator, 'unsuspend', { + userId: user.id, + userUsername: user.username, + userHost: user.host, + }); + + (async () => { + await this.postUnsuspend(user).catch(e => {}); + })(); + } + + @bindThis + private async postSuspend(user: { id: MiUser['id']; host: MiUser['host'] }): Promise { 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)); @@ -58,7 +109,7 @@ export class UserSuspendService { } @bindThis - public async doPostUnsuspend(user: MiUser): Promise { + private async postUnsuspend(user: MiUser): Promise { this.globalEventService.publishInternalEvent('userChangeSuspendedState', { id: user.id, isSuspended: false }); if (this.userEntityService.isLocalUser(user)) { @@ -86,4 +137,26 @@ export class UserSuspendService { } } } + + @bindThis + private async unFollowAll(follower: MiUser) { + const followings = await this.followingsRepository.find({ + where: { + followerId: follower.id, + followeeId: Not(IsNull()), + }, + }); + + const jobs: RelationshipJobData[] = []; + for (const following of followings) { + if (following.followeeId && following.followerId) { + jobs.push({ + from: { id: following.followerId }, + to: { id: following.followeeId }, + silent: true, + }); + } + } + this.queueService.createUnfollowJob(jobs); + } } diff --git a/packages/backend/src/server/api/endpoints/admin/suspend-user.ts b/packages/backend/src/server/api/endpoints/admin/suspend-user.ts index 8a946405cc..9f7378945e 100644 --- a/packages/backend/src/server/api/endpoints/admin/suspend-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/suspend-user.ts @@ -3,18 +3,13 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { IsNull, Not } from 'typeorm'; +import { } from 'typeorm'; import { Inject, Injectable } from '@nestjs/common'; import { Endpoint } from '@/server/api/endpoint-base.js'; -import type { UsersRepository, FollowingsRepository } from '@/models/_.js'; -import type { MiUser } from '@/models/User.js'; -import type { RelationshipJobData } from '@/queue/types.js'; -import { ModerationLogService } from '@/core/ModerationLogService.js'; +import type { UsersRepository } from '@/models/_.js'; import { UserSuspendService } from '@/core/UserSuspendService.js'; import { DI } from '@/di-symbols.js'; -import { bindThis } from '@/decorators.js'; import { RoleService } from '@/core/RoleService.js'; -import { QueueService } from '@/core/QueueService.js'; export const meta = { tags: ['admin'], @@ -38,13 +33,8 @@ export default class extends Endpoint { // eslint- @Inject(DI.usersRepository) private usersRepository: UsersRepository, - @Inject(DI.followingsRepository) - private followingsRepository: FollowingsRepository, - private userSuspendService: UserSuspendService, private roleService: RoleService, - private moderationLogService: ModerationLogService, - private queueService: QueueService, ) { super(meta, paramDef, async (ps, me) => { const user = await this.usersRepository.findOneBy({ id: ps.userId }); @@ -57,42 +47,7 @@ export default class extends Endpoint { // eslint- throw new Error('cannot suspend moderator account'); } - await this.usersRepository.update(user.id, { - isSuspended: true, - }); - - this.moderationLogService.log(me, 'suspend', { - userId: user.id, - userUsername: user.username, - userHost: user.host, - }); - - (async () => { - await this.userSuspendService.doPostSuspend(user).catch(e => {}); - await this.unFollowAll(user).catch(e => {}); - })(); + await this.userSuspendService.suspend(user, me); }); } - - @bindThis - private async unFollowAll(follower: MiUser) { - const followings = await this.followingsRepository.find({ - where: { - followerId: follower.id, - followeeId: Not(IsNull()), - }, - }); - - const jobs: RelationshipJobData[] = []; - for (const following of followings) { - if (following.followeeId && following.followerId) { - jobs.push({ - from: { id: following.followerId }, - to: { id: following.followeeId }, - silent: true, - }); - } - } - this.queueService.createUnfollowJob(jobs); - } } diff --git a/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts b/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts index 2c2b1bf6f5..b52c638cdb 100644 --- a/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts @@ -6,7 +6,6 @@ import { Inject, Injectable } from '@nestjs/common'; import { Endpoint } from '@/server/api/endpoint-base.js'; import type { UsersRepository } from '@/models/_.js'; -import { ModerationLogService } from '@/core/ModerationLogService.js'; import { UserSuspendService } from '@/core/UserSuspendService.js'; import { DI } from '@/di-symbols.js'; @@ -33,7 +32,6 @@ export default class extends Endpoint { // eslint- private usersRepository: UsersRepository, private userSuspendService: UserSuspendService, - private moderationLogService: ModerationLogService, ) { super(meta, paramDef, async (ps, me) => { const user = await this.usersRepository.findOneBy({ id: ps.userId }); @@ -42,17 +40,7 @@ export default class extends Endpoint { // eslint- throw new Error('user not found'); } - await this.usersRepository.update(user.id, { - isSuspended: false, - }); - - this.moderationLogService.log(me, 'unsuspend', { - userId: user.id, - userUsername: user.username, - userHost: user.host, - }); - - this.userSuspendService.doPostUnsuspend(user); + await this.userSuspendService.unsuspend(user, me); }); } } From 86dd4abadcb19c3fa4e082b7ab2dc80c5d93618b Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Wed, 14 Aug 2024 20:29:06 +0900 Subject: [PATCH 02/40] =?UTF-8?q?Revert=20"enhance(backend):=20=E5=87=8D?= =?UTF-8?q?=E7=B5=90=E3=81=95=E3=82=8C=E3=81=9F=E3=82=A2=E3=82=AB=E3=82=A6?= =?UTF-8?q?=E3=83=B3=E3=83=88=E3=81=AE=E3=83=95=E3=82=A9=E3=83=AD=E3=83=BC?= =?UTF-8?q?=E3=83=AA=E3=82=AF=E3=82=A8=E3=82=B9=E3=83=88=E3=82=92=E8=A1=A8?= =?UTF-8?q?=E7=A4=BA=E3=81=97=E3=81=AA=E3=81=84=E3=82=88=E3=81=86=E3=81=AB?= =?UTF-8?q?"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit cd210001e6ffd6232678cbc74f06f8e6d05a1d15. --- CHANGELOG.md | 1 - .../backend/src/core/UserSuspendService.ts | 79 +------------------ .../api/endpoints/admin/suspend-user.ts | 51 +++++++++++- .../api/endpoints/admin/unsuspend-user.ts | 14 +++- 4 files changed, 64 insertions(+), 81 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3abadfe3b..89c90bb663 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,6 @@ - Fix: mCaptchaを使用していてもbotプロテクションに関する警告が消えないのを修正 ### Server -- Enhance: 凍結されたアカウントのフォローリクエストを表示しないように - Fix: WSの`readAllNotifications` メッセージが `body` を持たない場合に動作しない問題 #14374 - 通知ページや通知カラム(デッキ)を開いている状態において、新たに発生した通知が既読されない問題が修正されます。 - これにより、プッシュ通知が有効な同条件下の環境において、プッシュ通知が常に発生してしまう問題も修正されます。 diff --git a/packages/backend/src/core/UserSuspendService.ts b/packages/backend/src/core/UserSuspendService.ts index 7920e58e36..d594a223f4 100644 --- a/packages/backend/src/core/UserSuspendService.ts +++ b/packages/backend/src/core/UserSuspendService.ts @@ -5,7 +5,7 @@ import { Inject, Injectable } from '@nestjs/common'; import { Not, IsNull } from 'typeorm'; -import type { FollowingsRepository, FollowRequestsRepository, UsersRepository } from '@/models/_.js'; +import type { FollowingsRepository } from '@/models/_.js'; import type { MiUser } from '@/models/User.js'; import { QueueService } from '@/core/QueueService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; @@ -13,75 +13,24 @@ import { DI } from '@/di-symbols.js'; import { ApRendererService } from '@/core/activitypub/ApRendererService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { bindThis } from '@/decorators.js'; -import { RelationshipJobData } from '@/queue/types.js'; -import { ModerationLogService } from '@/core/ModerationLogService.js'; @Injectable() export class UserSuspendService { constructor( - @Inject(DI.usersRepository) - private usersRepository: UsersRepository, - @Inject(DI.followingsRepository) private followingsRepository: FollowingsRepository, - @Inject(DI.followRequestsRepository) - private followRequestsRepository: FollowRequestsRepository, - private userEntityService: UserEntityService, private queueService: QueueService, private globalEventService: GlobalEventService, private apRendererService: ApRendererService, - private moderationLogService: ModerationLogService, ) { } @bindThis - public async suspend(user: MiUser, moderator: MiUser): Promise { - await this.usersRepository.update(user.id, { - isSuspended: true, - }); - - 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 => {}); - })(); - } - - @bindThis - public async unsuspend(user: MiUser, moderator: MiUser): Promise { - await this.usersRepository.update(user.id, { - isSuspended: false, - }); - - this.moderationLogService.log(moderator, 'unsuspend', { - userId: user.id, - userUsername: user.username, - userHost: user.host, - }); - - (async () => { - await this.postUnsuspend(user).catch(e => {}); - })(); - } - - @bindThis - private async postSuspend(user: { id: MiUser['id']; host: MiUser['host'] }): Promise { + public async doPostSuspend(user: { id: MiUser['id']; host: MiUser['host'] }): Promise { 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)); @@ -109,7 +58,7 @@ export class UserSuspendService { } @bindThis - private async postUnsuspend(user: MiUser): Promise { + public async doPostUnsuspend(user: MiUser): Promise { this.globalEventService.publishInternalEvent('userChangeSuspendedState', { id: user.id, isSuspended: false }); if (this.userEntityService.isLocalUser(user)) { @@ -137,26 +86,4 @@ export class UserSuspendService { } } } - - @bindThis - private async unFollowAll(follower: MiUser) { - const followings = await this.followingsRepository.find({ - where: { - followerId: follower.id, - followeeId: Not(IsNull()), - }, - }); - - const jobs: RelationshipJobData[] = []; - for (const following of followings) { - if (following.followeeId && following.followerId) { - jobs.push({ - from: { id: following.followerId }, - to: { id: following.followeeId }, - silent: true, - }); - } - } - this.queueService.createUnfollowJob(jobs); - } } diff --git a/packages/backend/src/server/api/endpoints/admin/suspend-user.ts b/packages/backend/src/server/api/endpoints/admin/suspend-user.ts index 9f7378945e..8a946405cc 100644 --- a/packages/backend/src/server/api/endpoints/admin/suspend-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/suspend-user.ts @@ -3,13 +3,18 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { } from 'typeorm'; +import { IsNull, Not } from 'typeorm'; import { Inject, Injectable } from '@nestjs/common'; import { Endpoint } from '@/server/api/endpoint-base.js'; -import type { UsersRepository } from '@/models/_.js'; +import type { UsersRepository, FollowingsRepository } from '@/models/_.js'; +import type { MiUser } from '@/models/User.js'; +import type { RelationshipJobData } from '@/queue/types.js'; +import { ModerationLogService } from '@/core/ModerationLogService.js'; import { UserSuspendService } from '@/core/UserSuspendService.js'; import { DI } from '@/di-symbols.js'; +import { bindThis } from '@/decorators.js'; import { RoleService } from '@/core/RoleService.js'; +import { QueueService } from '@/core/QueueService.js'; export const meta = { tags: ['admin'], @@ -33,8 +38,13 @@ export default class extends Endpoint { // eslint- @Inject(DI.usersRepository) private usersRepository: UsersRepository, + @Inject(DI.followingsRepository) + private followingsRepository: FollowingsRepository, + private userSuspendService: UserSuspendService, private roleService: RoleService, + private moderationLogService: ModerationLogService, + private queueService: QueueService, ) { super(meta, paramDef, async (ps, me) => { const user = await this.usersRepository.findOneBy({ id: ps.userId }); @@ -47,7 +57,42 @@ export default class extends Endpoint { // eslint- throw new Error('cannot suspend moderator account'); } - await this.userSuspendService.suspend(user, me); + await this.usersRepository.update(user.id, { + isSuspended: true, + }); + + this.moderationLogService.log(me, 'suspend', { + userId: user.id, + userUsername: user.username, + userHost: user.host, + }); + + (async () => { + await this.userSuspendService.doPostSuspend(user).catch(e => {}); + await this.unFollowAll(user).catch(e => {}); + })(); }); } + + @bindThis + private async unFollowAll(follower: MiUser) { + const followings = await this.followingsRepository.find({ + where: { + followerId: follower.id, + followeeId: Not(IsNull()), + }, + }); + + const jobs: RelationshipJobData[] = []; + for (const following of followings) { + if (following.followeeId && following.followerId) { + jobs.push({ + from: { id: following.followerId }, + to: { id: following.followeeId }, + silent: true, + }); + } + } + this.queueService.createUnfollowJob(jobs); + } } diff --git a/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts b/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts index b52c638cdb..2c2b1bf6f5 100644 --- a/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts @@ -6,6 +6,7 @@ import { Inject, Injectable } from '@nestjs/common'; import { Endpoint } from '@/server/api/endpoint-base.js'; import type { UsersRepository } from '@/models/_.js'; +import { ModerationLogService } from '@/core/ModerationLogService.js'; import { UserSuspendService } from '@/core/UserSuspendService.js'; import { DI } from '@/di-symbols.js'; @@ -32,6 +33,7 @@ export default class extends Endpoint { // eslint- private usersRepository: UsersRepository, private userSuspendService: UserSuspendService, + private moderationLogService: ModerationLogService, ) { super(meta, paramDef, async (ps, me) => { const user = await this.usersRepository.findOneBy({ id: ps.userId }); @@ -40,7 +42,17 @@ export default class extends Endpoint { // eslint- throw new Error('user not found'); } - await this.userSuspendService.unsuspend(user, me); + await this.usersRepository.update(user.id, { + isSuspended: false, + }); + + this.moderationLogService.log(me, 'unsuspend', { + userId: user.id, + userUsername: user.username, + userHost: user.host, + }); + + this.userSuspendService.doPostUnsuspend(user); }); } } From b68b2ee8c6102ed1c67056cf122a51d87ae5b567 Mon Sep 17 00:00:00 2001 From: zyoshoka <107108195+zyoshoka@users.noreply.github.com> Date: Wed, 14 Aug 2024 20:29:33 +0900 Subject: [PATCH 03/40] refactor(frontend): remove stale reload method call on `/admin/users` page (#14406) --- packages/frontend/src/pages/admin/users.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/pages/admin/users.vue b/packages/frontend/src/pages/admin/users.vue index 7d87b97a36..d1bbb5b734 100644 --- a/packages/frontend/src/pages/admin/users.vue +++ b/packages/frontend/src/pages/admin/users.vue @@ -33,11 +33,11 @@ SPDX-License-Identifier: AGPL-3.0-only
- + - + From 45d88574c309dcbf014e1ebc7895caca0b8dbed6 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 15 Aug 2024 20:02:53 +0900 Subject: [PATCH 04/40] enhance(frontend): improve usability --- packages/frontend/src/boot/main-boot.ts | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/packages/frontend/src/boot/main-boot.ts b/packages/frontend/src/boot/main-boot.ts index 2a549d1e8b..3e7c4f26f8 100644 --- a/packages/frontend/src/boot/main-boot.ts +++ b/packages/frontend/src/boot/main-boot.ts @@ -231,17 +231,18 @@ export async function mainBoot() { claimAchievement('client60min'); }, 1000 * 60 * 60); - const lastUsed = miLocalStorage.getItem('lastUsed'); - if (lastUsed) { - const lastUsedDate = parseInt(lastUsed, 10); - // 二時間以上前なら - if (Date.now() - lastUsedDate > 1000 * 60 * 60 * 2) { - toast(i18n.tsx.welcomeBackWithName({ - name: $i.name || $i.username, - })); - } - } - miLocalStorage.setItem('lastUsed', Date.now().toString()); + // 邪魔 + //const lastUsed = miLocalStorage.getItem('lastUsed'); + //if (lastUsed) { + // const lastUsedDate = parseInt(lastUsed, 10); + // // 二時間以上前なら + // if (Date.now() - lastUsedDate > 1000 * 60 * 60 * 2) { + // toast(i18n.tsx.welcomeBackWithName({ + // name: $i.name || $i.username, + // })); + // } + //} + //miLocalStorage.setItem('lastUsed', Date.now().toString()); const latestDonationInfoShownAt = miLocalStorage.getItem('latestDonationInfoShownAt'); const neverShowDonationInfo = miLocalStorage.getItem('neverShowDonationInfo'); From a8810af8d9a78c0819781001ab045a9c8cf9d171 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?= <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Fri, 16 Aug 2024 21:02:12 +0900 Subject: [PATCH 05/40] =?UTF-8?q?fix(backend):=20=E3=83=AA=E3=83=90?= =?UTF-8?q?=E3=83=BC=E3=82=B7=E3=81=AE=E8=A8=AD=E5=AE=9A=E5=A4=89=E6=9B=B4?= =?UTF-8?q?=E3=81=8C=E5=8F=8D=E6=98=A0=E3=81=95=E3=82=8C=E3=81=AA=E3=81=84?= =?UTF-8?q?=E3=81=AE=E3=82=92=E4=BF=AE=E6=AD=A3=20(#14404)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(backend): リバーシの設定変更が反映されないのを修正 * Update Changelog * add bindthis --- CHANGELOG.md | 1 + packages/backend/src/core/ReversiService.ts | 33 ++++++++++++++++--- .../api/stream/channels/reversi-game.ts | 8 +++-- packages/misskey-js/etc/misskey-js.api.md | 3 ++ packages/misskey-js/src/consts.ts | 13 +++++--- packages/misskey-js/src/index.ts | 1 + 6 files changed, 47 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 89c90bb663..9385842d62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/679) - Fix: ActivityPubのエンティティタイプ判定で不明なタイプを受け取った場合でも処理を継続するように - キュー処理のつまりが改善される可能性があります +- Fix: リバーシの対局設定の変更が反映されないのを修正 ## 2024.7.0 diff --git a/packages/backend/src/core/ReversiService.ts b/packages/backend/src/core/ReversiService.ts index 7f939b99c7..51dca3da59 100644 --- a/packages/backend/src/core/ReversiService.ts +++ b/packages/backend/src/core/ReversiService.ts @@ -6,6 +6,7 @@ import { Inject, Injectable } from '@nestjs/common'; import * as Redis from 'ioredis'; import { ModuleRef } from '@nestjs/core'; +import { reversiUpdateKeys } from 'misskey-js'; import * as Reversi from 'misskey-reversi'; import { IsNull, LessThan, MoreThan } from 'typeorm'; import type { @@ -399,7 +400,33 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit { } @bindThis - public async updateSettings(gameId: MiReversiGame['id'], user: MiUser, key: string, value: any) { + public isValidReversiUpdateKey(key: unknown): key is typeof reversiUpdateKeys[number] { + if (typeof key !== 'string') return false; + return (reversiUpdateKeys as string[]).includes(key); + } + + @bindThis + public isValidReversiUpdateValue(key: K, value: unknown): value is MiReversiGame[K] { + switch (key) { + case 'map': + return Array.isArray(value) && value.every(row => typeof row === 'string'); + case 'bw': + return typeof value === 'string' && ['random', '1', '2'].includes(value); + case 'isLlotheo': + return typeof value === 'boolean'; + case 'canPutEverywhere': + return typeof value === 'boolean'; + case 'loopedBoard': + return typeof value === 'boolean'; + case 'timeLimitForEachTurn': + return typeof value === 'number' && value >= 0; + default: + return false; + } + } + + @bindThis + public async updateSettings(gameId: MiReversiGame['id'], user: MiUser, key: K, value: MiReversiGame[K]) { const game = await this.get(gameId); if (game == null) throw new Error('game not found'); if (game.isStarted) return; @@ -407,10 +434,6 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit { if ((game.user1Id === user.id) && game.user1Ready) return; if ((game.user2Id === user.id) && game.user2Ready) return; - if (!['map', 'bw', 'isLlotheo', 'canPutEverywhere', 'loopedBoard', 'timeLimitForEachTurn'].includes(key)) return; - - // TODO: より厳格なバリデーション - const updatedGame = { ...game, [key]: value, diff --git a/packages/backend/src/server/api/stream/channels/reversi-game.ts b/packages/backend/src/server/api/stream/channels/reversi-game.ts index c6f4a4ae3b..7597a1cfa3 100644 --- a/packages/backend/src/server/api/stream/channels/reversi-game.ts +++ b/packages/backend/src/server/api/stream/channels/reversi-game.ts @@ -12,6 +12,7 @@ import { ReversiGameEntityService } from '@/core/entities/ReversiGameEntityServi import { isJsonObject } from '@/misc/json-value.js'; import type { JsonObject, JsonValue } from '@/misc/json-value.js'; import Channel, { type MiChannelService } from '../channel.js'; +import { reversiUpdateKeys } from 'misskey-js'; class ReversiGameChannel extends Channel { public readonly chName = 'reversiGame'; @@ -46,8 +47,9 @@ class ReversiGameChannel extends Channel { break; case 'updateSettings': if (!isJsonObject(body)) return; - if (typeof body.key !== 'string') return; - if (!isJsonObject(body.value)) return; + if (!this.reversiService.isValidReversiUpdateKey(body.key)) return; + if (!this.reversiService.isValidReversiUpdateValue(body.key, body.value)) return; + this.updateSettings(body.key, body.value); break; case 'cancel': @@ -64,7 +66,7 @@ class ReversiGameChannel extends Channel { } @bindThis - private async updateSettings(key: string, value: JsonObject) { + private async updateSettings(key: K, value: MiReversiGame[K]) { if (this.user == null) return; this.reversiService.updateSettings(this.gameId!, this.user, key, value); diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index 16cb560a52..77a3820f46 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -2829,6 +2829,9 @@ type ReversiShowGameResponse = operations['reversi___show-game']['responses']['2 // @public (undocumented) type ReversiSurrenderRequest = operations['reversi___surrender']['requestBody']['content']['application/json']; +// @public (undocumented) +export const reversiUpdateKeys: ["map", "bw", "isLlotheo", "canPutEverywhere", "loopedBoard", "timeLimitForEachTurn"]; + // @public (undocumented) type ReversiVerifyRequest = operations['reversi___verify']['requestBody']['content']['application/json']; diff --git a/packages/misskey-js/src/consts.ts b/packages/misskey-js/src/consts.ts index aa8eeb48cb..5863a0b1dd 100644 --- a/packages/misskey-js/src/consts.ts +++ b/packages/misskey-js/src/consts.ts @@ -1,11 +1,16 @@ import type { operations } from './autogen/types.js'; import type { - AbuseReportNotificationRecipient, Ad, + AbuseReportNotificationRecipient, + Ad, Announcement, - EmojiDetailed, InviteCode, + EmojiDetailed, + InviteCode, MetaDetailed, Note, - Role, SystemWebhook, UserLite, + Role, + ReversiGameDetailed, + SystemWebhook, + UserLite, } from './autogen/models.js'; export const notificationTypes = ['note', 'follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'pollEnded', 'receiveFollowRequest', 'followRequestAccepted', 'groupInvited', 'app', 'roleAssigned', 'achievementEarned'] as const; @@ -159,7 +164,7 @@ export const reversiUpdateKeys = [ 'canPutEverywhere', 'loopedBoard', 'timeLimitForEachTurn', -] as const; +] as const satisfies (keyof ReversiGameDetailed)[]; export type ReversiUpdateKey = typeof reversiUpdateKeys[number]; diff --git a/packages/misskey-js/src/index.ts b/packages/misskey-js/src/index.ts index 28007a8ade..7e0165d20b 100644 --- a/packages/misskey-js/src/index.ts +++ b/packages/misskey-js/src/index.ts @@ -22,6 +22,7 @@ export const mutedNoteReasons = consts.mutedNoteReasons; export const followingVisibilities = consts.followingVisibilities; export const followersVisibilities = consts.followersVisibilities; export const moderationLogTypes = consts.moderationLogTypes; +export const reversiUpdateKeys = consts.reversiUpdateKeys; // api extractor not supported yet //export * as api from './api.js'; From 26322048db819e294af80b6b5cf3799da10d73dc Mon Sep 17 00:00:00 2001 From: zyoshoka <107108195+zyoshoka@users.noreply.github.com> Date: Fri, 16 Aug 2024 21:04:08 +0900 Subject: [PATCH 06/40] fix(frontend): correct condition to displayed as system account on moderation page (#14407) --- CHANGELOG.md | 1 + packages/frontend/src/pages/admin-user.vue | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9385842d62..4cf454bb08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - Fix: ページ遷移に失敗することがある問題を修正 - Fix: iOSでユーザー名などがリンクとして誤検知される現象を抑制 - Fix: mCaptchaを使用していてもbotプロテクションに関する警告が消えないのを修正 +- Fix: ユーザーのモデレーションページにおいてユーザー名にドットが入っているとシステムアカウントとして表示されてしまう問題を修正 ### Server - Fix: WSの`readAllNotifications` メッセージが `body` を持たない場合に動作しない問題 #14374 diff --git a/packages/frontend/src/pages/admin-user.vue b/packages/frontend/src/pages/admin-user.vue index 1459997dcb..7cab8bf8bd 100644 --- a/packages/frontend/src/pages/admin-user.vue +++ b/packages/frontend/src/pages/admin-user.vue @@ -22,7 +22,7 @@ SPDX-License-Identifier: AGPL-3.0-only
- {{ i18n.ts.isSystemAccount }} + {{ i18n.ts.isSystemAccount }} {{ i18n.ts.instanceInfo }} From 6db3c50e32eb985ed76543e68ef0d75ffdad6874 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?= <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Fri, 16 Aug 2024 21:43:20 +0900 Subject: [PATCH 07/40] =?UTF-8?q?fix(frontend):=20Misskey=E3=81=AE?= =?UTF-8?q?=E5=88=A9=E7=94=A8=E4=B8=AD=E3=81=AB=E4=BD=BF=E7=94=A8=E3=81=A7?= =?UTF-8?q?=E3=81=8D=E3=82=8B=E3=82=BF=E3=82=A4=E3=83=A0=E3=83=A9=E3=82=A4?= =?UTF-8?q?=E3=83=B3=E3=81=AE=E7=A8=AE=E9=A1=9E=E3=81=8C=E5=A4=89=E5=8C=96?= =?UTF-8?q?=E3=81=97=E3=81=9F=E5=A0=B4=E5=90=88=E3=80=81=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E3=81=A7=E3=81=8D=E3=81=AA=E3=81=84=E3=82=BF=E3=82=A4=E3=83=A0?= =?UTF-8?q?=E3=83=A9=E3=82=A4=E3=83=B3=E3=81=8C=E8=A1=A8=E7=A4=BA=E3=81=95?= =?UTF-8?q?=E3=82=8C=E3=81=AA=E3=81=84=E3=82=88=E3=81=86=E3=81=AB=20(#1441?= =?UTF-8?q?2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(frontend): Misskeyの利用中に使用できるタイムラインの種類が変化した場合、使用できないタイムラインが表示されないように * Update timeline.vue * Update timeline.vue --- packages/frontend/src/pages/timeline.vue | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/packages/frontend/src/pages/timeline.vue b/packages/frontend/src/pages/timeline.vue index 32f6dd0e5a..258d1443d9 100644 --- a/packages/frontend/src/pages/timeline.vue +++ b/packages/frontend/src/pages/timeline.vue @@ -34,7 +34,7 @@ SPDX-License-Identifier: AGPL-3.0-only