From 0a73973a7c6e6e95a5206bfc5388ff7f7a9ba8ed Mon Sep 17 00:00:00 2001 From: Nafu Satsuki Date: Sat, 18 Nov 2023 20:39:48 +0900 Subject: [PATCH 1/9] =?UTF-8?q?=E3=83=A1=E3=83=BC=E3=83=AB=E3=82=A2?= =?UTF-8?q?=E3=83=89=E3=83=AC=E3=82=B9=E3=81=AE=E8=AA=8D=E8=A8=BC=E3=81=AB?= =?UTF-8?q?verifymail.io=E3=82=92=E4=BD=BF=E3=81=88=E3=82=8B=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB=E3=81=99=E3=82=8B=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../1700303245007-supportVerifyMailApi.js | 18 ++++ packages/backend/src/core/EmailService.ts | 92 +++++++++++++++++-- packages/backend/src/models/Meta.ts | 11 +++ .../server/api/endpoints/admin/update-meta.ts | 14 +++ .../frontend/src/pages/admin/security.vue | 13 +++ 5 files changed, 140 insertions(+), 8 deletions(-) create mode 100644 packages/backend/migration/1700303245007-supportVerifyMailApi.js diff --git a/packages/backend/migration/1700303245007-supportVerifyMailApi.js b/packages/backend/migration/1700303245007-supportVerifyMailApi.js new file mode 100644 index 0000000000..3ac59ec37a --- /dev/null +++ b/packages/backend/migration/1700303245007-supportVerifyMailApi.js @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class SupportVerifyMailApi1700303245007 { + name = 'SupportVerifyMailApi1700303245007' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" ADD "verifymailAuthKey" character varying(1024)`); + await queryRunner.query(`ALTER TABLE "meta" ADD "enableVerifymailApi" boolean NOT NULL DEFAULT false`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableVerifymailApi"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "verifymailAuthKey"`); + } +} diff --git a/packages/backend/src/core/EmailService.ts b/packages/backend/src/core/EmailService.ts index c9da3f77c0..8f28197ebc 100644 --- a/packages/backend/src/core/EmailService.ts +++ b/packages/backend/src/core/EmailService.ts @@ -13,6 +13,9 @@ import type Logger from '@/logger.js'; import type { UserProfilesRepository } from '@/models/_.js'; import { LoggerService } from '@/core/LoggerService.js'; import { bindThis } from '@/decorators.js'; +import {URLSearchParams} from "node:url"; +import { HttpRequestService } from '@/core/HttpRequestService.js'; +import {SubOutputFormat} from "deep-email-validator/dist/output/output.js"; @Injectable() export class EmailService { @@ -27,6 +30,7 @@ export class EmailService { private metaService: MetaService, private loggerService: LoggerService, + private httpRequestService: HttpRequestService, ) { this.logger = this.loggerService.getLogger('email'); } @@ -160,14 +164,25 @@ export class EmailService { email: emailAddress, }); - const validated = meta.enableActiveEmailValidation ? await validateEmail({ - email: emailAddress, - validateRegex: true, - validateMx: true, - validateTypo: false, // TLDを見ているみたいだけどclubとか弾かれるので - validateDisposable: true, // 捨てアドかどうかチェック - validateSMTP: false, // 日本だと25ポートが殆どのプロバイダーで塞がれていてタイムアウトになるので - }) : { valid: true, reason: null }; + const verifymailApi = meta.enableVerifymailApi && meta.verifymailAuthKey != null; + let validated; + + if (meta.enableActiveEmailValidation) { + if (verifymailApi) { + validated = await this.verifyMail(emailAddress, meta.verifymailAuthKey); + } else { + validated = meta.enableActiveEmailValidation ? await validateEmail({ + email: emailAddress, + validateRegex: true, + validateMx: true, + validateTypo: false, // TLDを見ているみたいだけどclubとか弾かれるので + validateDisposable: true, // 捨てアドかどうかチェック + validateSMTP: false, // 日本だと25ポートが殆どのプロバイダーで塞がれていてタイムアウトになるので + }) : { valid: true, reason: null }; + } + } else { + validated = { valid: true, reason: null }; + } const available = exist === 0 && validated.valid; @@ -182,4 +197,65 @@ export class EmailService { null, }; } + + private async verifyMail(emailAddress: string, verifymailAuthKey: string): Promise<{ + valid: boolean; + reason: 'used' | 'format' | 'disposable' | 'mx' | 'smtp' | null; + }> { + const endpoint = 'https://verifymail.io/api/' + emailAddress + '?key=' + verifymailAuthKey; + const res = await this.httpRequestService.send(endpoint, { + method: 'GET', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + Accept: 'application/json, */*', + }, + }); + + const json = (await res.json()) as { + block: boolean; + catch_all: boolean; + deliverable_email: boolean; + disposable: boolean; + domain: string; + email_address: string; + email_provider: string; + mx: boolean; + mx_fallback: boolean; + mx_host: string[]; + mx_ip: string[]; + mx_priority: { [key: string]: number }; + privacy: boolean; + related_domains: string[]; + }; + + if (json.email_address === undefined) { + return { + valid: false, + reason: 'format', + }; + } + if (json.deliverable_email !== undefined && !json.deliverable_email) { + return { + valid: false, + reason: 'smtp', + }; + } + if (json.disposable) { + return { + valid: false, + reason: 'disposable', + }; + } + if (json.mx !== undefined && !json.mx) { + return { + valid: false, + reason: 'mx', + }; + } + + return { + valid: true, + reason: null, + }; + } } diff --git a/packages/backend/src/models/Meta.ts b/packages/backend/src/models/Meta.ts index 14a72add1d..83e8962f5d 100644 --- a/packages/backend/src/models/Meta.ts +++ b/packages/backend/src/models/Meta.ts @@ -446,6 +446,17 @@ export class MiMeta { }) public enableActiveEmailValidation: boolean; + @Column('boolean', { + default: false, + }) + public enableVerifymailApi: boolean; + + @Column('varchar', { + length: 1024, + nullable: true, + }) + public verifymailAuthKey: string | null; + @Column('boolean', { default: true, }) diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts index da3e5dd9ac..d6f9b2cd94 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -113,6 +113,8 @@ export const paramDef = { objectStorageS3ForcePathStyle: { type: 'boolean' }, enableIpLogging: { type: 'boolean' }, enableActiveEmailValidation: { type: 'boolean' }, + enableVerifymailApi: { type: 'boolean' }, + verifymailAuthKey: { type: 'string', nullable: true }, enableChartsForRemoteUser: { type: 'boolean' }, enableChartsForFederatedInstances: { type: 'boolean' }, enableServerMachineStats: { type: 'boolean' }, @@ -454,6 +456,18 @@ export default class extends Endpoint { // eslint- set.enableActiveEmailValidation = ps.enableActiveEmailValidation; } + if (ps.enableVerifymailApi !== undefined) { + set.enableVerifymailApi = ps.enableVerifymailApi; + } + + if (ps.verifymailAuthKey !== undefined) { + if (ps.verifymailAuthKey === '') { + set.verifymailAuthKey = null; + } else { + set.verifymailAuthKey = ps.verifymailAuthKey; + } + } + if (ps.enableChartsForRemoteUser !== undefined) { set.enableChartsForRemoteUser = ps.enableChartsForRemoteUser; } diff --git a/packages/frontend/src/pages/admin/security.vue b/packages/frontend/src/pages/admin/security.vue index a2594ee6c5..f7f76d910a 100644 --- a/packages/frontend/src/pages/admin/security.vue +++ b/packages/frontend/src/pages/admin/security.vue @@ -73,6 +73,13 @@ SPDX-License-Identifier: AGPL-3.0-only + + + + + + + @@ -132,6 +139,8 @@ let setSensitiveFlagAutomatically: boolean = $ref(false); let enableSensitiveMediaDetectionForVideos: boolean = $ref(false); let enableIpLogging: boolean = $ref(false); let enableActiveEmailValidation: boolean = $ref(false); +let enableVerifymailApi: boolean = $ref(false); +let verifymailAuthKey: string | null = $ref(null); async function init() { const meta = await os.api('admin/meta'); @@ -150,6 +159,8 @@ async function init() { enableSensitiveMediaDetectionForVideos = meta.enableSensitiveMediaDetectionForVideos; enableIpLogging = meta.enableIpLogging; enableActiveEmailValidation = meta.enableActiveEmailValidation; + enableVerifymailApi = meta.enableVerifymailApi; + verifymailAuthKey = meta.verifymailAuthKey; } function save() { @@ -167,6 +178,8 @@ function save() { enableSensitiveMediaDetectionForVideos, enableIpLogging, enableActiveEmailValidation, + enableVerifymailApi, + verifymailAuthKey, }).then(() => { fetchInstance(); }); From af668b15c447d1c175cd3669fe0025a3aff61d73 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 18 Nov 2023 21:03:01 +0900 Subject: [PATCH 2/9] Update CHANGELOG.md --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92e02508fe..4b08d12093 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,17 @@ --> +## 2023.x.x (unreleased) + +### General +- Feat: メールアドレスの認証にverifymail.ioを使えるように (cherry-pick from https://github.com/TeamNijimiss/misskey/commit/971ba07a44550f68d2ba31c62066db2d43a0caed) + +### Client +- + +### Server +- + ## 2023.11.1 ### General From 30dc6e691d09073a904a40beb94370b6ad3c5c5c Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 18 Nov 2023 21:04:00 +0900 Subject: [PATCH 3/9] lint fix --- packages/backend/src/core/EmailService.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/backend/src/core/EmailService.ts b/packages/backend/src/core/EmailService.ts index 8f28197ebc..f31cec2b3a 100644 --- a/packages/backend/src/core/EmailService.ts +++ b/packages/backend/src/core/EmailService.ts @@ -3,9 +3,11 @@ * SPDX-License-Identifier: AGPL-3.0-only */ +import { URLSearchParams } from 'node:url'; import * as nodemailer from 'nodemailer'; import { Inject, Injectable } from '@nestjs/common'; import { validate as validateEmail } from 'deep-email-validator'; +import { SubOutputFormat } from 'deep-email-validator/dist/output/output.js'; import { MetaService } from '@/core/MetaService.js'; import { DI } from '@/di-symbols.js'; import type { Config } from '@/config.js'; @@ -13,9 +15,7 @@ import type Logger from '@/logger.js'; import type { UserProfilesRepository } from '@/models/_.js'; import { LoggerService } from '@/core/LoggerService.js'; import { bindThis } from '@/decorators.js'; -import {URLSearchParams} from "node:url"; import { HttpRequestService } from '@/core/HttpRequestService.js'; -import {SubOutputFormat} from "deep-email-validator/dist/output/output.js"; @Injectable() export class EmailService { @@ -167,7 +167,7 @@ export class EmailService { const verifymailApi = meta.enableVerifymailApi && meta.verifymailAuthKey != null; let validated; - if (meta.enableActiveEmailValidation) { + if (meta.enableActiveEmailValidation && meta.verifymailAuthKey) { if (verifymailApi) { validated = await this.verifyMail(emailAddress, meta.verifymailAuthKey); } else { From 2b6f789a5bc741d9092d29ea17d03be794ef5d51 Mon Sep 17 00:00:00 2001 From: Nafu Satsuki Date: Sat, 18 Nov 2023 05:20:11 +0900 Subject: [PATCH 4/9] =?UTF-8?q?feat(moderation):=20=E3=83=A2=E3=83=87?= =?UTF-8?q?=E3=83=AC=E3=83=BC=E3=82=BF=E3=83=BC=E3=81=8C=E3=83=A6=E3=83=BC?= =?UTF-8?q?=E3=82=B6=E3=83=BC=E3=81=AE=E3=82=A2=E3=82=A4=E3=82=B3=E3=83=B3?= =?UTF-8?q?=E3=82=82=E3=81=97=E3=81=8F=E3=81=AF=E3=83=90=E3=83=8A=E3=83=BC?= =?UTF-8?q?=E7=94=BB=E5=83=8F=E3=82=92=E6=9C=AA=E8=A8=AD=E5=AE=9A=E7=8A=B6?= =?UTF-8?q?=E6=85=8B=E3=81=AB=E3=81=A7=E3=81=8D=E3=82=8B=E6=A9=9F=E8=83=BD?= =?UTF-8?q?=E3=82=92=E8=BF=BD=E5=8A=A0=20(MisskeyIO#222)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: まっちゃとーにゅ <17376330+u1-liquid@users.noreply.github.com> --- locales/en-US.yml | 4 ++ locales/index.d.ts | 4 ++ locales/ja-JP.yml | 4 ++ .../backend/src/server/api/EndpointsModule.ts | 8 ++++ packages/backend/src/server/api/endpoints.ts | 4 ++ .../api/endpoints/admin/delete-user-avatar.ts | 48 +++++++++++++++++++ .../api/endpoints/admin/delete-user-banner.ts | 48 +++++++++++++++++++ packages/frontend/src/pages/admin-user.vue | 42 ++++++++++++++++ packages/misskey-js/etc/misskey-js.api.md | 12 +++++ packages/misskey-js/src/api.types.ts | 2 + 10 files changed, 176 insertions(+) create mode 100644 packages/backend/src/server/api/endpoints/admin/delete-user-avatar.ts create mode 100644 packages/backend/src/server/api/endpoints/admin/delete-user-banner.ts diff --git a/locales/en-US.yml b/locales/en-US.yml index 09fd726c9f..2aba028e45 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -564,6 +564,10 @@ output: "Output" script: "Script" disablePagesScript: "Disable AiScript on Pages" updateRemoteUser: "Update remote user information" +deleteUserAvatar: "Delete user icon" +deleteUserAvatarConfirm: "Are you sure that you want to delete this user's icon?" +deleteUserBanner: "Delete user banner" +deleteUserBannerConfirm: "Are you sure that you want to delete this user's banner?" deleteAllFiles: "Delete all files" deleteAllFilesConfirm: "Are you sure that you want to delete all files?" removeAllFollowing: "Unfollow all followed users" diff --git a/locales/index.d.ts b/locales/index.d.ts index 6baed91c42..6fd6d3641a 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -567,6 +567,10 @@ export interface Locale { "script": string; "disablePagesScript": string; "updateRemoteUser": string; + "deleteUserAvatar": string; + "deleteUserAvatarConfirm": string; + "deleteUserBanner": string; + "deleteUserBannerConfirm": string; "deleteAllFiles": string; "deleteAllFilesConfirm": string; "removeAllFollowing": string; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index e59a550df5..9685e9c5a5 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -564,6 +564,10 @@ output: "出力" script: "スクリプト" disablePagesScript: "Pagesのスクリプトを無効にする" updateRemoteUser: "リモートユーザー情報の更新" +deleteUserAvatar: "アイコンを削除" +deleteUserAvatarConfirm: "アイコンを削除しますか?" +deleteUserBanner: "バナーを削除" +deleteUserBannerConfirm: "バナーを削除しますか?" deleteAllFiles: "すべてのファイルを削除" deleteAllFilesConfirm: "すべてのファイルを削除しますか?" removeAllFollowing: "フォローを全解除" diff --git a/packages/backend/src/server/api/EndpointsModule.ts b/packages/backend/src/server/api/EndpointsModule.ts index 6d813ae04e..3797b46d04 100644 --- a/packages/backend/src/server/api/EndpointsModule.ts +++ b/packages/backend/src/server/api/EndpointsModule.ts @@ -24,6 +24,8 @@ import * as ep___admin_avatarDecorations_delete from './endpoints/admin/avatar-d import * as ep___admin_avatarDecorations_list from './endpoints/admin/avatar-decorations/list.js'; import * as ep___admin_avatarDecorations_update from './endpoints/admin/avatar-decorations/update.js'; import * as ep___admin_deleteAllFilesOfAUser from './endpoints/admin/delete-all-files-of-a-user.js'; +import * as ep___admin_deleteUserAvatar from './endpoints/admin/delete-user-avatar.js'; +import * as ep___admin_deleteUserBanner from './endpoints/admin/delete-user-banner.js'; import * as ep___admin_drive_cleanRemoteFiles from './endpoints/admin/drive/clean-remote-files.js'; import * as ep___admin_drive_cleanup from './endpoints/admin/drive/cleanup.js'; import * as ep___admin_drive_files from './endpoints/admin/drive/files.js'; @@ -383,6 +385,8 @@ const $admin_avatarDecorations_delete: Provider = { provide: 'ep:admin/avatar-de const $admin_avatarDecorations_list: Provider = { provide: 'ep:admin/avatar-decorations/list', useClass: ep___admin_avatarDecorations_list.default }; const $admin_avatarDecorations_update: Provider = { provide: 'ep:admin/avatar-decorations/update', useClass: ep___admin_avatarDecorations_update.default }; const $admin_deleteAllFilesOfAUser: Provider = { provide: 'ep:admin/delete-all-files-of-a-user', useClass: ep___admin_deleteAllFilesOfAUser.default }; +const $admin_deleteUserAvatar: Provider = { provide: 'ep:admin/delete-user-avatar', useClass: ep___admin_deleteUserAvatar.default }; +const $admin_deleteUserBanner: Provider = { provide: 'ep:admin/delete-user-banner', useClass: ep___admin_deleteUserBanner.default }; const $admin_drive_cleanRemoteFiles: Provider = { provide: 'ep:admin/drive/clean-remote-files', useClass: ep___admin_drive_cleanRemoteFiles.default }; const $admin_drive_cleanup: Provider = { provide: 'ep:admin/drive/cleanup', useClass: ep___admin_drive_cleanup.default }; const $admin_drive_files: Provider = { provide: 'ep:admin/drive/files', useClass: ep___admin_drive_files.default }; @@ -746,6 +750,8 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention $admin_avatarDecorations_list, $admin_avatarDecorations_update, $admin_deleteAllFilesOfAUser, + $admin_deleteUserAvatar, + $admin_deleteUserBanner, $admin_drive_cleanRemoteFiles, $admin_drive_cleanup, $admin_drive_files, @@ -1103,6 +1109,8 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention $admin_avatarDecorations_list, $admin_avatarDecorations_update, $admin_deleteAllFilesOfAUser, + $admin_deleteUserAvatar, + $admin_deleteUserBanner, $admin_drive_cleanRemoteFiles, $admin_drive_cleanup, $admin_drive_files, diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts index ef4bd3e2b5..4162ace337 100644 --- a/packages/backend/src/server/api/endpoints.ts +++ b/packages/backend/src/server/api/endpoints.ts @@ -24,6 +24,8 @@ import * as ep___admin_avatarDecorations_delete from './endpoints/admin/avatar-d import * as ep___admin_avatarDecorations_list from './endpoints/admin/avatar-decorations/list.js'; import * as ep___admin_avatarDecorations_update from './endpoints/admin/avatar-decorations/update.js'; import * as ep___admin_deleteAllFilesOfAUser from './endpoints/admin/delete-all-files-of-a-user.js'; +import * as ep___admin_deleteUserAvatar from './endpoints/admin/delete-user-avatar.js'; +import * as ep___admin_deleteUserBanner from './endpoints/admin/delete-user-banner.js'; import * as ep___admin_drive_cleanRemoteFiles from './endpoints/admin/drive/clean-remote-files.js'; import * as ep___admin_drive_cleanup from './endpoints/admin/drive/cleanup.js'; import * as ep___admin_drive_files from './endpoints/admin/drive/files.js'; @@ -381,6 +383,8 @@ const eps = [ ['admin/avatar-decorations/list', ep___admin_avatarDecorations_list], ['admin/avatar-decorations/update', ep___admin_avatarDecorations_update], ['admin/delete-all-files-of-a-user', ep___admin_deleteAllFilesOfAUser], + ['admin/delete-user-avatar', ep___admin_deleteUserAvatar], + ['admin/delete-user-banner', ep___admin_deleteUserBanner], ['admin/drive/clean-remote-files', ep___admin_drive_cleanRemoteFiles], ['admin/drive/cleanup', ep___admin_drive_cleanup], ['admin/drive/files', ep___admin_drive_files], diff --git a/packages/backend/src/server/api/endpoints/admin/delete-user-avatar.ts b/packages/backend/src/server/api/endpoints/admin/delete-user-avatar.ts new file mode 100644 index 0000000000..d3c78d7fb6 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/admin/delete-user-avatar.ts @@ -0,0 +1,48 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Inject, Injectable } from '@nestjs/common'; +import type { UsersRepository } from '@/models/_.js'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { DI } from '@/di-symbols.js'; + +export const meta = { + tags: ['admin'], + + requireCredential: true, + requireModerator: true, +} as const; + +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + }, + required: ['userId'], +} as const; + +// eslint-disable-next-line import/no-default-export +@Injectable() +export default class extends Endpoint { + constructor( + @Inject(DI.usersRepository) + private usersRepository: UsersRepository, + ) { + super(meta, paramDef, async (ps, me) => { + const user = await this.usersRepository.findOneBy({ id: ps.userId }); + + if (user == null) { + throw new Error('user not found'); + } + + await this.usersRepository.update(user.id, { + avatar: null, + avatarId: null, + avatarUrl: null, + avatarBlurhash: null, + }); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/admin/delete-user-banner.ts b/packages/backend/src/server/api/endpoints/admin/delete-user-banner.ts new file mode 100644 index 0000000000..e076cdcfc1 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/admin/delete-user-banner.ts @@ -0,0 +1,48 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Inject, Injectable } from '@nestjs/common'; +import type { UsersRepository } from '@/models/_.js'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { DI } from '@/di-symbols.js'; + +export const meta = { + tags: ['admin'], + + requireCredential: true, + requireModerator: true, +} as const; + +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + }, + required: ['userId'], +} as const; + +// eslint-disable-next-line import/no-default-export +@Injectable() +export default class extends Endpoint { + constructor( + @Inject(DI.usersRepository) + private usersRepository: UsersRepository, + ) { + super(meta, paramDef, async (ps, me) => { + const user = await this.usersRepository.findOneBy({ id: ps.userId }); + + if (user == null) { + throw new Error('user not found'); + } + + await this.usersRepository.update(user.id, { + banner: null, + bannerId: null, + bannerUrl: null, + bannerBlurhash: null, + }); + }); + } +} diff --git a/packages/frontend/src/pages/admin-user.vue b/packages/frontend/src/pages/admin-user.vue index 5d671acf31..9f4975e888 100644 --- a/packages/frontend/src/pages/admin-user.vue +++ b/packages/frontend/src/pages/admin-user.vue @@ -122,6 +122,10 @@ SPDX-License-Identifier: AGPL-3.0-only +
+ {{ i18n.ts.deleteUserAvatar }} + {{ i18n.ts.deleteUserBanner }} +
{{ i18n.ts.deleteAccount }} @@ -320,6 +324,44 @@ async function toggleSuspend(v) { } } +async function deleteUserAvatar() { + const confirm = await os.confirm({ + type: 'warning', + text: i18n.ts.deleteUserAvatarConfirm, + }); + if (confirm.canceled) return; + const process = async () => { + await os.api('admin/delete-user-avatar', { userId: user.id }); + os.success(); + }; + await process().catch(err => { + os.alert({ + type: 'error', + text: err.toString(), + }); + }); + refreshUser(); +} + +async function deleteUserBanner() { + const confirm = await os.confirm({ + type: 'warning', + text: i18n.ts.deleteUserBannerConfirm, + }); + if (confirm.canceled) return; + const process = async () => { + await os.api('admin/delete-user-banner', { userId: user.id }); + os.success(); + }; + await process().catch(err => { + os.alert({ + type: 'error', + text: err.toString(), + }); + }); + refreshUser(); +} + async function deleteAllFiles() { const confirm = await os.confirm({ type: 'warning', diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index 87922ba791..f4bcaa8066 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -345,6 +345,18 @@ export type Endpoints = { }; res: null; }; + 'admin/delete-user-avatar': { + req: { + userId: User['id']; + }; + res: null; + }; + 'admin/delete-user-banner': { + req: { + userId: User['id']; + }; + res: null; + }; 'admin/delete-logs': { req: NoParams; res: null; diff --git a/packages/misskey-js/src/api.types.ts b/packages/misskey-js/src/api.types.ts index 54b175fcf1..e3f28c644e 100644 --- a/packages/misskey-js/src/api.types.ts +++ b/packages/misskey-js/src/api.types.ts @@ -15,6 +15,8 @@ export type Endpoints = { // admin 'admin/abuse-user-reports': { req: TODO; res: TODO; }; 'admin/delete-all-files-of-a-user': { req: { userId: User['id']; }; res: null; }; + 'admin/delete-user-avatar': { req: { userId: User['id']; }; res: null; }; + 'admin/delete-user-banner': { req: { userId: User['id']; }; res: null; }; 'admin/delete-logs': { req: NoParams; res: null; }; 'admin/get-index-stats': { req: TODO; res: TODO; }; 'admin/get-table-stats': { req: TODO; res: TODO; }; From 2f7d10bf2359823f5c37f8971bab287e7918a246 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 18 Nov 2023 21:08:32 +0900 Subject: [PATCH 5/9] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b08d12093..e2c226aec0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ ### General - Feat: メールアドレスの認証にverifymail.ioを使えるように (cherry-pick from https://github.com/TeamNijimiss/misskey/commit/971ba07a44550f68d2ba31c62066db2d43a0caed) +- Feat: モデレーターがユーザーのアイコンもしくはバナー画像を未設定状態にできる機能を追加 (cherry-pick from https://github.com/TeamNijimiss/misskey/commit/e0eb5a752f6e5616d6312bb7c9790302f9dbff83) ### Client - From b65fd349812fe3c89b5face6ec5c12823459d7df Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 19 Nov 2023 10:18:57 +0900 Subject: [PATCH 6/9] tweak of 2b6f789a5b --- locales/en-US.yml | 8 ++++---- locales/index.d.ts | 10 ++++++---- locales/ja-JP.yml | 10 ++++++---- .../backend/src/server/api/EndpointsModule.ts | 16 ++++++++-------- packages/backend/src/server/api/endpoints.ts | 8 ++++---- ...elete-user-avatar.ts => unset-user-avatar.ts} | 12 ++++++++++++ ...elete-user-banner.ts => unset-user-banner.ts} | 12 ++++++++++++ packages/backend/src/types.ts | 14 ++++++++++++++ packages/frontend/src/pages/admin-user.vue | 16 ++++++++-------- packages/misskey-js/etc/misskey-js.api.md | 4 ++-- packages/misskey-js/src/api.types.ts | 4 ++-- packages/misskey-js/src/consts.ts | 14 ++++++++++++++ packages/misskey-js/src/entities.ts | 6 ++++++ 13 files changed, 98 insertions(+), 36 deletions(-) rename packages/backend/src/server/api/endpoints/admin/{delete-user-avatar.ts => unset-user-avatar.ts} (77%) rename packages/backend/src/server/api/endpoints/admin/{delete-user-banner.ts => unset-user-banner.ts} (77%) diff --git a/locales/en-US.yml b/locales/en-US.yml index 2aba028e45..b14592b20a 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -564,10 +564,10 @@ output: "Output" script: "Script" disablePagesScript: "Disable AiScript on Pages" updateRemoteUser: "Update remote user information" -deleteUserAvatar: "Delete user icon" -deleteUserAvatarConfirm: "Are you sure that you want to delete this user's icon?" -deleteUserBanner: "Delete user banner" -deleteUserBannerConfirm: "Are you sure that you want to delete this user's banner?" +unsetUserAvatar: "Delete user icon" +unsetUserAvatarConfirm: "Are you sure that you want to delete this user's icon?" +unsetUserBanner: "Delete user banner" +unsetUserBannerConfirm: "Are you sure that you want to delete this user's banner?" deleteAllFiles: "Delete all files" deleteAllFilesConfirm: "Are you sure that you want to delete all files?" removeAllFollowing: "Unfollow all followed users" diff --git a/locales/index.d.ts b/locales/index.d.ts index 6fd6d3641a..39fbb57799 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -567,10 +567,10 @@ export interface Locale { "script": string; "disablePagesScript": string; "updateRemoteUser": string; - "deleteUserAvatar": string; - "deleteUserAvatarConfirm": string; - "deleteUserBanner": string; - "deleteUserBannerConfirm": string; + "unsetUserAvatar": string; + "unsetUserAvatarConfirm": string; + "unsetUserBanner": string; + "unsetUserBannerConfirm": string; "deleteAllFiles": string; "deleteAllFilesConfirm": string; "removeAllFollowing": string; @@ -2417,6 +2417,8 @@ export interface Locale { "createAvatarDecoration": string; "updateAvatarDecoration": string; "deleteAvatarDecoration": string; + "unsetUserAvatar": string; + "unsetUserBanner": string; }; "_fileViewer": { "title": string; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 9685e9c5a5..3757715c0f 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -564,10 +564,10 @@ output: "出力" script: "スクリプト" disablePagesScript: "Pagesのスクリプトを無効にする" updateRemoteUser: "リモートユーザー情報の更新" -deleteUserAvatar: "アイコンを削除" -deleteUserAvatarConfirm: "アイコンを削除しますか?" -deleteUserBanner: "バナーを削除" -deleteUserBannerConfirm: "バナーを削除しますか?" +unsetUserAvatar: "アイコンを解除" +unsetUserAvatarConfirm: "アイコンを解除しますか?" +unsetUserBanner: "バナーを解除" +unsetUserBannerConfirm: "バナーを解除しますか?" deleteAllFiles: "すべてのファイルを削除" deleteAllFilesConfirm: "すべてのファイルを削除しますか?" removeAllFollowing: "フォローを全解除" @@ -2318,6 +2318,8 @@ _moderationLogTypes: createAvatarDecoration: "アイコンデコレーションを作成" updateAvatarDecoration: "アイコンデコレーションを更新" deleteAvatarDecoration: "アイコンデコレーションを削除" + unsetUserAvatar: "ユーザーのアイコンを解除" + unsetUserBanner: "ユーザーのバナーを解除" _fileViewer: title: "ファイルの詳細" diff --git a/packages/backend/src/server/api/EndpointsModule.ts b/packages/backend/src/server/api/EndpointsModule.ts index 3797b46d04..86a64d7121 100644 --- a/packages/backend/src/server/api/EndpointsModule.ts +++ b/packages/backend/src/server/api/EndpointsModule.ts @@ -24,8 +24,8 @@ import * as ep___admin_avatarDecorations_delete from './endpoints/admin/avatar-d import * as ep___admin_avatarDecorations_list from './endpoints/admin/avatar-decorations/list.js'; import * as ep___admin_avatarDecorations_update from './endpoints/admin/avatar-decorations/update.js'; import * as ep___admin_deleteAllFilesOfAUser from './endpoints/admin/delete-all-files-of-a-user.js'; -import * as ep___admin_deleteUserAvatar from './endpoints/admin/delete-user-avatar.js'; -import * as ep___admin_deleteUserBanner from './endpoints/admin/delete-user-banner.js'; +import * as ep___admin_unsetUserAvatar from './endpoints/admin/unset-user-avatar.js'; +import * as ep___admin_unsetUserBanner from './endpoints/admin/unset-user-banner.js'; import * as ep___admin_drive_cleanRemoteFiles from './endpoints/admin/drive/clean-remote-files.js'; import * as ep___admin_drive_cleanup from './endpoints/admin/drive/cleanup.js'; import * as ep___admin_drive_files from './endpoints/admin/drive/files.js'; @@ -385,8 +385,8 @@ const $admin_avatarDecorations_delete: Provider = { provide: 'ep:admin/avatar-de const $admin_avatarDecorations_list: Provider = { provide: 'ep:admin/avatar-decorations/list', useClass: ep___admin_avatarDecorations_list.default }; const $admin_avatarDecorations_update: Provider = { provide: 'ep:admin/avatar-decorations/update', useClass: ep___admin_avatarDecorations_update.default }; const $admin_deleteAllFilesOfAUser: Provider = { provide: 'ep:admin/delete-all-files-of-a-user', useClass: ep___admin_deleteAllFilesOfAUser.default }; -const $admin_deleteUserAvatar: Provider = { provide: 'ep:admin/delete-user-avatar', useClass: ep___admin_deleteUserAvatar.default }; -const $admin_deleteUserBanner: Provider = { provide: 'ep:admin/delete-user-banner', useClass: ep___admin_deleteUserBanner.default }; +const $admin_unsetUserAvatar: Provider = { provide: 'ep:admin/unset-user-avatar', useClass: ep___admin_unsetUserAvatar.default }; +const $admin_unsetUserBanner: Provider = { provide: 'ep:admin/unset-user-banner', useClass: ep___admin_unsetUserBanner.default }; const $admin_drive_cleanRemoteFiles: Provider = { provide: 'ep:admin/drive/clean-remote-files', useClass: ep___admin_drive_cleanRemoteFiles.default }; const $admin_drive_cleanup: Provider = { provide: 'ep:admin/drive/cleanup', useClass: ep___admin_drive_cleanup.default }; const $admin_drive_files: Provider = { provide: 'ep:admin/drive/files', useClass: ep___admin_drive_files.default }; @@ -750,8 +750,8 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention $admin_avatarDecorations_list, $admin_avatarDecorations_update, $admin_deleteAllFilesOfAUser, - $admin_deleteUserAvatar, - $admin_deleteUserBanner, + $admin_unsetUserAvatar, + $admin_unsetUserBanner, $admin_drive_cleanRemoteFiles, $admin_drive_cleanup, $admin_drive_files, @@ -1109,8 +1109,8 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention $admin_avatarDecorations_list, $admin_avatarDecorations_update, $admin_deleteAllFilesOfAUser, - $admin_deleteUserAvatar, - $admin_deleteUserBanner, + $admin_unsetUserAvatar, + $admin_unsetUserBanner, $admin_drive_cleanRemoteFiles, $admin_drive_cleanup, $admin_drive_files, diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts index 4162ace337..e458d720ab 100644 --- a/packages/backend/src/server/api/endpoints.ts +++ b/packages/backend/src/server/api/endpoints.ts @@ -24,8 +24,8 @@ import * as ep___admin_avatarDecorations_delete from './endpoints/admin/avatar-d import * as ep___admin_avatarDecorations_list from './endpoints/admin/avatar-decorations/list.js'; import * as ep___admin_avatarDecorations_update from './endpoints/admin/avatar-decorations/update.js'; import * as ep___admin_deleteAllFilesOfAUser from './endpoints/admin/delete-all-files-of-a-user.js'; -import * as ep___admin_deleteUserAvatar from './endpoints/admin/delete-user-avatar.js'; -import * as ep___admin_deleteUserBanner from './endpoints/admin/delete-user-banner.js'; +import * as ep___admin_unsetUserAvatar from './endpoints/admin/unset-user-avatar.js'; +import * as ep___admin_unsetUserBanner from './endpoints/admin/unset-user-banner.js'; import * as ep___admin_drive_cleanRemoteFiles from './endpoints/admin/drive/clean-remote-files.js'; import * as ep___admin_drive_cleanup from './endpoints/admin/drive/cleanup.js'; import * as ep___admin_drive_files from './endpoints/admin/drive/files.js'; @@ -383,8 +383,8 @@ const eps = [ ['admin/avatar-decorations/list', ep___admin_avatarDecorations_list], ['admin/avatar-decorations/update', ep___admin_avatarDecorations_update], ['admin/delete-all-files-of-a-user', ep___admin_deleteAllFilesOfAUser], - ['admin/delete-user-avatar', ep___admin_deleteUserAvatar], - ['admin/delete-user-banner', ep___admin_deleteUserBanner], + ['admin/unset-user-avatar', ep___admin_unsetUserAvatar], + ['admin/unset-user-banner', ep___admin_unsetUserBanner], ['admin/drive/clean-remote-files', ep___admin_drive_cleanRemoteFiles], ['admin/drive/cleanup', ep___admin_drive_cleanup], ['admin/drive/files', ep___admin_drive_files], diff --git a/packages/backend/src/server/api/endpoints/admin/delete-user-avatar.ts b/packages/backend/src/server/api/endpoints/admin/unset-user-avatar.ts similarity index 77% rename from packages/backend/src/server/api/endpoints/admin/delete-user-avatar.ts rename to packages/backend/src/server/api/endpoints/admin/unset-user-avatar.ts index d3c78d7fb6..ac10f1b6fd 100644 --- a/packages/backend/src/server/api/endpoints/admin/delete-user-avatar.ts +++ b/packages/backend/src/server/api/endpoints/admin/unset-user-avatar.ts @@ -7,6 +7,7 @@ import { Inject, Injectable } from '@nestjs/common'; import type { UsersRepository } from '@/models/_.js'; import { Endpoint } from '@/server/api/endpoint-base.js'; import { DI } from '@/di-symbols.js'; +import { ModerationLogService } from '@/core/ModerationLogService.js'; export const meta = { tags: ['admin'], @@ -29,6 +30,8 @@ export default class extends Endpoint { constructor( @Inject(DI.usersRepository) private usersRepository: UsersRepository, + + private moderationLogService: ModerationLogService, ) { super(meta, paramDef, async (ps, me) => { const user = await this.usersRepository.findOneBy({ id: ps.userId }); @@ -36,6 +39,8 @@ export default class extends Endpoint { if (user == null) { throw new Error('user not found'); } + + if (user.avatarId == null) return; await this.usersRepository.update(user.id, { avatar: null, @@ -43,6 +48,13 @@ export default class extends Endpoint { avatarUrl: null, avatarBlurhash: null, }); + + this.moderationLogService.log(me, 'unsetUserAvatar', { + userId: user.id, + userUsername: user.username, + userHost: user.host, + fileId: user.avatarId, + }); }); } } diff --git a/packages/backend/src/server/api/endpoints/admin/delete-user-banner.ts b/packages/backend/src/server/api/endpoints/admin/unset-user-banner.ts similarity index 77% rename from packages/backend/src/server/api/endpoints/admin/delete-user-banner.ts rename to packages/backend/src/server/api/endpoints/admin/unset-user-banner.ts index e076cdcfc1..66acd367df 100644 --- a/packages/backend/src/server/api/endpoints/admin/delete-user-banner.ts +++ b/packages/backend/src/server/api/endpoints/admin/unset-user-banner.ts @@ -7,6 +7,7 @@ import { Inject, Injectable } from '@nestjs/common'; import type { UsersRepository } from '@/models/_.js'; import { Endpoint } from '@/server/api/endpoint-base.js'; import { DI } from '@/di-symbols.js'; +import { ModerationLogService } from '@/core/ModerationLogService.js'; export const meta = { tags: ['admin'], @@ -29,6 +30,8 @@ export default class extends Endpoint { constructor( @Inject(DI.usersRepository) private usersRepository: UsersRepository, + + private moderationLogService: ModerationLogService, ) { super(meta, paramDef, async (ps, me) => { const user = await this.usersRepository.findOneBy({ id: ps.userId }); @@ -37,12 +40,21 @@ export default class extends Endpoint { throw new Error('user not found'); } + if (user.bannerId == null) return; + await this.usersRepository.update(user.id, { banner: null, bannerId: null, bannerUrl: null, bannerBlurhash: null, }); + + this.moderationLogService.log(me, 'unsetUserBanner', { + userId: user.id, + userUsername: user.username, + userHost: user.host, + fileId: user.bannerId, + }); }); } } diff --git a/packages/backend/src/types.ts b/packages/backend/src/types.ts index e6dfeb6f8c..1fb3d6a6ce 100644 --- a/packages/backend/src/types.ts +++ b/packages/backend/src/types.ts @@ -63,6 +63,8 @@ export const moderationLogTypes = [ 'createAvatarDecoration', 'updateAvatarDecoration', 'deleteAvatarDecoration', + 'unsetUserAvatar', + 'unsetUserBanner', ] as const; export type ModerationLogPayloads = { @@ -237,6 +239,18 @@ export type ModerationLogPayloads = { avatarDecorationId: string; avatarDecoration: any; }; + unsetUserAvatar: { + userId: string; + userUsername: string; + userHost: string | null; + fileId: string; + }; + unsetUserBanner: { + userId: string; + userUsername: string; + userHost: string | null; + fileId: string; + }; }; export type Serialized = { diff --git a/packages/frontend/src/pages/admin-user.vue b/packages/frontend/src/pages/admin-user.vue index 9f4975e888..87ebedc296 100644 --- a/packages/frontend/src/pages/admin-user.vue +++ b/packages/frontend/src/pages/admin-user.vue @@ -123,8 +123,8 @@ SPDX-License-Identifier: AGPL-3.0-only
- {{ i18n.ts.deleteUserAvatar }} - {{ i18n.ts.deleteUserBanner }} + {{ i18n.ts.unsetUserAvatar }} + {{ i18n.ts.unsetUserBanner }}
{{ i18n.ts.deleteAccount }} @@ -324,14 +324,14 @@ async function toggleSuspend(v) { } } -async function deleteUserAvatar() { +async function unsetUserAvatar() { const confirm = await os.confirm({ type: 'warning', - text: i18n.ts.deleteUserAvatarConfirm, + text: i18n.ts.unsetUserAvatarConfirm, }); if (confirm.canceled) return; const process = async () => { - await os.api('admin/delete-user-avatar', { userId: user.id }); + await os.api('admin/unset-user-avatar', { userId: user.id }); os.success(); }; await process().catch(err => { @@ -343,14 +343,14 @@ async function deleteUserAvatar() { refreshUser(); } -async function deleteUserBanner() { +async function unsetUserBanner() { const confirm = await os.confirm({ type: 'warning', - text: i18n.ts.deleteUserBannerConfirm, + text: i18n.ts.unsetUserBannerConfirm, }); if (confirm.canceled) return; const process = async () => { - await os.api('admin/delete-user-banner', { userId: user.id }); + await os.api('admin/unset-user-banner', { userId: user.id }); os.success(); }; await process().catch(err => { diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index f4bcaa8066..85907de665 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -345,13 +345,13 @@ export type Endpoints = { }; res: null; }; - 'admin/delete-user-avatar': { + 'admin/unset-user-avatar': { req: { userId: User['id']; }; res: null; }; - 'admin/delete-user-banner': { + 'admin/unset-user-banner': { req: { userId: User['id']; }; diff --git a/packages/misskey-js/src/api.types.ts b/packages/misskey-js/src/api.types.ts index e3f28c644e..1a75b7cf57 100644 --- a/packages/misskey-js/src/api.types.ts +++ b/packages/misskey-js/src/api.types.ts @@ -15,8 +15,8 @@ export type Endpoints = { // admin 'admin/abuse-user-reports': { req: TODO; res: TODO; }; 'admin/delete-all-files-of-a-user': { req: { userId: User['id']; }; res: null; }; - 'admin/delete-user-avatar': { req: { userId: User['id']; }; res: null; }; - 'admin/delete-user-banner': { req: { userId: User['id']; }; res: null; }; + 'admin/unset-user-avatar': { req: { userId: User['id']; }; res: null; }; + 'admin/unset-user-banner': { req: { userId: User['id']; }; res: null; }; 'admin/delete-logs': { req: NoParams; res: null; }; 'admin/get-index-stats': { req: TODO; res: TODO; }; 'admin/get-table-stats': { req: TODO; res: TODO; }; diff --git a/packages/misskey-js/src/consts.ts b/packages/misskey-js/src/consts.ts index 48a36a31d6..a8f0b96d5d 100644 --- a/packages/misskey-js/src/consts.ts +++ b/packages/misskey-js/src/consts.ts @@ -81,6 +81,8 @@ export const moderationLogTypes = [ 'createAvatarDecoration', 'updateAvatarDecoration', 'deleteAvatarDecoration', + 'unsetUserAvatar', + 'unsetUserBanner', ] as const; export type ModerationLogPayloads = { @@ -255,4 +257,16 @@ export type ModerationLogPayloads = { avatarDecorationId: string; avatarDecoration: any; }; + unsetUserAvatar: { + userId: string; + userUsername: string; + userHost: string | null; + fileId: string; + }; + unsetUserBanner: { + userId: string; + userUsername: string; + userHost: string | null; + fileId: string; + }; }; diff --git a/packages/misskey-js/src/entities.ts b/packages/misskey-js/src/entities.ts index a0d0b7528d..a51315b13b 100644 --- a/packages/misskey-js/src/entities.ts +++ b/packages/misskey-js/src/entities.ts @@ -727,4 +727,10 @@ export type ModerationLog = { } | { type: 'resolveAbuseReport'; info: ModerationLogPayloads['resolveAbuseReport']; +} | { + type: 'unsetUserAvatar'; + info: ModerationLogPayloads['unsetUserAvatar']; +} | { + type: 'unsetUserBanner'; + info: ModerationLogPayloads['unsetUserBanner']; }); From cbebe85ccfab582f9cdf6f3680673e80d708439c Mon Sep 17 00:00:00 2001 From: Lynx Kotoura Date: Sun, 19 Nov 2023 11:43:04 +0900 Subject: [PATCH 7/9] =?UTF-8?q?=E3=83=9A=E3=83=BC=E3=82=B8=E4=B8=80?= =?UTF-8?q?=E8=A6=A7=E3=83=9A=E3=83=BC=E3=82=B8=E3=81=AE=E8=A1=A8=E7=A4=BA?= =?UTF-8?q?=E3=81=8C=E3=83=A2=E3=83=90=E3=82=A4=E3=83=AB=E7=92=B0=E5=A2=83?= =?UTF-8?q?=E3=81=AB=E3=81=8A=E3=81=84=E3=81=A6=E5=B4=A9=E3=82=8C=E3=81=A6?= =?UTF-8?q?=E3=81=84=E3=82=8B=E3=81=AE=E3=82=92=E4=BF=AE=E6=AD=A3=20(#1235?= =?UTF-8?q?4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix style of list of pages on mobile * overflow clip に変えた --- CHANGELOG.md | 2 +- packages/frontend/src/components/MkPagePreview.vue | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2c226aec0..d96af455f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ - ### Client -- +- Fix: ページ一覧ページの表示がモバイル環境において崩れているのを修正 ### Server - diff --git a/packages/frontend/src/components/MkPagePreview.vue b/packages/frontend/src/components/MkPagePreview.vue index 05b577c49c..6c8a0e56a6 100644 --- a/packages/frontend/src/components/MkPagePreview.vue +++ b/packages/frontend/src/components/MkPagePreview.vue @@ -114,7 +114,6 @@ const props = defineProps<{ & + article { left: 0; - width: 100%; } } } @@ -124,6 +123,7 @@ const props = defineProps<{ > .thumbnail { height: 80px; + overflow: clip; } > article { From 02b0adf31facbe7eb6d5905e9670ee541e2585e6 Mon Sep 17 00:00:00 2001 From: yukineko <27853966+hideki0403@users.noreply.github.com> Date: Sun, 19 Nov 2023 11:45:24 +0900 Subject: [PATCH 8/9] =?UTF-8?q?fix:=20=E3=80=8C=E8=A8=AD=E5=AE=9A=E3=81=AE?= =?UTF-8?q?=E3=83=90=E3=83=83=E3=82=AF=E3=82=A2=E3=83=83=E3=83=97=E3=80=8D?= =?UTF-8?q?=E3=81=AB=E4=B8=80=E9=83=A8=E3=81=AE=E8=A8=AD=E5=AE=9A=E9=A0=85?= =?UTF-8?q?=E7=9B=AE=E3=81=8C=E5=90=AB=E3=81=BE=E3=82=8C=E3=81=A6=E3=81=84?= =?UTF-8?q?=E3=81=AA=E3=81=84=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=20(#12366)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 一部の設定項目がバックアップに含まれていなかったのを修正 * update: CHANGELOG.md * remove: バックアップ不要な項目を削除 --- CHANGELOG.md | 2 +- .../pages/settings/preferences-backups.vue | 25 +++++++++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d96af455f1..0bdbb2aade 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ - Feat: モデレーターがユーザーのアイコンもしくはバナー画像を未設定状態にできる機能を追加 (cherry-pick from https://github.com/TeamNijimiss/misskey/commit/e0eb5a752f6e5616d6312bb7c9790302f9dbff83) ### Client -- +- fix: 「設定のバックアップ」で一部の項目がバックアップに含まれていなかった問題を修正 ### Server - diff --git a/packages/frontend/src/pages/settings/preferences-backups.vue b/packages/frontend/src/pages/settings/preferences-backups.vue index 3b3a6bd07d..35435238fc 100644 --- a/packages/frontend/src/pages/settings/preferences-backups.vue +++ b/packages/frontend/src/pages/settings/preferences-backups.vue @@ -54,22 +54,24 @@ import { miLocalStorage } from '@/local-storage.js'; const { t, ts } = i18n; const defaultStoreSaveKeys: (keyof typeof defaultStore['state'])[] = [ + 'collapseRenotes', 'menu', 'visibility', 'localOnly', 'statusbars', 'widgets', 'tl', + 'pinnedUserLists', 'overridedDeviceKind', 'serverDisconnectedBehavior', - 'collapseRenotes', - 'showNoteActionsOnlyHover', 'nsfw', + 'highlightSensitiveMedia', 'animation', 'animatedMfm', 'advancedMfm', 'loadRawImages', 'imageNewTab', + 'enableDataSaverMode', 'disableShowingAnimatedImages', 'emojiStyle', 'disableDrawer', @@ -89,9 +91,28 @@ const defaultStoreSaveKeys: (keyof typeof defaultStore['state'])[] = [ 'menuDisplay', 'reportError', 'squareAvatars', + 'showAvatarDecorations', 'numberOfPageCache', + 'showNoteActionsOnlyHover', + 'showClipButtonInNoteFooter', + 'reactionsDisplaySize', + 'forceShowAds', 'aiChanMode', + 'devMode', 'mediaListWithOneImageAppearance', + 'notificationPosition', + 'notificationStackAxis', + 'enableCondensedLineForAcct', + 'keepScreenOn', + 'defaultWithReplies', + 'disableStreamingTimeline', + 'useGroupedNotifications', + 'sound_masterVolume', + 'sound_note', + 'sound_noteMy', + 'sound_notification', + 'sound_antenna', + 'sound_channel', ]; const coldDeviceStorageSaveKeys: (keyof typeof ColdDeviceStorage.default)[] = [ 'lightTheme', From e0de86359c9df510e02a2fa25643030d0517afdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9E=9C=E7=89=A9=E3=83=AA=E3=83=B3?= Date: Sun, 19 Nov 2023 13:39:25 +0900 Subject: [PATCH 9/9] =?UTF-8?q?backend=E3=81=AE=E3=83=97=E3=83=AD=E3=82=B8?= =?UTF-8?q?=E3=82=A7=E3=82=AF=E3=83=88=E3=81=A7=E5=8D=98=E4=BD=93=E3=81=A7?= =?UTF-8?q?=20start=20=E3=81=A7=E3=81=8D=E3=81=AA=E3=81=84=E3=81=AE?= =?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3=20(#12371)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/backend/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/backend/package.json b/packages/backend/package.json index a4856709c3..496c79c9c0 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -7,8 +7,8 @@ "node": ">=18.16.0" }, "scripts": { - "start": "node ./built/index.js", - "start:test": "NODE_ENV=test node ./built/index.js", + "start": "node ./built/boot/entry.js", + "start:test": "NODE_ENV=test node ./built/boot/entry.js", "migrate": "pnpm typeorm migration:run -d ormconfig.js", "revert": "pnpm typeorm migration:revert -d ormconfig.js", "check:connect": "node ./check_connect.js",