From 76ccae8a2f7ce4ded27509249ef4b99199944fde Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 17 Nov 2023 18:17:32 +0900 Subject: [PATCH 001/435] chore(frontend): tweak rt style for safari --- packages/frontend/src/style.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/frontend/src/style.scss b/packages/frontend/src/style.scss index 7bb443cece..978707140c 100644 --- a/packages/frontend/src/style.scss +++ b/packages/frontend/src/style.scss @@ -132,6 +132,10 @@ hr { background: var(--divider); } +rt { + text-align: center; +} + .ti { width: 1.28em; vertical-align: -12%; From f007890e845361d8b9ceccae0e5318ec1a01fc42 Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 17 Nov 2023 18:31:09 +0900 Subject: [PATCH 002/435] Revert "chore(frontend): tweak rt style for safari" This reverts commit 76ccae8a2f7ce4ded27509249ef4b99199944fde. --- packages/frontend/src/style.scss | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/frontend/src/style.scss b/packages/frontend/src/style.scss index 978707140c..7bb443cece 100644 --- a/packages/frontend/src/style.scss +++ b/packages/frontend/src/style.scss @@ -132,10 +132,6 @@ hr { background: var(--divider); } -rt { - text-align: center; -} - .ti { width: 1.28em; vertical-align: -12%; From 83ea0395f6a884b2de43b3e5bb93d1ceb107df64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?= <46447427+samunohito@users.noreply.github.com> Date: Fri, 17 Nov 2023 22:26:54 +0900 Subject: [PATCH 003/435] =?UTF-8?q?DeepL=20Translation=E3=81=AEPro=20accou?= =?UTF-8?q?nt=E3=83=88=E3=82=B0=E3=83=AB=E3=82=B9=E3=82=A4=E3=83=83?= =?UTF-8?q?=E3=83=81=E3=81=8C=E8=A1=A8=E7=A4=BA=E3=81=95=E3=82=8C=E3=81=A6?= =?UTF-8?q?=E3=81=84=E3=81=AA=E3=81=8B=E3=81=A3=E3=81=9F=E3=81=AE=E3=82=92?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=20(#12355)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: osamu <46447427+sam-osamu@users.noreply.github.com> --- packages/frontend/src/pages/admin/external-services.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/frontend/src/pages/admin/external-services.vue b/packages/frontend/src/pages/admin/external-services.vue index e88860166c..e614bfeb1b 100644 --- a/packages/frontend/src/pages/admin/external-services.vue +++ b/packages/frontend/src/pages/admin/external-services.vue @@ -38,6 +38,7 @@ import { } from 'vue'; import XHeader from './_header_.vue'; import MkInput from '@/components/MkInput.vue'; import MkButton from '@/components/MkButton.vue'; +import MkSwitch from '@/components/MkSwitch.vue'; import FormSuspense from '@/components/form/suspense.vue'; import FormSection from '@/components/form/section.vue'; import * as os from '@/os.js'; From 0a73973a7c6e6e95a5206bfc5388ff7f7a9ba8ed Mon Sep 17 00:00:00 2001 From: Nafu Satsuki Date: Sat, 18 Nov 2023 20:39:48 +0900 Subject: [PATCH 004/435] =?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 005/435] 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 006/435] 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 007/435] =?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 008/435] 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 009/435] 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 010/435] =?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 011/435] =?UTF-8?q?fix:=20=E3=80=8C=E8=A8=AD=E5=AE=9A?= =?UTF-8?q?=E3=81=AE=E3=83=90=E3=83=83=E3=82=AF=E3=82=A2=E3=83=83=E3=83=97?= =?UTF-8?q?=E3=80=8D=E3=81=AB=E4=B8=80=E9=83=A8=E3=81=AE=E8=A8=AD=E5=AE=9A?= =?UTF-8?q?=E9=A0=85=E7=9B=AE=E3=81=8C=E5=90=AB=E3=81=BE=E3=82=8C=E3=81=A6?= =?UTF-8?q?=E3=81=84=E3=81=AA=E3=81=84=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3=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 012/435] =?UTF-8?q?backend=E3=81=AE=E3=83=97=E3=83=AD?= =?UTF-8?q?=E3=82=B8=E3=82=A7=E3=82=AF=E3=83=88=E3=81=A7=E5=8D=98=E4=BD=93?= =?UTF-8?q?=E3=81=A7=20start=20=E3=81=A7=E3=81=8D=E3=81=AA=E3=81=84?= =?UTF-8?q?=E3=81=AE=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", From ed0cc443ea8122d01488f427bcced457d3d65d4f Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 21 Nov 2023 09:55:49 +0900 Subject: [PATCH 013/435] =?UTF-8?q?fix(backend):=20=E3=83=AD=E3=83=BC?= =?UTF-8?q?=E3=83=AB=E3=82=BF=E3=82=A4=E3=83=A0=E3=83=A9=E3=82=A4=E3=83=B3?= =?UTF-8?q?=E3=81=8C=E4=BF=9D=E5=AD=98=E3=81=95=E3=82=8C=E3=81=AA=E3=81=84?= =?UTF-8?q?=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 2 +- packages/backend/src/core/RoleService.ts | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2c226aec0..aff2ed283e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,7 @@ - ### Server -- +- Fix: ロールタイムラインが保存されない問題を修正 ## 2023.11.1 diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts index d6a414694a..432887b3b7 100644 --- a/packages/backend/src/core/RoleService.ts +++ b/packages/backend/src/core/RoleService.ts @@ -87,6 +87,9 @@ export class RoleService implements OnApplicationShutdown { @Inject(DI.redis) private redisClient: Redis.Redis, + @Inject(DI.redisForTimelines) + private redisForTimelines: Redis.Redis, + @Inject(DI.redisForSub) private redisForSub: Redis.Redis, @@ -476,7 +479,7 @@ export class RoleService implements OnApplicationShutdown { public async addNoteToRoleTimeline(note: Packed<'Note'>): Promise { const roles = await this.getUserRoles(note.userId); - const redisPipeline = this.redisClient.pipeline(); + const redisPipeline = this.redisForTimelines.pipeline(); for (const role of roles) { this.funoutTimelineService.push(`roleTimeline:${role.id}`, note.id, 1000, redisPipeline); From 2ec3227012eecb4358feed6d16bf2b700b3ac9c7 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Tue, 21 Nov 2023 10:48:01 +0900 Subject: [PATCH 014/435] update api.md (#12379) for API changes in b65fd349812fe3c89b5face6ec5c12823459d7df --- packages/misskey-js/etc/misskey-js.api.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index 85907de665..63c3cb71a5 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -2685,10 +2685,16 @@ type ModerationLog = { } | { type: 'resolveAbuseReport'; info: ModerationLogPayloads['resolveAbuseReport']; +} | { + type: 'unsetUserAvatar'; + info: ModerationLogPayloads['unsetUserAvatar']; +} | { + type: 'unsetUserBanner'; + info: ModerationLogPayloads['unsetUserBanner']; }); // @public (undocumented) -export const moderationLogTypes: readonly ["updateServerSettings", "suspend", "unsuspend", "updateUserNote", "addCustomEmoji", "updateCustomEmoji", "deleteCustomEmoji", "assignRole", "unassignRole", "createRole", "updateRole", "deleteRole", "clearQueue", "promoteQueue", "deleteDriveFile", "deleteNote", "createGlobalAnnouncement", "createUserAnnouncement", "updateGlobalAnnouncement", "updateUserAnnouncement", "deleteGlobalAnnouncement", "deleteUserAnnouncement", "resetPassword", "suspendRemoteInstance", "unsuspendRemoteInstance", "markSensitiveDriveFile", "unmarkSensitiveDriveFile", "resolveAbuseReport", "createInvitation", "createAd", "updateAd", "deleteAd", "createAvatarDecoration", "updateAvatarDecoration", "deleteAvatarDecoration"]; +export const moderationLogTypes: readonly ["updateServerSettings", "suspend", "unsuspend", "updateUserNote", "addCustomEmoji", "updateCustomEmoji", "deleteCustomEmoji", "assignRole", "unassignRole", "createRole", "updateRole", "deleteRole", "clearQueue", "promoteQueue", "deleteDriveFile", "deleteNote", "createGlobalAnnouncement", "createUserAnnouncement", "updateGlobalAnnouncement", "updateUserAnnouncement", "deleteGlobalAnnouncement", "deleteUserAnnouncement", "resetPassword", "suspendRemoteInstance", "unsuspendRemoteInstance", "markSensitiveDriveFile", "unmarkSensitiveDriveFile", "resolveAbuseReport", "createInvitation", "createAd", "updateAd", "deleteAd", "createAvatarDecoration", "updateAvatarDecoration", "deleteAvatarDecoration", "unsetUserAvatar", "unsetUserBanner"]; // @public (undocumented) export const mutedNoteReasons: readonly ["word", "manual", "spam", "other"]; @@ -3046,8 +3052,8 @@ type UserSorting = '+follower' | '-follower' | '+createdAt' | '-createdAt' | '+u // Warnings were encountered during analysis: // // src/api.types.ts:16:32 - (ae-forgotten-export) The symbol "TODO" needs to be exported by the entry point index.d.ts -// src/api.types.ts:18:25 - (ae-forgotten-export) The symbol "NoParams" needs to be exported by the entry point index.d.ts -// src/api.types.ts:632:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts +// src/api.types.ts:20:25 - (ae-forgotten-export) The symbol "NoParams" needs to be exported by the entry point index.d.ts +// src/api.types.ts:634:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts // src/entities.ts:116:2 - (ae-forgotten-export) The symbol "notificationTypes_2" needs to be exported by the entry point index.d.ts // src/entities.ts:627:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts // src/streaming.types.ts:33:4 - (ae-forgotten-export) The symbol "FIXME" needs to be exported by the entry point index.d.ts From 8bd9077f77eaebaa4dff403e072ba49e4cab1326 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?= <46447427+samunohito@users.noreply.github.com> Date: Tue, 21 Nov 2023 11:13:56 +0900 Subject: [PATCH 015/435] =?UTF-8?q?json-schema=E9=85=8D=E4=B8=8B=E3=81=AE?= =?UTF-8?q?=E6=9C=80=E6=96=B0=E5=8C=96=20(#12312)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * user.ts、page.ts、drive-folder.tsを各EntityServiceの戻り値をもとに最新化 * 再確認 * fix error * note以外の残りのファイルを対応 * fix CHANGELOG.md * fix CHANGELOG.md * fix user.ts * fix user.ts * コメント対応 * fix note.ts --------- Co-authored-by: osamu <46447427+sam-osamu@users.noreply.github.com> --- CHANGELOG.md | 1 + .../entities/NotificationEntityService.ts | 14 +- .../src/models/json-schema/announcement.ts | 8 +- .../backend/src/models/json-schema/channel.ts | 63 ++-- .../backend/src/models/json-schema/clip.ts | 8 +- .../src/models/json-schema/drive-file.ts | 2 +- .../src/models/json-schema/drive-folder.ts | 12 +- .../models/json-schema/federation-instance.ts | 9 +- .../backend/src/models/json-schema/flash.ts | 20 +- .../src/models/json-schema/following.ts | 10 +- .../src/models/json-schema/gallery-post.ts | 24 +- .../backend/src/models/json-schema/note.ts | 28 +- .../src/models/json-schema/notification.ts | 26 +- .../backend/src/models/json-schema/page.ts | 68 +++- .../backend/src/models/json-schema/user.ts | 313 ++++++++++++++++-- 15 files changed, 457 insertions(+), 149 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc38356284..2efa1b230d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ - Feat: 管理者がコントロールパネルからメールアドレスの照会を行えるようになりました - Enhance: ローカリゼーションの更新 - Enhance: 依存関係の更新 +- Enhance: json-schema(OpenAPIの戻り値として使用されるスキーマ定義)を出来る限り最新化 #12311 ### Client - Enhance: MFMでルビを振れるように diff --git a/packages/backend/src/core/entities/NotificationEntityService.ts b/packages/backend/src/core/entities/NotificationEntityService.ts index f74594ff0c..e723ea5a55 100644 --- a/packages/backend/src/core/entities/NotificationEntityService.ts +++ b/packages/backend/src/core/entities/NotificationEntityService.ts @@ -198,12 +198,14 @@ export class NotificationEntityService implements OnModuleInit { }); } else if (notification.type === 'renote:grouped') { const users = await Promise.all(notification.userIds.map(userId => { - const user = hint?.packedUsers != null - ? hint.packedUsers.get(userId) - : this.userEntityService.pack(userId!, { id: meId }, { - detail: false, - }); - return user; + const packedUser = hint?.packedUsers != null ? hint.packedUsers.get(userId) : null; + if (packedUser) { + return packedUser; + } + + return this.userEntityService.pack(userId, { id: meId }, { + detail: false, + }); })); return await awaitAll({ id: notification.id, diff --git a/packages/backend/src/models/json-schema/announcement.ts b/packages/backend/src/models/json-schema/announcement.ts index c7e24c7f29..78a98872b2 100644 --- a/packages/backend/src/models/json-schema/announcement.ts +++ b/packages/backend/src/models/json-schema/announcement.ts @@ -42,11 +42,15 @@ export const packedAnnouncementSchema = { type: 'string', optional: false, nullable: false, }, - forYou: { + needConfirmationToRead: { type: 'boolean', optional: false, nullable: false, }, - needConfirmationToRead: { + silence: { + type: 'boolean', + optional: false, nullable: false, + }, + forYou: { type: 'boolean', optional: false, nullable: false, }, diff --git a/packages/backend/src/models/json-schema/channel.ts b/packages/backend/src/models/json-schema/channel.ts index 8f9770cdc5..5b0fa0f15d 100644 --- a/packages/backend/src/models/json-schema/channel.ts +++ b/packages/backend/src/models/json-schema/channel.ts @@ -19,7 +19,7 @@ export const packedChannelSchema = { }, lastNotedAt: { type: 'string', - optional: false, nullable: true, + nullable: true, optional: false, format: 'date-time', }, name: { @@ -28,38 +28,18 @@ export const packedChannelSchema = { }, description: { type: 'string', - nullable: true, optional: false, - }, - bannerUrl: { - type: 'string', - format: 'url', - nullable: true, optional: false, - }, - isArchived: { - type: 'boolean', - optional: false, nullable: false, - }, - notesCount: { - type: 'number', - nullable: false, optional: false, - }, - usersCount: { - type: 'number', - nullable: false, optional: false, - }, - isFollowing: { - type: 'boolean', - optional: true, nullable: false, - }, - isFavorited: { - type: 'boolean', - optional: true, nullable: false, + optional: false, nullable: true, }, userId: { type: 'string', nullable: true, optional: false, format: 'id', }, + bannerUrl: { + type: 'string', + format: 'url', + nullable: true, optional: false, + }, pinnedNoteIds: { type: 'array', nullable: false, optional: false, @@ -72,6 +52,18 @@ export const packedChannelSchema = { type: 'string', optional: false, nullable: false, }, + isArchived: { + type: 'boolean', + optional: false, nullable: false, + }, + usersCount: { + type: 'number', + nullable: false, optional: false, + }, + notesCount: { + type: 'number', + nullable: false, optional: false, + }, isSensitive: { type: 'boolean', optional: false, nullable: false, @@ -80,5 +72,22 @@ export const packedChannelSchema = { type: 'boolean', optional: false, nullable: false, }, + isFollowing: { + type: 'boolean', + optional: true, nullable: false, + }, + isFavorited: { + type: 'boolean', + optional: true, nullable: false, + }, + pinnedNotes: { + type: 'array', + optional: true, nullable: false, + items: { + type: 'object', + optional: false, nullable: false, + ref: 'Note', + }, + }, }, } as const; diff --git a/packages/backend/src/models/json-schema/clip.ts b/packages/backend/src/models/json-schema/clip.ts index 64f7a2ad9c..1ab96c2b3b 100644 --- a/packages/backend/src/models/json-schema/clip.ts +++ b/packages/backend/src/models/json-schema/clip.ts @@ -44,13 +44,13 @@ export const packedClipSchema = { type: 'boolean', optional: false, nullable: false, }, - isFavorited: { - type: 'boolean', - optional: true, nullable: false, - }, favoritedCount: { type: 'number', optional: false, nullable: false, }, + isFavorited: { + type: 'boolean', + optional: true, nullable: false, + }, }, } as const; diff --git a/packages/backend/src/models/json-schema/drive-file.ts b/packages/backend/src/models/json-schema/drive-file.ts index 87f1340812..79f242a711 100644 --- a/packages/backend/src/models/json-schema/drive-file.ts +++ b/packages/backend/src/models/json-schema/drive-file.ts @@ -74,7 +74,7 @@ export const packedDriveFileSchema = { }, url: { type: 'string', - optional: false, nullable: true, + optional: false, nullable: false, format: 'url', }, thumbnailUrl: { diff --git a/packages/backend/src/models/json-schema/drive-folder.ts b/packages/backend/src/models/json-schema/drive-folder.ts index 51107d423f..aaad301303 100644 --- a/packages/backend/src/models/json-schema/drive-folder.ts +++ b/packages/backend/src/models/json-schema/drive-folder.ts @@ -21,6 +21,12 @@ export const packedDriveFolderSchema = { type: 'string', optional: false, nullable: false, }, + parentId: { + type: 'string', + optional: false, nullable: true, + format: 'id', + example: 'xxxxxxxxxx', + }, foldersCount: { type: 'number', optional: true, nullable: false, @@ -29,12 +35,6 @@ export const packedDriveFolderSchema = { type: 'number', optional: true, nullable: false, }, - parentId: { - type: 'string', - optional: false, nullable: true, - format: 'id', - example: 'xxxxxxxxxx', - }, parent: { type: 'object', optional: true, nullable: true, diff --git a/packages/backend/src/models/json-schema/federation-instance.ts b/packages/backend/src/models/json-schema/federation-instance.ts index 442e1076f2..3417314272 100644 --- a/packages/backend/src/models/json-schema/federation-instance.ts +++ b/packages/backend/src/models/json-schema/federation-instance.ts @@ -79,6 +79,10 @@ export const packedFederationInstanceSchema = { type: 'string', optional: false, nullable: true, }, + isSilenced: { + type: 'boolean', + optional: false, nullable: false, + }, iconUrl: { type: 'string', optional: false, nullable: true, @@ -93,11 +97,6 @@ export const packedFederationInstanceSchema = { type: 'string', optional: false, nullable: true, }, - isSilenced: { - type: "boolean", - optional: false, - nullable: false, - }, infoUpdatedAt: { type: 'string', optional: false, nullable: true, diff --git a/packages/backend/src/models/json-schema/flash.ts b/packages/backend/src/models/json-schema/flash.ts index 9453ba1dce..f08fa7a279 100644 --- a/packages/backend/src/models/json-schema/flash.ts +++ b/packages/backend/src/models/json-schema/flash.ts @@ -22,6 +22,16 @@ export const packedFlashSchema = { optional: false, nullable: false, format: 'date-time', }, + userId: { + type: 'string', + optional: false, nullable: false, + format: 'id', + }, + user: { + type: 'object', + ref: 'UserLite', + optional: false, nullable: false, + }, title: { type: 'string', optional: false, nullable: false, @@ -34,16 +44,6 @@ export const packedFlashSchema = { type: 'string', optional: false, nullable: false, }, - userId: { - type: 'string', - optional: false, nullable: false, - format: 'id', - }, - user: { - type: 'object', - ref: 'UserLite', - optional: false, nullable: false, - }, likedCount: { type: 'number', optional: false, nullable: true, diff --git a/packages/backend/src/models/json-schema/following.ts b/packages/backend/src/models/json-schema/following.ts index 3a24ebb619..e92cff20a1 100644 --- a/packages/backend/src/models/json-schema/following.ts +++ b/packages/backend/src/models/json-schema/following.ts @@ -22,16 +22,16 @@ export const packedFollowingSchema = { optional: false, nullable: false, format: 'id', }, - followee: { - type: 'object', - optional: true, nullable: false, - ref: 'UserDetailed', - }, followerId: { type: 'string', optional: false, nullable: false, format: 'id', }, + followee: { + type: 'object', + optional: true, nullable: false, + ref: 'UserDetailed', + }, follower: { type: 'object', optional: true, nullable: false, diff --git a/packages/backend/src/models/json-schema/gallery-post.ts b/packages/backend/src/models/json-schema/gallery-post.ts index cf260c0bf5..df7038950c 100644 --- a/packages/backend/src/models/json-schema/gallery-post.ts +++ b/packages/backend/src/models/json-schema/gallery-post.ts @@ -22,14 +22,6 @@ export const packedGalleryPostSchema = { optional: false, nullable: false, format: 'date-time', }, - title: { - type: 'string', - optional: false, nullable: false, - }, - description: { - type: 'string', - optional: false, nullable: true, - }, userId: { type: 'string', optional: false, nullable: false, @@ -40,6 +32,14 @@ export const packedGalleryPostSchema = { ref: 'UserLite', optional: false, nullable: false, }, + title: { + type: 'string', + optional: false, nullable: false, + }, + description: { + type: 'string', + optional: false, nullable: true, + }, fileIds: { type: 'array', optional: true, nullable: false, @@ -70,5 +70,13 @@ export const packedGalleryPostSchema = { type: 'boolean', optional: false, nullable: false, }, + likedCount: { + type: 'number', + optional: false, nullable: false, + }, + isLiked: { + type: 'boolean', + optional: true, nullable: false, + }, }, } as const; diff --git a/packages/backend/src/models/json-schema/note.ts b/packages/backend/src/models/json-schema/note.ts index 38c0054b55..9d5d558f51 100644 --- a/packages/backend/src/models/json-schema/note.ts +++ b/packages/backend/src/models/json-schema/note.ts @@ -127,22 +127,18 @@ export const packedNoteSchema = { channel: { type: 'object', optional: true, nullable: true, - items: { - type: 'object', - optional: false, nullable: false, - properties: { - id: { - type: 'string', - optional: false, nullable: false, - }, - name: { - type: 'string', - optional: false, nullable: true, - }, - isSensitive: { - type: 'boolean', - optional: true, nullable: false, - }, + properties: { + id: { + type: 'string', + optional: false, nullable: false, + }, + name: { + type: 'string', + optional: false, nullable: true, + }, + isSensitive: { + type: 'boolean', + optional: true, nullable: false, }, }, }, diff --git a/packages/backend/src/models/json-schema/notification.ts b/packages/backend/src/models/json-schema/notification.ts index 27db3bb62c..c6d6e84317 100644 --- a/packages/backend/src/models/json-schema/notification.ts +++ b/packages/backend/src/models/json-schema/notification.ts @@ -42,13 +42,9 @@ export const packedNotificationSchema = { type: 'string', optional: true, nullable: true, }, - choice: { - type: 'number', - optional: true, nullable: true, - }, - invitation: { - type: 'object', - optional: true, nullable: true, + achievement: { + type: 'string', + optional: true, nullable: false, }, body: { type: 'string', @@ -81,14 +77,14 @@ export const packedNotificationSchema = { required: ['user', 'reaction'], }, }, - }, - users: { - type: 'array', - optional: true, nullable: true, - items: { - type: 'object', - ref: 'UserLite', - optional: false, nullable: false, + users: { + type: 'array', + optional: true, nullable: true, + items: { + type: 'object', + ref: 'UserLite', + optional: false, nullable: false, + }, }, }, } as const; diff --git a/packages/backend/src/models/json-schema/page.ts b/packages/backend/src/models/json-schema/page.ts index 3f20a4b802..9baacd6884 100644 --- a/packages/backend/src/models/json-schema/page.ts +++ b/packages/backend/src/models/json-schema/page.ts @@ -22,6 +22,32 @@ export const packedPageSchema = { optional: false, nullable: false, format: 'date-time', }, + userId: { + type: 'string', + optional: false, nullable: false, + format: 'id', + }, + user: { + type: 'object', + ref: 'UserLite', + optional: false, nullable: false, + }, + content: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'object', + optional: false, nullable: false, + }, + }, + variables: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'object', + optional: false, nullable: false, + }, + }, title: { type: 'string', optional: false, nullable: false, @@ -34,23 +60,47 @@ export const packedPageSchema = { type: 'string', optional: false, nullable: true, }, - content: { - type: 'array', + hideTitleWhenPinned: { + type: 'boolean', optional: false, nullable: false, }, - variables: { - type: 'array', + alignCenter: { + type: 'boolean', optional: false, nullable: false, }, - userId: { + font: { type: 'string', optional: false, nullable: false, - format: 'id', }, - user: { - type: 'object', - ref: 'UserLite', + script: { + type: 'string', optional: false, nullable: false, }, + eyeCatchingImageId: { + type: 'string', + optional: false, nullable: true, + }, + eyeCatchingImage: { + type: 'object', + optional: false, nullable: true, + ref: 'DriveFile', + }, + attachedFiles: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'object', + optional: false, nullable: false, + ref: 'DriveFile', + }, + }, + likedCount: { + type: 'number', + optional: false, nullable: false, + }, + isLiked: { + type: 'boolean', + optional: true, nullable: false, + }, }, } as const; diff --git a/packages/backend/src/models/json-schema/user.ts b/packages/backend/src/models/json-schema/user.ts index 37bdcbe281..b0e18db01a 100644 --- a/packages/backend/src/models/json-schema/user.ts +++ b/packages/backend/src/models/json-schema/user.ts @@ -49,11 +49,6 @@ export const packedUserLiteSchema = { nullable: false, optional: false, format: 'id', }, - url: { - type: 'string', - format: 'url', - nullable: false, optional: false, - }, angle: { type: 'number', nullable: false, optional: true, @@ -62,19 +57,14 @@ export const packedUserLiteSchema = { type: 'boolean', nullable: false, optional: true, }, + url: { + type: 'string', + format: 'url', + nullable: false, optional: false, + }, }, }, }, - isAdmin: { - type: 'boolean', - nullable: false, optional: true, - default: false, - }, - isModerator: { - type: 'boolean', - nullable: false, optional: true, - default: false, - }, isBot: { type: 'boolean', nullable: false, optional: true, @@ -83,12 +73,67 @@ export const packedUserLiteSchema = { type: 'boolean', nullable: false, optional: true, }, + instance: { + type: 'object', + nullable: false, optional: true, + properties: { + name: { + type: 'string', + nullable: true, optional: false, + }, + softwareName: { + type: 'string', + nullable: true, optional: false, + }, + softwareVersion: { + type: 'string', + nullable: true, optional: false, + }, + iconUrl: { + type: 'string', + nullable: true, optional: false, + }, + faviconUrl: { + type: 'string', + nullable: true, optional: false, + }, + themeColor: { + type: 'string', + nullable: true, optional: false, + }, + }, + }, + emojis: { + type: 'object', + nullable: false, optional: false, + }, onlineStatus: { type: 'string', - format: 'url', - nullable: true, optional: false, + nullable: false, optional: false, enum: ['unknown', 'online', 'active', 'offline'], }, + badgeRoles: { + type: 'array', + nullable: false, optional: true, + items: { + type: 'object', + nullable: false, optional: false, + properties: { + name: { + type: 'string', + nullable: false, optional: false, + }, + iconUrl: { + type: 'string', + nullable: true, optional: false, + }, + displayOrder: { + type: 'number', + nullable: false, optional: false, + }, + }, + }, + }, }, } as const; @@ -105,21 +150,18 @@ export const packedUserDetailedNotMeOnlySchema = { format: 'uri', nullable: true, optional: false, }, - movedToUri: { + movedTo: { type: 'string', format: 'uri', - nullable: true, - optional: false, + nullable: true, optional: false, }, alsoKnownAs: { type: 'array', - nullable: true, - optional: false, + nullable: true, optional: false, items: { type: 'string', format: 'id', - nullable: false, - optional: false, + nullable: false, optional: false, }, }, createdAt: { @@ -249,6 +291,11 @@ export const packedUserDetailedNotMeOnlySchema = { type: 'boolean', nullable: false, optional: false, }, + ffVisibility: { + type: 'string', + nullable: false, optional: false, + enum: ['public', 'followers', 'private'], + }, twoFactorEnabled: { type: 'boolean', nullable: false, optional: false, @@ -264,6 +311,57 @@ export const packedUserDetailedNotMeOnlySchema = { nullable: false, optional: false, default: false, }, + roles: { + type: 'array', + nullable: false, optional: false, + items: { + type: 'object', + nullable: false, optional: false, + properties: { + id: { + type: 'string', + nullable: false, optional: false, + format: 'id', + }, + name: { + type: 'string', + nullable: false, optional: false, + }, + color: { + type: 'string', + nullable: true, optional: false, + }, + iconUrl: { + type: 'string', + nullable: true, optional: false, + }, + description: { + type: 'string', + nullable: false, optional: false, + }, + isModerator: { + type: 'boolean', + nullable: false, optional: false, + }, + isAdministrator: { + type: 'boolean', + nullable: false, optional: false, + }, + displayOrder: { + type: 'number', + nullable: false, optional: false, + }, + }, + }, + }, + memo: { + type: 'string', + nullable: true, optional: false, + }, + moderationNote: { + type: 'string', + nullable: false, optional: true, + }, //#region relations isFollowing: { type: 'boolean', @@ -297,10 +395,6 @@ export const packedUserDetailedNotMeOnlySchema = { type: 'boolean', nullable: false, optional: true, }, - memo: { - type: 'string', - nullable: false, optional: true, - }, notify: { type: 'string', nullable: false, optional: true, @@ -326,29 +420,37 @@ export const packedMeDetailedOnlySchema = { nullable: true, optional: false, format: 'id', }, - injectFeaturedNote: { + isModerator: { type: 'boolean', nullable: true, optional: false, }, + isAdmin: { + type: 'boolean', + nullable: true, optional: false, + }, + injectFeaturedNote: { + type: 'boolean', + nullable: false, optional: false, + }, receiveAnnouncementEmail: { type: 'boolean', - nullable: true, optional: false, + nullable: false, optional: false, }, alwaysMarkNsfw: { type: 'boolean', - nullable: true, optional: false, + nullable: false, optional: false, }, autoSensitive: { type: 'boolean', - nullable: true, optional: false, + nullable: false, optional: false, }, carefulBot: { type: 'boolean', - nullable: true, optional: false, + nullable: false, optional: false, }, autoAcceptFollowed: { type: 'boolean', - nullable: true, optional: false, + nullable: false, optional: false, }, noCrawle: { type: 'boolean', @@ -387,10 +489,23 @@ export const packedMeDetailedOnlySchema = { type: 'boolean', nullable: false, optional: false, }, + unreadAnnouncements: { + type: 'array', + nullable: false, optional: false, + items: { + type: 'object', + nullable: false, optional: false, + ref: 'Announcement', + }, + }, hasUnreadAntenna: { type: 'boolean', nullable: false, optional: false, }, + hasUnreadChannel: { + type: 'boolean', + nullable: false, optional: false, + }, hasUnreadNotification: { type: 'boolean', nullable: false, optional: false, @@ -429,12 +544,132 @@ export const packedMeDetailedOnlySchema = { }, emailNotificationTypes: { type: 'array', - nullable: true, optional: false, + nullable: false, optional: false, items: { type: 'string', nullable: false, optional: false, }, }, + achievements: { + type: 'array', + nullable: false, optional: false, + items: { + type: 'object', + nullable: false, optional: false, + properties: { + name: { + type: 'string', + nullable: false, optional: false, + }, + unlockedAt: { + type: 'number', + nullable: false, optional: false, + }, + }, + }, + }, + loggedInDays: { + type: 'number', + nullable: false, optional: false, + }, + policies: { + type: 'object', + nullable: false, optional: false, + properties: { + gtlAvailable: { + type: 'boolean', + nullable: false, optional: false, + }, + ltlAvailable: { + type: 'boolean', + nullable: false, optional: false, + }, + canPublicNote: { + type: 'boolean', + nullable: false, optional: false, + }, + canInvite: { + type: 'boolean', + nullable: false, optional: false, + }, + inviteLimit: { + type: 'number', + nullable: false, optional: false, + }, + inviteLimitCycle: { + type: 'number', + nullable: false, optional: false, + }, + inviteExpirationTime: { + type: 'number', + nullable: false, optional: false, + }, + canManageCustomEmojis: { + type: 'boolean', + nullable: false, optional: false, + }, + canManageAvatarDecorations: { + type: 'boolean', + nullable: false, optional: false, + }, + canSearchNotes: { + type: 'boolean', + nullable: false, optional: false, + }, + canUseTranslator: { + type: 'boolean', + nullable: false, optional: false, + }, + canHideAds: { + type: 'boolean', + nullable: false, optional: false, + }, + driveCapacityMb: { + type: 'number', + nullable: false, optional: false, + }, + alwaysMarkNsfw: { + type: 'boolean', + nullable: false, optional: false, + }, + pinLimit: { + type: 'number', + nullable: false, optional: false, + }, + antennaLimit: { + type: 'number', + nullable: false, optional: false, + }, + wordMuteLimit: { + type: 'number', + nullable: false, optional: false, + }, + webhookLimit: { + type: 'number', + nullable: false, optional: false, + }, + clipLimit: { + type: 'number', + nullable: false, optional: false, + }, + noteEachClipsLimit: { + type: 'number', + nullable: false, optional: false, + }, + userListLimit: { + type: 'number', + nullable: false, optional: false, + }, + userEachUserListsLimit: { + type: 'number', + nullable: false, optional: false, + }, + rateLimitFactor: { + type: 'number', + nullable: false, optional: false, + }, + }, + }, //#region secrets email: { type: 'string', @@ -511,5 +746,13 @@ export const packedUserSchema = { type: 'object', ref: 'UserDetailed', }, + { + type: 'object', + ref: 'UserDetailedNotMe', + }, + { + type: 'object', + ref: 'MeDetailed', + }, ], } as const; From 77ac51a680c352d5bed90a90379fcaf1454612a7 Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 21 Nov 2023 11:32:13 +0900 Subject: [PATCH 016/435] update typescript to 5.3 --- package.json | 2 +- packages/backend/package.json | 2 +- packages/frontend/package.json | 2 +- packages/misskey-js/package.json | 2 +- packages/sw/package.json | 2 +- pnpm-lock.yaml | 172 +++++++++++++++---------------- 6 files changed, 91 insertions(+), 91 deletions(-) diff --git a/package.json b/package.json index d0fc867b3c..f51861401e 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "js-yaml": "4.1.0", "postcss": "8.4.31", "terser": "5.24.0", - "typescript": "5.2.2" + "typescript": "5.3.2" }, "devDependencies": { "@typescript-eslint/eslint-plugin": "6.11.0", diff --git a/packages/backend/package.json b/packages/backend/package.json index 496c79c9c0..3b029a49d2 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -165,7 +165,7 @@ "tsconfig-paths": "4.2.0", "twemoji-parser": "14.0.0", "typeorm": "0.3.17", - "typescript": "5.2.2", + "typescript": "5.3.2", "ulid": "2.3.0", "vary": "1.1.2", "web-push": "3.6.6", diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 62192d0dab..c7736f7ac7 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -69,7 +69,7 @@ "tsc-alias": "1.8.8", "tsconfig-paths": "4.2.0", "twemoji-parser": "14.0.0", - "typescript": "5.2.2", + "typescript": "5.3.2", "uuid": "9.0.1", "v-code-diff": "1.7.2", "vanilla-tilt": "1.8.1", diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json index 0a4855874f..69ce173bf4 100644 --- a/packages/misskey-js/package.json +++ b/packages/misskey-js/package.json @@ -32,7 +32,7 @@ "jest-websocket-mock": "2.5.0", "mock-socket": "9.3.1", "tsd": "0.29.0", - "typescript": "5.2.2" + "typescript": "5.3.2" }, "files": [ "built" diff --git a/packages/sw/package.json b/packages/sw/package.json index 3259cae879..3c74ee8c78 100644 --- a/packages/sw/package.json +++ b/packages/sw/package.json @@ -18,7 +18,7 @@ "@typescript/lib-webworker": "npm:@types/serviceworker@0.0.67", "eslint": "8.53.0", "eslint-plugin-import": "2.29.0", - "typescript": "5.2.2" + "typescript": "5.3.2" }, "type": "module" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 904150b075..7373d5f10b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -28,8 +28,8 @@ importers: specifier: 5.24.0 version: 5.24.0 typescript: - specifier: 5.2.2 - version: 5.2.2 + specifier: 5.3.2 + version: 5.3.2 optionalDependencies: '@tensorflow/tfjs-core': specifier: 4.4.0 @@ -37,10 +37,10 @@ importers: devDependencies: '@typescript-eslint/eslint-plugin': specifier: 6.11.0 - version: 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.2.2) + version: 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.3.2) '@typescript-eslint/parser': specifier: 6.11.0 - version: 6.11.0(eslint@8.53.0)(typescript@5.2.2) + version: 6.11.0(eslint@8.53.0)(typescript@5.3.2) cross-env: specifier: 7.0.3 version: 7.0.3 @@ -381,8 +381,8 @@ importers: specifier: 0.3.17 version: 0.3.17(ioredis@5.3.2)(pg@8.11.3) typescript: - specifier: 5.2.2 - version: 5.2.2 + specifier: 5.3.2 + version: 5.3.2 ulid: specifier: 2.3.0 version: 2.3.0 @@ -615,10 +615,10 @@ importers: version: 8.5.9 '@typescript-eslint/eslint-plugin': specifier: 6.11.0 - version: 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.2.2) + version: 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.3.2) '@typescript-eslint/parser': specifier: 6.11.0 - version: 6.11.0(eslint@8.53.0)(typescript@5.2.2) + version: 6.11.0(eslint@8.53.0)(typescript@5.3.2) aws-sdk-client-mock: specifier: 3.0.0 version: 3.0.0 @@ -806,8 +806,8 @@ importers: specifier: 14.0.0 version: 14.0.0 typescript: - specifier: 5.2.2 - version: 5.2.2 + specifier: 5.3.2 + version: 5.3.2 uuid: specifier: 9.0.1 version: 9.0.1 @@ -822,7 +822,7 @@ importers: version: 4.5.0(@types/node@20.9.1)(sass@1.69.5)(terser@5.24.0) vue: specifier: 3.3.8 - version: 3.3.8(typescript@5.2.2) + version: 3.3.8(typescript@5.3.2) vuedraggable: specifier: next version: 4.1.0(vue@3.3.8) @@ -862,10 +862,10 @@ importers: version: 7.5.3 '@storybook/react': specifier: 7.5.3 - version: 7.5.3(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2) + version: 7.5.3(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.2) '@storybook/react-vite': specifier: 7.5.3 - version: 7.5.3(react-dom@18.2.0)(react@18.2.0)(rollup@4.4.1)(typescript@5.2.2)(vite@4.5.0) + version: 7.5.3(react-dom@18.2.0)(react@18.2.0)(rollup@4.4.1)(typescript@5.3.2)(vite@4.5.0) '@storybook/testing-library': specifier: 0.2.2 version: 0.2.2 @@ -880,7 +880,7 @@ importers: version: 7.5.3(@vue/compiler-core@3.3.8)(vue@3.3.8) '@storybook/vue3-vite': specifier: 7.5.3 - version: 7.5.3(@vue/compiler-core@3.3.8)(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2)(vite@4.5.0)(vue@3.3.8) + version: 7.5.3(@vue/compiler-core@3.3.8)(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.2)(vite@4.5.0)(vue@3.3.8) '@testing-library/vue': specifier: 8.0.0 version: 8.0.0(@vue/compiler-sfc@3.3.8)(vue@3.3.8) @@ -922,10 +922,10 @@ importers: version: 8.5.9 '@typescript-eslint/eslint-plugin': specifier: 6.11.0 - version: 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.2.2) + version: 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.3.2) '@typescript-eslint/parser': specifier: 6.11.0 - version: 6.11.0(eslint@8.53.0)(typescript@5.2.2) + version: 6.11.0(eslint@8.53.0)(typescript@5.3.2) '@vitest/coverage-v8': specifier: 0.34.6 version: 0.34.6(vitest@0.34.6) @@ -961,7 +961,7 @@ importers: version: 4.0.5 msw: specifier: 1.3.2 - version: 1.3.2(typescript@5.2.2) + version: 1.3.2(typescript@5.3.2) msw-storybook-addon: specifier: 1.10.0 version: 1.10.0(msw@1.3.2) @@ -1003,7 +1003,7 @@ importers: version: 9.3.2(eslint@8.53.0) vue-tsc: specifier: 1.8.22 - version: 1.8.22(typescript@5.2.2) + version: 1.8.22(typescript@5.3.2) packages/misskey-js: dependencies: @@ -1034,10 +1034,10 @@ importers: version: 20.9.1 '@typescript-eslint/eslint-plugin': specifier: 6.11.0 - version: 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.2.2) + version: 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.3.2) '@typescript-eslint/parser': specifier: 6.11.0 - version: 6.11.0(eslint@8.53.0)(typescript@5.2.2) + version: 6.11.0(eslint@8.53.0)(typescript@5.3.2) eslint: specifier: 8.53.0 version: 8.53.0 @@ -1057,8 +1057,8 @@ importers: specifier: 0.29.0 version: 0.29.0 typescript: - specifier: 5.2.2 - version: 5.2.2 + specifier: 5.3.2 + version: 5.3.2 packages/sw: dependencies: @@ -1074,7 +1074,7 @@ importers: devDependencies: '@typescript-eslint/parser': specifier: 6.11.0 - version: 6.11.0(eslint@8.53.0)(typescript@5.2.2) + version: 6.11.0(eslint@8.53.0)(typescript@5.3.2) '@typescript/lib-webworker': specifier: npm:@types/serviceworker@0.0.67 version: /@types/serviceworker@0.0.67 @@ -1085,8 +1085,8 @@ importers: specifier: 2.29.0 version: 2.29.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0) typescript: - specifier: 5.2.2 - version: 5.2.2 + specifier: 5.3.2 + version: 5.3.2 packages: @@ -4254,7 +4254,7 @@ packages: chalk: 4.1.2 dev: true - /@joshwooding/vite-plugin-react-docgen-typescript@0.3.0(typescript@5.2.2)(vite@4.5.0): + /@joshwooding/vite-plugin-react-docgen-typescript@0.3.0(typescript@5.3.2)(vite@4.5.0): resolution: {integrity: sha512-2D6y7fNvFmsLmRt6UCOFJPvFoPMJGT0Uh1Wg0RaigUp7kdQPs6yYn8Dmx6GZkOH/NW0yMTwRz/p0SRMMRo50vA==} peerDependencies: typescript: '>= 4.3.x' @@ -4266,8 +4266,8 @@ packages: glob: 7.2.3 glob-promise: 4.2.2(glob@7.2.3) magic-string: 0.27.0 - react-docgen-typescript: 2.2.2(typescript@5.2.2) - typescript: 5.2.2 + react-docgen-typescript: 2.2.2(typescript@5.3.2) + typescript: 5.3.2 vite: 4.5.0(@types/node@20.9.1)(sass@1.69.5)(terser@5.24.0) dev: true @@ -6348,7 +6348,7 @@ packages: - supports-color dev: true - /@storybook/builder-vite@7.5.3(typescript@5.2.2)(vite@4.5.0): + /@storybook/builder-vite@7.5.3(typescript@5.3.2)(vite@4.5.0): resolution: {integrity: sha512-c104V3O75OCVnfZj0Jr70V09g0KSbPGvQK2Zh31omXGvakG8XrhWolYxkmjOcForJmAqsXnKs/nw3F75Gp853g==} peerDependencies: '@preact/preset-vite': '*' @@ -6379,7 +6379,7 @@ packages: fs-extra: 11.1.1 magic-string: 0.30.5 rollup: 3.29.4 - typescript: 5.2.2 + typescript: 5.3.2 vite: 4.5.0(@types/node@20.9.1)(sass@1.69.5)(terser@5.24.0) transitivePeerDependencies: - encoding @@ -6750,7 +6750,7 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/react-vite@7.5.3(react-dom@18.2.0)(react@18.2.0)(rollup@4.4.1)(typescript@5.2.2)(vite@4.5.0): + /@storybook/react-vite@7.5.3(react-dom@18.2.0)(react@18.2.0)(rollup@4.4.1)(typescript@5.3.2)(vite@4.5.0): resolution: {integrity: sha512-ArPyHgiPbT5YvcyK4xK/DfqBOpn4R4/EP3kfIGhx8QKJyOtxPEYFdkLIZ5xu3KnPX7/z7GT+4a6Rb+8sk9gliA==} engines: {node: '>=16'} peerDependencies: @@ -6758,10 +6758,10 @@ packages: react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 vite: ^3.0.0 || ^4.0.0 || ^5.0.0 dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.3.0(typescript@5.2.2)(vite@4.5.0) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.3.0(typescript@5.3.2)(vite@4.5.0) '@rollup/pluginutils': 5.0.5(rollup@4.4.1) - '@storybook/builder-vite': 7.5.3(typescript@5.2.2)(vite@4.5.0) - '@storybook/react': 7.5.3(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2) + '@storybook/builder-vite': 7.5.3(typescript@5.3.2)(vite@4.5.0) + '@storybook/react': 7.5.3(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.2) '@vitejs/plugin-react': 3.1.0(vite@4.5.0) magic-string: 0.30.5 react: 18.2.0 @@ -6777,7 +6777,7 @@ packages: - vite-plugin-glimmerx dev: true - /@storybook/react@7.5.3(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2): + /@storybook/react@7.5.3(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.2): resolution: {integrity: sha512-dZILdM36xMFDjdmmy421G5X+sOIncB2qF3IPTooniG1i1Z6v/dVNo57ovdID9lDTNa+AWr2fLB9hANiISMqmjQ==} engines: {node: '>=16.0.0'} peerDependencies: @@ -6810,7 +6810,7 @@ packages: react-element-to-jsx-string: 15.0.0(react-dom@18.2.0)(react@18.2.0) ts-dedent: 2.2.0 type-fest: 2.19.0 - typescript: 5.2.2 + typescript: 5.3.2 util-deprecate: 1.0.2 transitivePeerDependencies: - encoding @@ -6892,7 +6892,7 @@ packages: file-system-cache: 2.3.0 dev: true - /@storybook/vue3-vite@7.5.3(@vue/compiler-core@3.3.8)(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2)(vite@4.5.0)(vue@3.3.8): + /@storybook/vue3-vite@7.5.3(@vue/compiler-core@3.3.8)(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.2)(vite@4.5.0)(vue@3.3.8): resolution: {integrity: sha512-gkNwDDn2AKthAtaoPrHb0+2gi33UluxpfSq/M5COoMEVFphj6y/jyDa+OEYlceXgnD8g2xvX4/yv2TbTNDzmcQ==} engines: {node: ^14.18 || >=16} peerDependencies: @@ -6900,7 +6900,7 @@ packages: react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 vite: ^3.0.0 || ^4.0.0 || ^5.0.0 dependencies: - '@storybook/builder-vite': 7.5.3(typescript@5.2.2)(vite@4.5.0) + '@storybook/builder-vite': 7.5.3(typescript@5.3.2)(vite@4.5.0) '@storybook/core-server': 7.5.3 '@storybook/vue3': 7.5.3(@vue/compiler-core@3.3.8)(vue@3.3.8) '@vitejs/plugin-vue': 4.5.0(vite@4.5.0)(vue@3.3.8) @@ -6937,7 +6937,7 @@ packages: lodash: 4.17.21 ts-dedent: 2.2.0 type-fest: 2.19.0 - vue: 3.3.8(typescript@5.2.2) + vue: 3.3.8(typescript@5.3.2) vue-component-type-helpers: 1.8.22 transitivePeerDependencies: - encoding @@ -7432,7 +7432,7 @@ packages: '@testing-library/dom': 9.3.3 '@vue/compiler-sfc': 3.3.8 '@vue/test-utils': 2.4.1(vue@3.3.8) - vue: 3.3.8(typescript@5.2.2) + vue: 3.3.8(typescript@5.3.2) transitivePeerDependencies: - '@vue/server-renderer' dev: true @@ -8073,7 +8073,7 @@ packages: dev: true optional: true - /@typescript-eslint/eslint-plugin@6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.2.2): + /@typescript-eslint/eslint-plugin@6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.3.2): resolution: {integrity: sha512-uXnpZDc4VRjY4iuypDBKzW1rz9T5YBBK0snMn8MaTSNd2kMlj50LnLBABELjJiOL5YHk7ZD8hbSpI9ubzqYI0w==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -8085,10 +8085,10 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.6.2 - '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.2.2) + '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.3.2) '@typescript-eslint/scope-manager': 6.11.0 - '@typescript-eslint/type-utils': 6.11.0(eslint@8.53.0)(typescript@5.2.2) - '@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.2.2) + '@typescript-eslint/type-utils': 6.11.0(eslint@8.53.0)(typescript@5.3.2) + '@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.3.2) '@typescript-eslint/visitor-keys': 6.11.0 debug: 4.3.4(supports-color@8.1.1) eslint: 8.53.0 @@ -8096,13 +8096,13 @@ packages: ignore: 5.2.4 natural-compare: 1.4.0 semver: 7.5.4 - ts-api-utils: 1.0.1(typescript@5.2.2) - typescript: 5.2.2 + ts-api-utils: 1.0.1(typescript@5.3.2) + typescript: 5.3.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.2.2): + /@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.2): resolution: {integrity: sha512-+whEdjk+d5do5nxfxx73oanLL9ghKO3EwM9kBCkUtWMRwWuPaFv9ScuqlYfQ6pAD6ZiJhky7TZ2ZYhrMsfMxVQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -8114,11 +8114,11 @@ packages: dependencies: '@typescript-eslint/scope-manager': 6.11.0 '@typescript-eslint/types': 6.11.0 - '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.2.2) + '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.3.2) '@typescript-eslint/visitor-keys': 6.11.0 debug: 4.3.4(supports-color@8.1.1) eslint: 8.53.0 - typescript: 5.2.2 + typescript: 5.3.2 transitivePeerDependencies: - supports-color dev: true @@ -8131,7 +8131,7 @@ packages: '@typescript-eslint/visitor-keys': 6.11.0 dev: true - /@typescript-eslint/type-utils@6.11.0(eslint@8.53.0)(typescript@5.2.2): + /@typescript-eslint/type-utils@6.11.0(eslint@8.53.0)(typescript@5.3.2): resolution: {integrity: sha512-nA4IOXwZtqBjIoYrJcYxLRO+F9ri+leVGoJcMW1uqr4r1Hq7vW5cyWrA43lFbpRvQ9XgNrnfLpIkO3i1emDBIA==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -8141,12 +8141,12 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.2.2) - '@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.2.2) + '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.3.2) + '@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.3.2) debug: 4.3.4(supports-color@8.1.1) eslint: 8.53.0 - ts-api-utils: 1.0.1(typescript@5.2.2) - typescript: 5.2.2 + ts-api-utils: 1.0.1(typescript@5.3.2) + typescript: 5.3.2 transitivePeerDependencies: - supports-color dev: true @@ -8156,7 +8156,7 @@ packages: engines: {node: ^16.0.0 || >=18.0.0} dev: true - /@typescript-eslint/typescript-estree@6.11.0(typescript@5.2.2): + /@typescript-eslint/typescript-estree@6.11.0(typescript@5.3.2): resolution: {integrity: sha512-Aezzv1o2tWJwvZhedzvD5Yv7+Lpu1by/U1LZ5gLc4tCx8jUmuSCMioPFRjliN/6SJIvY6HpTtJIWubKuYYYesQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -8171,13 +8171,13 @@ packages: globby: 11.1.0 is-glob: 4.0.3 semver: 7.5.4 - ts-api-utils: 1.0.1(typescript@5.2.2) - typescript: 5.2.2 + ts-api-utils: 1.0.1(typescript@5.3.2) + typescript: 5.3.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/utils@6.11.0(eslint@8.53.0)(typescript@5.2.2): + /@typescript-eslint/utils@6.11.0(eslint@8.53.0)(typescript@5.3.2): resolution: {integrity: sha512-p23ibf68fxoZy605dc0dQAEoUsoiNoP3MD9WQGiHLDuTSOuqoTsa4oAy+h3KDkTcxbbfOtUjb9h3Ta0gT4ug2g==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -8188,7 +8188,7 @@ packages: '@types/semver': 7.5.5 '@typescript-eslint/scope-manager': 6.11.0 '@typescript-eslint/types': 6.11.0 - '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.2.2) + '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.3.2) eslint: 8.53.0 semver: 7.5.4 transitivePeerDependencies: @@ -8232,7 +8232,7 @@ packages: vue: ^3.2.25 dependencies: vite: 4.5.0(@types/node@20.9.1)(sass@1.69.5)(terser@5.24.0) - vue: 3.3.8(typescript@5.2.2) + vue: 3.3.8(typescript@5.3.2) /@vitest/coverage-v8@0.34.6(vitest@0.34.6): resolution: {integrity: sha512-fivy/OK2d/EsJFoEoxHFEnNGTg+MmdZBAVK9Ka4qhXR2K3J0DS08vcGVwzDtXSuUMabLv4KtPcpSKkcMXFDViw==} @@ -8327,7 +8327,7 @@ packages: ast-kit: 0.11.2(rollup@4.4.1) local-pkg: 0.5.0 magic-string-ast: 0.3.0 - vue: 3.3.8(typescript@5.2.2) + vue: 3.3.8(typescript@5.3.2) transitivePeerDependencies: - rollup dev: false @@ -8344,7 +8344,7 @@ packages: '@vue/shared': 3.3.8 magic-string: 0.30.5 unplugin: 1.5.1 - vue: 3.3.8(typescript@5.2.2) + vue: 3.3.8(typescript@5.3.2) transitivePeerDependencies: - rollup dev: false @@ -8415,7 +8415,7 @@ packages: '@vue/compiler-dom': 3.3.8 '@vue/shared': 3.3.8 - /@vue/language-core@1.8.22(typescript@5.2.2): + /@vue/language-core@1.8.22(typescript@5.3.2): resolution: {integrity: sha512-bsMoJzCrXZqGsxawtUea1cLjUT9dZnDsy5TuZ+l1fxRMzUGQUG9+Ypq4w//CqpWmrx7nIAJpw2JVF/t258miRw==} peerDependencies: typescript: '*' @@ -8430,7 +8430,7 @@ packages: computeds: 0.0.1 minimatch: 9.0.3 muggle-string: 0.3.1 - typescript: 5.2.2 + typescript: 5.3.2 vue-template-compiler: 2.7.14 dev: true @@ -8468,7 +8468,7 @@ packages: dependencies: '@vue/compiler-ssr': 3.3.8 '@vue/shared': 3.3.8 - vue: 3.3.8(typescript@5.2.2) + vue: 3.3.8(typescript@5.3.2) /@vue/shared@3.3.6: resolution: {integrity: sha512-Xno5pEqg8SVhomD0kTSmfh30ZEmV/+jZtyh39q6QflrjdJCXah5lrnOLi9KB6a5k5aAHXMXjoMnxlzUkCNfWLQ==} @@ -8491,7 +8491,7 @@ packages: optional: true dependencies: js-beautify: 1.14.9 - vue: 3.3.8(typescript@5.2.2) + vue: 3.3.8(typescript@5.3.2) vue-component-type-helpers: 1.8.4 dev: true @@ -11158,7 +11158,7 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.2.2) + '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.3.2) debug: 3.2.7(supports-color@5.5.0) eslint: 8.53.0 eslint-import-resolver-node: 0.3.9 @@ -11176,7 +11176,7 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.2.2) + '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.3.2) array-includes: 3.1.7 array.prototype.findlastindex: 1.2.3 array.prototype.flat: 1.3.2 @@ -14852,10 +14852,10 @@ packages: msw: '>=0.35.0 <2.0.0' dependencies: is-node-process: 1.2.0 - msw: 1.3.2(typescript@5.2.2) + msw: 1.3.2(typescript@5.3.2) dev: true - /msw@1.3.2(typescript@5.2.2): + /msw@1.3.2(typescript@5.3.2): resolution: {integrity: sha512-wKLhFPR+NitYTkQl5047pia0reNGgf0P6a1eTnA5aNlripmiz0sabMvvHcicE8kQ3/gZcI0YiPFWmYfowfm3lA==} engines: {node: '>=14'} hasBin: true @@ -14884,7 +14884,7 @@ packages: path-to-regexp: 6.2.1 strict-event-emitter: 0.4.6 type-fest: 2.19.0 - typescript: 5.2.2 + typescript: 5.3.2 yargs: 17.6.2 transitivePeerDependencies: - encoding @@ -16773,12 +16773,12 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true - /react-docgen-typescript@2.2.2(typescript@5.2.2): + /react-docgen-typescript@2.2.2(typescript@5.3.2): resolution: {integrity: sha512-tvg2ZtOpOi6QDwsb3GZhOjDkkX0h8Z2gipvTg6OVMUyoYoURhEiRNePT8NZItTVCDh39JJHnLdfCOkzoLbFnTg==} peerDependencies: typescript: '>= 4.3.x' dependencies: - typescript: 5.2.2 + typescript: 5.3.2 dev: true /react-docgen@6.0.4: @@ -18627,13 +18627,13 @@ packages: escape-string-regexp: 5.0.0 dev: false - /ts-api-utils@1.0.1(typescript@5.2.2): + /ts-api-utils@1.0.1(typescript@5.3.2): resolution: {integrity: sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==} engines: {node: '>=16.13.0'} peerDependencies: typescript: '>=4.2.0' dependencies: - typescript: 5.2.2 + typescript: 5.3.2 dev: true /ts-dedent@2.2.0: @@ -18897,8 +18897,8 @@ packages: hasBin: true dev: true - /typescript@5.2.2: - resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} + /typescript@5.3.2: + resolution: {integrity: sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==} engines: {node: '>=14.17'} hasBin: true @@ -19186,7 +19186,7 @@ packages: diff: 5.1.0 diff-match-patch: 1.0.5 highlight.js: 11.8.0 - vue: 3.3.8(typescript@5.2.2) + vue: 3.3.8(typescript@5.3.2) vue-demi: 0.13.11(vue@3.3.8) dev: false @@ -19400,7 +19400,7 @@ packages: '@vue/composition-api': optional: true dependencies: - vue: 3.3.8(typescript@5.2.2) + vue: 3.3.8(typescript@5.3.2) dev: false /vue-docgen-api@4.64.1(vue@3.3.8): @@ -19444,7 +19444,7 @@ packages: peerDependencies: vue: '>=2' dependencies: - vue: 3.3.8(typescript@5.2.2) + vue: 3.3.8(typescript@5.3.2) dev: true /vue-template-compiler@2.7.14: @@ -19454,19 +19454,19 @@ packages: he: 1.2.0 dev: true - /vue-tsc@1.8.22(typescript@5.2.2): + /vue-tsc@1.8.22(typescript@5.3.2): resolution: {integrity: sha512-j9P4kHtW6eEE08aS5McFZE/ivmipXy0JzrnTgbomfABMaVKx37kNBw//irL3+LlE3kOo63XpnRigyPC3w7+z+A==} hasBin: true peerDependencies: typescript: '*' dependencies: '@volar/typescript': 1.10.7 - '@vue/language-core': 1.8.22(typescript@5.2.2) + '@vue/language-core': 1.8.22(typescript@5.3.2) semver: 7.5.4 - typescript: 5.2.2 + typescript: 5.3.2 dev: true - /vue@3.3.8(typescript@5.2.2): + /vue@3.3.8(typescript@5.3.2): resolution: {integrity: sha512-5VSX/3DabBikOXMsxzlW8JyfeLKlG9mzqnWgLQLty88vdZL7ZJgrdgBOmrArwxiLtmS+lNNpPcBYqrhE6TQW5w==} peerDependencies: typescript: '*' @@ -19479,7 +19479,7 @@ packages: '@vue/runtime-dom': 3.3.8 '@vue/server-renderer': 3.3.8(vue@3.3.8) '@vue/shared': 3.3.8 - typescript: 5.2.2 + typescript: 5.3.2 /vuedraggable@4.1.0(vue@3.3.8): resolution: {integrity: sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==} @@ -19487,7 +19487,7 @@ packages: vue: ^3.0.1 dependencies: sortablejs: 1.14.0 - vue: 3.3.8(typescript@5.2.2) + vue: 3.3.8(typescript@5.3.2) dev: false /w3c-xmlserializer@4.0.0: From b5be0e5780453653ca37ea809c36757057a21758 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?= <46447427+samunohito@users.noreply.github.com> Date: Tue, 21 Nov 2023 15:12:05 +0900 Subject: [PATCH 017/435] =?UTF-8?q?note.ts=E3=81=AEchannel=E3=82=92?= =?UTF-8?q?=E6=AD=A3=E3=81=97=E3=81=84=E5=BD=A2=E3=81=AB=E3=81=97=E3=81=9F?= =?UTF-8?q?=E3=81=93=E3=81=A8=E3=81=AB=E3=82=88=E3=82=8A=E8=A1=A8=E5=87=BA?= =?UTF-8?q?=E5=8C=96=E3=81=97=E3=81=9F=E5=9E=8B=E3=83=81=E3=82=A7=E3=83=83?= =?UTF-8?q?=E3=82=AF=E3=82=A8=E3=83=A9=E3=83=BC=E3=82=92=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=20(#12395)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: osamu <46447427+sam-osamu@users.noreply.github.com> --- packages/backend/src/models/json-schema/note.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/models/json-schema/note.ts b/packages/backend/src/models/json-schema/note.ts index 9d5d558f51..392fa7e1cb 100644 --- a/packages/backend/src/models/json-schema/note.ts +++ b/packages/backend/src/models/json-schema/note.ts @@ -134,11 +134,19 @@ export const packedNoteSchema = { }, name: { type: 'string', - optional: false, nullable: true, + optional: false, nullable: false, + }, + color: { + type: 'string', + optional: false, nullable: false, }, isSensitive: { type: 'boolean', - optional: true, nullable: false, + optional: false, nullable: false, + }, + allowRenoteToExternal: { + type: 'boolean', + optional: false, nullable: false, }, }, }, From b3d1cc9525b44e37b983c3a97af4e2aea80ea735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?= <46447427+samunohito@users.noreply.github.com> Date: Tue, 21 Nov 2023 15:32:34 +0900 Subject: [PATCH 018/435] =?UTF-8?q?=E3=82=B5=E3=83=BC=E3=83=90=E8=B5=B7?= =?UTF-8?q?=E5=8B=95=E6=99=82=E3=81=AB=E3=82=A2=E3=83=B3=E3=83=86=E3=83=8A?= =?UTF-8?q?=E3=81=8C=E9=9D=9E=E3=82=A2=E3=82=AF=E3=83=86=E3=82=A3=E3=83=96?= =?UTF-8?q?=E3=81=A0=E3=81=A3=E3=81=9F=E5=A0=B4=E5=90=88=E3=80=81=E3=82=A2?= =?UTF-8?q?=E3=82=AF=E3=83=86=E3=82=A3=E3=83=96=E5=8C=96=E3=81=97=E3=81=A6?= =?UTF-8?q?=E3=82=82=E5=86=8D=E8=B5=B7=E5=8B=95=E3=81=99=E3=82=8B=E3=81=BE?= =?UTF-8?q?=E3=81=A7=E5=8F=8D=E6=98=A0=E3=81=95=E3=82=8C=E3=81=AA=E3=81=84?= =?UTF-8?q?=20(#12391)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * サーバ起動時にアンテナが非アクティブだった場合、アクティブ化しても再起動するまで反映されない * Fix CHANGELOG.md * lastUsedAtの更新に不備が出るので修正 --------- Co-authored-by: osamu <46447427+sam-osamu@users.noreply.github.com> --- CHANGELOG.md | 1 + packages/backend/src/core/AntennaService.ts | 20 ++++++++++++++----- .../server/api/endpoints/antennas/notes.ts | 16 +++++++++++---- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2efa1b230d..900d042eaf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ - fix: 「設定のバックアップ」で一部の項目がバックアップに含まれていなかった問題を修正 ### Server +- Fix: 時間経過により無効化されたアンテナを再有効化したとき、サーバ再起動までその状況が反映されないのを修正 #12303 - Fix: ロールタイムラインが保存されない問題を修正 ## 2023.11.1 diff --git a/packages/backend/src/core/AntennaService.ts b/packages/backend/src/core/AntennaService.ts index 65be275548..2815d24734 100644 --- a/packages/backend/src/core/AntennaService.ts +++ b/packages/backend/src/core/AntennaService.ts @@ -60,11 +60,21 @@ export class AntennaService implements OnApplicationShutdown { lastUsedAt: new Date(body.lastUsedAt), }); break; - case 'antennaUpdated': - this.antennas[this.antennas.findIndex(a => a.id === body.id)] = { - ...body, - lastUsedAt: new Date(body.lastUsedAt), - }; + case 'antennaUpdated': { + const idx = this.antennas.findIndex(a => a.id === body.id); + if (idx >= 0) { + this.antennas[idx] = { + ...body, + lastUsedAt: new Date(body.lastUsedAt), + }; + } else { + // サーバ起動時にactiveじゃなかった場合、リストに持っていないので追加する必要あり + this.antennas.push({ + ...body, + lastUsedAt: new Date(body.lastUsedAt), + }); + } + } break; case 'antennaDeleted': this.antennas = this.antennas.filter(a => a.id !== body.id); diff --git a/packages/backend/src/server/api/endpoints/antennas/notes.ts b/packages/backend/src/server/api/endpoints/antennas/notes.ts index 9b5911800c..29e56b1085 100644 --- a/packages/backend/src/server/api/endpoints/antennas/notes.ts +++ b/packages/backend/src/server/api/endpoints/antennas/notes.ts @@ -13,6 +13,7 @@ import { DI } from '@/di-symbols.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { IdService } from '@/core/IdService.js'; import { FunoutTimelineService } from '@/core/FunoutTimelineService.js'; +import { GlobalEventService } from '@/core/GlobalEventService.js'; import { ApiError } from '../../error.js'; export const meta = { @@ -71,6 +72,7 @@ export default class extends Endpoint { // eslint- private queryService: QueryService, private noteReadService: NoteReadService, private funoutTimelineService: FunoutTimelineService, + private globalEventService: GlobalEventService, ) { super(meta, paramDef, async (ps, me) => { const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null); @@ -85,10 +87,16 @@ export default class extends Endpoint { // eslint- throw new ApiError(meta.errors.noSuchAntenna); } - this.antennasRepository.update(antenna.id, { - isActive: true, - lastUsedAt: new Date(), - }); + // falseだった場合はアンテナの配信先が増えたことを通知したい + const needPublishEvent = !antenna.isActive; + + antenna.isActive = true; + antenna.lastUsedAt = new Date(); + this.antennasRepository.update(antenna.id, antenna); + + if (needPublishEvent) { + this.globalEventService.publishInternalEvent('antennaUpdated', antenna); + } let noteIds = await this.funoutTimelineService.get(`antennaTimeline:${antenna.id}`, untilId, sinceId); noteIds = noteIds.slice(0, ps.limit); From 481bca4cf2e8f13a46654770291b7ee31a1c361e Mon Sep 17 00:00:00 2001 From: nenohi Date: Tue, 21 Nov 2023 19:50:06 +0900 Subject: [PATCH 019/435] =?UTF-8?q?=E5=BA=83=E5=91=8A=E6=8E=B2=E8=BC=89?= =?UTF-8?q?=E3=83=9A=E3=83=BC=E3=82=B8=E3=81=AB=E3=81=A6filter=E3=82=92?= =?UTF-8?q?=E3=82=8F=E3=81=8B=E3=82=8A=E3=82=84=E3=81=99=E3=81=8F=20(#1238?= =?UTF-8?q?5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/server/api/endpoints/admin/ad/list.ts | 6 ++- packages/frontend/src/pages/admin/ads.vue | 50 ++++++++++++------- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/packages/backend/src/server/api/endpoints/admin/ad/list.ts b/packages/backend/src/server/api/endpoints/admin/ad/list.ts index 29eff89523..1366fbf76a 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/list.ts @@ -22,7 +22,7 @@ export const paramDef = { limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, sinceId: { type: 'string', format: 'misskey:id' }, untilId: { type: 'string', format: 'misskey:id' }, - publishing: { type: 'boolean', default: false }, + publishing: { type: 'boolean', default: null, nullable: true}, }, required: [], } as const; @@ -37,8 +37,10 @@ export default class extends Endpoint { // eslint- ) { super(meta, paramDef, async (ps, me) => { const query = this.queryService.makePaginationQuery(this.adsRepository.createQueryBuilder('ad'), ps.sinceId, ps.untilId); - if (ps.publishing) { + if (ps.publishing === true) { query.andWhere('ad.expiresAt > :now', { now: new Date() }).andWhere('ad.startsAt <= :now', { now: new Date() }); + } else if (ps.publishing === false) { + query.andWhere('ad.expiresAt <= :now', { now: new Date() }).orWhere('ad.startsAt > :now', { now: new Date() }); } const ads = await query.limit(ps.limit).getMany(); diff --git a/packages/frontend/src/pages/admin/ads.vue b/packages/frontend/src/pages/admin/ads.vue index 6e07585fdc..1ce99d4ba5 100644 --- a/packages/frontend/src/pages/admin/ads.vue +++ b/packages/frontend/src/pages/admin/ads.vue @@ -9,12 +9,15 @@ SPDX-License-Identifier: AGPL-3.0-only - - {{ i18n.ts.publishing }} - + + + + + +
- + @@ -82,14 +85,14 @@ SPDX-License-Identifier: AGPL-3.0-only + + From c8b85a98b807be7d7b4032cb2b9703c25665b1c5 Mon Sep 17 00:00:00 2001 From: woxtu Date: Sun, 26 Nov 2023 09:54:24 +0900 Subject: [PATCH 043/435] Add mocks for Web Audio API (#12457) --- packages/frontend/test/init.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/frontend/test/init.ts b/packages/frontend/test/init.ts index 986fa99c17..ab5e84b53c 100644 --- a/packages/frontend/test/init.ts +++ b/packages/frontend/test/init.ts @@ -25,3 +25,21 @@ vi.mock('@/store.js', () => { }, }; }); + +// Add mocks for Web Audio API +const AudioNodeMock = vi.fn(() => ({ + connect: vi.fn(() => ({ connect: vi.fn() })), + start: vi.fn(), +})); + +const GainNodeMock = vi.fn(() => ({ + gain: vi.fn(), +})); + +const AudioContextMock = vi.fn(() => ({ + createBufferSource: vi.fn(() => new AudioNodeMock()), + createGain: vi.fn(() => new GainNodeMock()), + decodeAudioData: vi.fn(), +})); + +vi.stubGlobal('AudioContext', AudioContextMock); From 3e0231d99501aba3b1f47431015c9b4a2f671e26 Mon Sep 17 00:00:00 2001 From: zyoshoka <107108195+zyoshoka@users.noreply.github.com> Date: Sun, 26 Nov 2023 10:01:06 +0900 Subject: [PATCH 044/435] =?UTF-8?q?fix(backend):=20=E4=BD=95=E3=82=82?= =?UTF-8?q?=E3=83=8E=E3=83=BC=E3=83=88=E3=81=97=E3=81=A6=E3=81=84=E3=81=AA?= =?UTF-8?q?=E3=81=84=E3=83=A6=E3=83=BC=E3=82=B6=E3=83=BC=E3=81=AE=E3=83=95?= =?UTF-8?q?=E3=82=A3=E3=83=BC=E3=83=89=E3=81=AB=E3=82=A2=E3=82=AF=E3=82=BB?= =?UTF-8?q?=E3=82=B9=E3=81=99=E3=82=8B=E3=81=A8=E3=82=A8=E3=83=A9=E3=83=BC?= =?UTF-8?q?=E3=81=AB=E3=81=AA=E3=82=8B=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3=20(#12455)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(backend): 何もノートしていないユーザーのフィードにアクセスするとエラーになる問題を修正 * Update CHANGELOG.md * add test * fix: incorrect bob's username --- CHANGELOG.md | 1 + packages/backend/src/server/web/FeedService.ts | 2 +- packages/backend/test/e2e/fetch-resource.ts | 7 ++++++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0215e7e735..fdf6709117 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ - Fix: api.jsonの生成ロジックを改善 #12402 - Fix: 招待コードが使い回せる問題を修正 - Fix: 特定の条件下でチャンネルやユーザーのノート一覧に最新のノートが表示されなくなる問題を修正 +- Fix: 何もノートしていないユーザーのフィードにアクセスするとエラーになる問題を修正 ## 2023.11.1 diff --git a/packages/backend/src/server/web/FeedService.ts b/packages/backend/src/server/web/FeedService.ts index 3ba26ad34a..dd4304e6ef 100644 --- a/packages/backend/src/server/web/FeedService.ts +++ b/packages/backend/src/server/web/FeedService.ts @@ -58,7 +58,7 @@ export class FeedService { const feed = new Feed({ id: author.link, title: `${author.name} (@${user.username}@${this.config.host})`, - updated: this.idService.parse(notes[0].id).date, + updated: notes.length !== 0 ? this.idService.parse(notes[0].id).date : undefined, generator: 'Misskey', description: `${user.notesCount} Notes, ${profile.ffVisibility === 'public' ? user.followingCount : '?'} Following, ${profile.ffVisibility === 'public' ? user.followersCount : '?'} Followers${profile.description ? ` · ${profile.description}` : ''}`, link: author.link, diff --git a/packages/backend/test/e2e/fetch-resource.ts b/packages/backend/test/e2e/fetch-resource.ts index 1cbfec3e5f..251d662760 100644 --- a/packages/backend/test/e2e/fetch-resource.ts +++ b/packages/backend/test/e2e/fetch-resource.ts @@ -93,7 +93,7 @@ describe('Webリソース', () => { }); aliceChannel = await channel(alice, {}); - bob = await signup({ username: 'alice' }); + bob = await signup({ username: 'bob' }); }, 1000 * 60 * 2); afterAll(async () => { @@ -152,6 +152,11 @@ describe('Webリソース', () => { type, })); + test('がGETできる。(ノートが存在しない場合でも。)', async () => await ok({ + path: path(bob.username), + type, + })); + test('は存在しないユーザーはGETできない。', async () => await notOk({ path: path('nonexisting'), status: 404, From 7a494b2aa7e0337a220b8988122839e9a7b75538 Mon Sep 17 00:00:00 2001 From: zyoshoka <107108195+zyoshoka@users.noreply.github.com> Date: Sun, 26 Nov 2023 10:02:22 +0900 Subject: [PATCH 045/435] fix(backend): rename FunoutTimelineService to FanoutTimelineService (#12453) --- packages/backend/src/core/AntennaService.ts | 6 ++-- packages/backend/src/core/CoreModule.ts | 12 +++---- ...ineService.ts => FanoutTimelineService.ts} | 2 +- .../backend/src/core/NoteCreateService.ts | 36 +++++++++---------- packages/backend/src/core/RoleService.ts | 6 ++-- .../backend/src/core/UserFollowingService.ts | 8 ++--- .../server/api/endpoints/antennas/notes.ts | 6 ++-- .../server/api/endpoints/channels/timeline.ts | 6 ++-- .../api/endpoints/notes/hybrid-timeline.ts | 10 +++--- .../api/endpoints/notes/local-timeline.ts | 8 ++--- .../server/api/endpoints/notes/timeline.ts | 6 ++-- .../api/endpoints/notes/user-list-timeline.ts | 6 ++-- .../src/server/api/endpoints/roles/notes.ts | 6 ++-- .../src/server/api/endpoints/users/notes.ts | 10 +++--- 14 files changed, 64 insertions(+), 64 deletions(-) rename packages/backend/src/core/{FunoutTimelineService.ts => FanoutTimelineService.ts} (98%) diff --git a/packages/backend/src/core/AntennaService.ts b/packages/backend/src/core/AntennaService.ts index 2815d24734..2c27a02559 100644 --- a/packages/backend/src/core/AntennaService.ts +++ b/packages/backend/src/core/AntennaService.ts @@ -16,7 +16,7 @@ import type { AntennasRepository, UserListMembershipsRepository } from '@/models import { UtilityService } from '@/core/UtilityService.js'; import { bindThis } from '@/decorators.js'; import type { GlobalEvents } from '@/core/GlobalEventService.js'; -import { FunoutTimelineService } from '@/core/FunoutTimelineService.js'; +import { FanoutTimelineService } from '@/core/FanoutTimelineService.js'; import type { OnApplicationShutdown } from '@nestjs/common'; @Injectable() @@ -39,7 +39,7 @@ export class AntennaService implements OnApplicationShutdown { private utilityService: UtilityService, private globalEventService: GlobalEventService, - private funoutTimelineService: FunoutTimelineService, + private fanoutTimelineService: FanoutTimelineService, ) { this.antennasFetched = false; this.antennas = []; @@ -94,7 +94,7 @@ export class AntennaService implements OnApplicationShutdown { const redisPipeline = this.redisForTimelines.pipeline(); for (const antenna of matchedAntennas) { - this.funoutTimelineService.push(`antennaTimeline:${antenna.id}`, note.id, 200, redisPipeline); + this.fanoutTimelineService.push(`antennaTimeline:${antenna.id}`, note.id, 200, redisPipeline); this.globalEventService.publishAntennaStream(antenna.id, 'note', note); } diff --git a/packages/backend/src/core/CoreModule.ts b/packages/backend/src/core/CoreModule.ts index 9fb29e0e68..bf6f0ef879 100644 --- a/packages/backend/src/core/CoreModule.ts +++ b/packages/backend/src/core/CoreModule.ts @@ -62,7 +62,7 @@ import { FileInfoService } from './FileInfoService.js'; import { SearchService } from './SearchService.js'; import { ClipService } from './ClipService.js'; import { FeaturedService } from './FeaturedService.js'; -import { FunoutTimelineService } from './FunoutTimelineService.js'; +import { FanoutTimelineService } from './FanoutTimelineService.js'; import { ChannelFollowingService } from './ChannelFollowingService.js'; import { RegistryApiService } from './RegistryApiService.js'; import { ChartLoggerService } from './chart/ChartLoggerService.js'; @@ -194,7 +194,7 @@ const $FileInfoService: Provider = { provide: 'FileInfoService', useExisting: Fi const $SearchService: Provider = { provide: 'SearchService', useExisting: SearchService }; const $ClipService: Provider = { provide: 'ClipService', useExisting: ClipService }; const $FeaturedService: Provider = { provide: 'FeaturedService', useExisting: FeaturedService }; -const $FunoutTimelineService: Provider = { provide: 'FunoutTimelineService', useExisting: FunoutTimelineService }; +const $FanoutTimelineService: Provider = { provide: 'FanoutTimelineService', useExisting: FanoutTimelineService }; const $ChannelFollowingService: Provider = { provide: 'ChannelFollowingService', useExisting: ChannelFollowingService }; const $RegistryApiService: Provider = { provide: 'RegistryApiService', useExisting: RegistryApiService }; @@ -330,7 +330,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting SearchService, ClipService, FeaturedService, - FunoutTimelineService, + FanoutTimelineService, ChannelFollowingService, RegistryApiService, ChartLoggerService, @@ -459,7 +459,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting $SearchService, $ClipService, $FeaturedService, - $FunoutTimelineService, + $FanoutTimelineService, $ChannelFollowingService, $RegistryApiService, $ChartLoggerService, @@ -589,7 +589,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting SearchService, ClipService, FeaturedService, - FunoutTimelineService, + FanoutTimelineService, ChannelFollowingService, RegistryApiService, FederationChart, @@ -717,7 +717,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting $SearchService, $ClipService, $FeaturedService, - $FunoutTimelineService, + $FanoutTimelineService, $ChannelFollowingService, $RegistryApiService, $FederationChart, diff --git a/packages/backend/src/core/FunoutTimelineService.ts b/packages/backend/src/core/FanoutTimelineService.ts similarity index 98% rename from packages/backend/src/core/FunoutTimelineService.ts rename to packages/backend/src/core/FanoutTimelineService.ts index c633c329e5..6a1b0aa879 100644 --- a/packages/backend/src/core/FunoutTimelineService.ts +++ b/packages/backend/src/core/FanoutTimelineService.ts @@ -10,7 +10,7 @@ import { bindThis } from '@/decorators.js'; import { IdService } from '@/core/IdService.js'; @Injectable() -export class FunoutTimelineService { +export class FanoutTimelineService { constructor( @Inject(DI.redisForTimelines) private redisForTimelines: Redis.Redis, diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index 86f220abd0..fd87edc28e 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -54,7 +54,7 @@ import { RoleService } from '@/core/RoleService.js'; import { MetaService } from '@/core/MetaService.js'; import { SearchService } from '@/core/SearchService.js'; import { FeaturedService } from '@/core/FeaturedService.js'; -import { FunoutTimelineService } from '@/core/FunoutTimelineService.js'; +import { FanoutTimelineService } from '@/core/FanoutTimelineService.js'; import { UtilityService } from '@/core/UtilityService.js'; import { UserBlockingService } from '@/core/UserBlockingService.js'; @@ -194,7 +194,7 @@ export class NoteCreateService implements OnApplicationShutdown { private idService: IdService, private globalEventService: GlobalEventService, private queueService: QueueService, - private funoutTimelineService: FunoutTimelineService, + private fanoutTimelineService: FanoutTimelineService, private noteReadService: NoteReadService, private notificationService: NotificationService, private relayService: RelayService, @@ -843,9 +843,9 @@ export class NoteCreateService implements OnApplicationShutdown { const r = this.redisForTimelines.pipeline(); if (note.channelId) { - this.funoutTimelineService.push(`channelTimeline:${note.channelId}`, note.id, this.config.perChannelMaxNoteCacheCount, r); + this.fanoutTimelineService.push(`channelTimeline:${note.channelId}`, note.id, this.config.perChannelMaxNoteCacheCount, r); - this.funoutTimelineService.push(`userTimelineWithChannel:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r); + this.fanoutTimelineService.push(`userTimelineWithChannel:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r); const channelFollowings = await this.channelFollowingsRepository.find({ where: { @@ -855,9 +855,9 @@ export class NoteCreateService implements OnApplicationShutdown { }); for (const channelFollowing of channelFollowings) { - this.funoutTimelineService.push(`homeTimeline:${channelFollowing.followerId}`, note.id, meta.perUserHomeTimelineCacheMax, r); + this.fanoutTimelineService.push(`homeTimeline:${channelFollowing.followerId}`, note.id, meta.perUserHomeTimelineCacheMax, r); if (note.fileIds.length > 0) { - this.funoutTimelineService.push(`homeTimelineWithFiles:${channelFollowing.followerId}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r); + this.fanoutTimelineService.push(`homeTimelineWithFiles:${channelFollowing.followerId}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r); } } } else { @@ -895,9 +895,9 @@ export class NoteCreateService implements OnApplicationShutdown { if (!following.withReplies) continue; } - this.funoutTimelineService.push(`homeTimeline:${following.followerId}`, note.id, meta.perUserHomeTimelineCacheMax, r); + this.fanoutTimelineService.push(`homeTimeline:${following.followerId}`, note.id, meta.perUserHomeTimelineCacheMax, r); if (note.fileIds.length > 0) { - this.funoutTimelineService.push(`homeTimelineWithFiles:${following.followerId}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r); + this.fanoutTimelineService.push(`homeTimelineWithFiles:${following.followerId}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r); } } @@ -913,36 +913,36 @@ export class NoteCreateService implements OnApplicationShutdown { if (!userListMembership.withReplies) continue; } - this.funoutTimelineService.push(`userListTimeline:${userListMembership.userListId}`, note.id, meta.perUserListTimelineCacheMax, r); + this.fanoutTimelineService.push(`userListTimeline:${userListMembership.userListId}`, note.id, meta.perUserListTimelineCacheMax, r); if (note.fileIds.length > 0) { - this.funoutTimelineService.push(`userListTimelineWithFiles:${userListMembership.userListId}`, note.id, meta.perUserListTimelineCacheMax / 2, r); + this.fanoutTimelineService.push(`userListTimelineWithFiles:${userListMembership.userListId}`, note.id, meta.perUserListTimelineCacheMax / 2, r); } } if (note.visibility !== 'specified' || !note.visibleUserIds.some(v => v === user.id)) { // 自分自身のHTL - this.funoutTimelineService.push(`homeTimeline:${user.id}`, note.id, meta.perUserHomeTimelineCacheMax, r); + this.fanoutTimelineService.push(`homeTimeline:${user.id}`, note.id, meta.perUserHomeTimelineCacheMax, r); if (note.fileIds.length > 0) { - this.funoutTimelineService.push(`homeTimelineWithFiles:${user.id}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r); + this.fanoutTimelineService.push(`homeTimelineWithFiles:${user.id}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r); } } // 自分自身以外への返信 if (note.replyId && note.replyUserId !== note.userId) { - this.funoutTimelineService.push(`userTimelineWithReplies:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r); + this.fanoutTimelineService.push(`userTimelineWithReplies:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r); if (note.visibility === 'public' && note.userHost == null) { - this.funoutTimelineService.push('localTimelineWithReplies', note.id, 300, r); + this.fanoutTimelineService.push('localTimelineWithReplies', note.id, 300, r); } } else { - this.funoutTimelineService.push(`userTimeline:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r); + this.fanoutTimelineService.push(`userTimeline:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r); if (note.fileIds.length > 0) { - this.funoutTimelineService.push(`userTimelineWithFiles:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax / 2 : meta.perRemoteUserUserTimelineCacheMax / 2, r); + this.fanoutTimelineService.push(`userTimelineWithFiles:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax / 2 : meta.perRemoteUserUserTimelineCacheMax / 2, r); } if (note.visibility === 'public' && note.userHost == null) { - this.funoutTimelineService.push('localTimeline', note.id, 1000, r); + this.fanoutTimelineService.push('localTimeline', note.id, 1000, r); if (note.fileIds.length > 0) { - this.funoutTimelineService.push('localTimelineWithFiles', note.id, 500, r); + this.fanoutTimelineService.push('localTimelineWithFiles', note.id, 500, r); } } } diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts index 432887b3b7..29e48aa8ca 100644 --- a/packages/backend/src/core/RoleService.ts +++ b/packages/backend/src/core/RoleService.ts @@ -20,7 +20,7 @@ import { IdService } from '@/core/IdService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; import { ModerationLogService } from '@/core/ModerationLogService.js'; import type { Packed } from '@/misc/json-schema.js'; -import { FunoutTimelineService } from '@/core/FunoutTimelineService.js'; +import { FanoutTimelineService } from '@/core/FanoutTimelineService.js'; import type { OnApplicationShutdown } from '@nestjs/common'; export type RolePolicies = { @@ -108,7 +108,7 @@ export class RoleService implements OnApplicationShutdown { private globalEventService: GlobalEventService, private idService: IdService, private moderationLogService: ModerationLogService, - private funoutTimelineService: FunoutTimelineService, + private fanoutTimelineService: FanoutTimelineService, ) { //this.onMessage = this.onMessage.bind(this); @@ -482,7 +482,7 @@ export class RoleService implements OnApplicationShutdown { const redisPipeline = this.redisForTimelines.pipeline(); for (const role of roles) { - this.funoutTimelineService.push(`roleTimeline:${role.id}`, note.id, 1000, redisPipeline); + this.fanoutTimelineService.push(`roleTimeline:${role.id}`, note.id, 1000, redisPipeline); this.globalEventService.publishRoleTimelineStream(role.id, 'note', note); } diff --git a/packages/backend/src/core/UserFollowingService.ts b/packages/backend/src/core/UserFollowingService.ts index bd7f298021..3062999c08 100644 --- a/packages/backend/src/core/UserFollowingService.ts +++ b/packages/backend/src/core/UserFollowingService.ts @@ -29,7 +29,7 @@ import { CacheService } from '@/core/CacheService.js'; import type { Config } from '@/config.js'; import { AccountMoveService } from '@/core/AccountMoveService.js'; import { UtilityService } from '@/core/UtilityService.js'; -import { FunoutTimelineService } from '@/core/FunoutTimelineService.js'; +import { FanoutTimelineService } from '@/core/FanoutTimelineService.js'; import Logger from '../logger.js'; const logger = new Logger('following/create'); @@ -84,7 +84,7 @@ export class UserFollowingService implements OnModuleInit { private webhookService: WebhookService, private apRendererService: ApRendererService, private accountMoveService: AccountMoveService, - private funoutTimelineService: FunoutTimelineService, + private fanoutTimelineService: FanoutTimelineService, private perUserFollowingChart: PerUserFollowingChart, private instanceChart: InstanceChart, ) { @@ -305,7 +305,7 @@ export class UserFollowingService implements OnModuleInit { } }); - this.funoutTimelineService.purge(`homeTimeline:${follower.id}`); + this.fanoutTimelineService.purge(`homeTimeline:${follower.id}`); } // Publish followed event @@ -374,7 +374,7 @@ export class UserFollowingService implements OnModuleInit { } }); - this.funoutTimelineService.purge(`homeTimeline:${follower.id}`); + this.fanoutTimelineService.purge(`homeTimeline:${follower.id}`); } if (this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee)) { diff --git a/packages/backend/src/server/api/endpoints/antennas/notes.ts b/packages/backend/src/server/api/endpoints/antennas/notes.ts index 29e56b1085..0bf2688b4a 100644 --- a/packages/backend/src/server/api/endpoints/antennas/notes.ts +++ b/packages/backend/src/server/api/endpoints/antennas/notes.ts @@ -12,7 +12,7 @@ import { NoteReadService } from '@/core/NoteReadService.js'; import { DI } from '@/di-symbols.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { IdService } from '@/core/IdService.js'; -import { FunoutTimelineService } from '@/core/FunoutTimelineService.js'; +import { FanoutTimelineService } from '@/core/FanoutTimelineService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; import { ApiError } from '../../error.js'; @@ -71,7 +71,7 @@ export default class extends Endpoint { // eslint- private noteEntityService: NoteEntityService, private queryService: QueryService, private noteReadService: NoteReadService, - private funoutTimelineService: FunoutTimelineService, + private fanoutTimelineService: FanoutTimelineService, private globalEventService: GlobalEventService, ) { super(meta, paramDef, async (ps, me) => { @@ -98,7 +98,7 @@ export default class extends Endpoint { // eslint- this.globalEventService.publishInternalEvent('antennaUpdated', antenna); } - let noteIds = await this.funoutTimelineService.get(`antennaTimeline:${antenna.id}`, untilId, sinceId); + let noteIds = await this.fanoutTimelineService.get(`antennaTimeline:${antenna.id}`, untilId, sinceId); noteIds = noteIds.slice(0, ps.limit); if (noteIds.length === 0) { return []; diff --git a/packages/backend/src/server/api/endpoints/channels/timeline.ts b/packages/backend/src/server/api/endpoints/channels/timeline.ts index 4ca7325f30..f9207199d6 100644 --- a/packages/backend/src/server/api/endpoints/channels/timeline.ts +++ b/packages/backend/src/server/api/endpoints/channels/timeline.ts @@ -12,7 +12,7 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import ActiveUsersChart from '@/core/chart/charts/active-users.js'; import { DI } from '@/di-symbols.js'; import { IdService } from '@/core/IdService.js'; -import { FunoutTimelineService } from '@/core/FunoutTimelineService.js'; +import { FanoutTimelineService } from '@/core/FanoutTimelineService.js'; import { isUserRelated } from '@/misc/is-user-related.js'; import { CacheService } from '@/core/CacheService.js'; import { MetaService } from '@/core/MetaService.js'; @@ -70,7 +70,7 @@ export default class extends Endpoint { // eslint- private idService: IdService, private noteEntityService: NoteEntityService, private queryService: QueryService, - private funoutTimelineService: FunoutTimelineService, + private fanoutTimelineService: FanoutTimelineService, private cacheService: CacheService, private activeUsersChart: ActiveUsersChart, private metaService: MetaService, @@ -99,7 +99,7 @@ export default class extends Endpoint { // eslint- this.cacheService.userMutingsCache.fetch(me.id), ]) : [new Set()]; - let noteIds = await this.funoutTimelineService.get(`channelTimeline:${channel.id}`, untilId, sinceId); + let noteIds = await this.fanoutTimelineService.get(`channelTimeline:${channel.id}`, untilId, sinceId); noteIds = noteIds.slice(0, ps.limit); if (noteIds.length > 0) { diff --git a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts index 408c2fa371..372199844d 100644 --- a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts @@ -14,7 +14,7 @@ import { RoleService } from '@/core/RoleService.js'; import { IdService } from '@/core/IdService.js'; import { isUserRelated } from '@/misc/is-user-related.js'; import { CacheService } from '@/core/CacheService.js'; -import { FunoutTimelineService } from '@/core/FunoutTimelineService.js'; +import { FanoutTimelineService } from '@/core/FanoutTimelineService.js'; import { QueryService } from '@/core/QueryService.js'; import { UserFollowingService } from '@/core/UserFollowingService.js'; import { MetaService } from '@/core/MetaService.js'; @@ -77,7 +77,7 @@ export default class extends Endpoint { // eslint- private activeUsersChart: ActiveUsersChart, private idService: IdService, private cacheService: CacheService, - private funoutTimelineService: FunoutTimelineService, + private fanoutTimelineService: FanoutTimelineService, private queryService: QueryService, private userFollowingService: UserFollowingService, private metaService: MetaService, @@ -120,20 +120,20 @@ export default class extends Endpoint { // eslint- let shouldFallbackToDb = false; if (ps.withFiles) { - const [htlNoteIds, ltlNoteIds] = await this.funoutTimelineService.getMulti([ + const [htlNoteIds, ltlNoteIds] = await this.fanoutTimelineService.getMulti([ `homeTimelineWithFiles:${me.id}`, 'localTimelineWithFiles', ], untilId, sinceId); noteIds = Array.from(new Set([...htlNoteIds, ...ltlNoteIds])); } else if (ps.withReplies) { - const [htlNoteIds, ltlNoteIds, ltlReplyNoteIds] = await this.funoutTimelineService.getMulti([ + const [htlNoteIds, ltlNoteIds, ltlReplyNoteIds] = await this.fanoutTimelineService.getMulti([ `homeTimeline:${me.id}`, 'localTimeline', 'localTimelineWithReplies', ], untilId, sinceId); noteIds = Array.from(new Set([...htlNoteIds, ...ltlNoteIds, ...ltlReplyNoteIds])); } else { - const [htlNoteIds, ltlNoteIds] = await this.funoutTimelineService.getMulti([ + const [htlNoteIds, ltlNoteIds] = await this.fanoutTimelineService.getMulti([ `homeTimeline:${me.id}`, 'localTimeline', ], untilId, sinceId); diff --git a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts index 79baa6b285..7d8dec7b8f 100644 --- a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts @@ -14,7 +14,7 @@ import { RoleService } from '@/core/RoleService.js'; import { IdService } from '@/core/IdService.js'; import { CacheService } from '@/core/CacheService.js'; import { isUserRelated } from '@/misc/is-user-related.js'; -import { FunoutTimelineService } from '@/core/FunoutTimelineService.js'; +import { FanoutTimelineService } from '@/core/FanoutTimelineService.js'; import { QueryService } from '@/core/QueryService.js'; import { MetaService } from '@/core/MetaService.js'; import { MiLocalUser } from '@/models/User.js'; @@ -69,7 +69,7 @@ export default class extends Endpoint { // eslint- private activeUsersChart: ActiveUsersChart, private idService: IdService, private cacheService: CacheService, - private funoutTimelineService: FunoutTimelineService, + private fanoutTimelineService: FanoutTimelineService, private queryService: QueryService, private metaService: MetaService, ) { @@ -107,9 +107,9 @@ export default class extends Endpoint { // eslint- let noteIds: string[]; if (ps.withFiles) { - noteIds = await this.funoutTimelineService.get('localTimelineWithFiles', untilId, sinceId); + noteIds = await this.fanoutTimelineService.get('localTimelineWithFiles', untilId, sinceId); } else { - const [nonReplyNoteIds, replyNoteIds] = await this.funoutTimelineService.getMulti([ + const [nonReplyNoteIds, replyNoteIds] = await this.fanoutTimelineService.getMulti([ 'localTimeline', 'localTimelineWithReplies', ], untilId, sinceId); diff --git a/packages/backend/src/server/api/endpoints/notes/timeline.ts b/packages/backend/src/server/api/endpoints/notes/timeline.ts index 8037d4862f..470abe0b14 100644 --- a/packages/backend/src/server/api/endpoints/notes/timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/timeline.ts @@ -14,7 +14,7 @@ import { DI } from '@/di-symbols.js'; import { IdService } from '@/core/IdService.js'; import { CacheService } from '@/core/CacheService.js'; import { isUserRelated } from '@/misc/is-user-related.js'; -import { FunoutTimelineService } from '@/core/FunoutTimelineService.js'; +import { FanoutTimelineService } from '@/core/FanoutTimelineService.js'; import { UserFollowingService } from '@/core/UserFollowingService.js'; import { MiLocalUser } from '@/models/User.js'; import { MetaService } from '@/core/MetaService.js'; @@ -65,7 +65,7 @@ export default class extends Endpoint { // eslint- private activeUsersChart: ActiveUsersChart, private idService: IdService, private cacheService: CacheService, - private funoutTimelineService: FunoutTimelineService, + private fanoutTimelineService: FanoutTimelineService, private userFollowingService: UserFollowingService, private queryService: QueryService, private metaService: MetaService, @@ -101,7 +101,7 @@ export default class extends Endpoint { // eslint- this.cacheService.userBlockedCache.fetch(me.id), ]); - let noteIds = await this.funoutTimelineService.get(ps.withFiles ? `homeTimelineWithFiles:${me.id}` : `homeTimeline:${me.id}`, untilId, sinceId); + let noteIds = await this.fanoutTimelineService.get(ps.withFiles ? `homeTimelineWithFiles:${me.id}` : `homeTimeline:${me.id}`, untilId, sinceId); noteIds = noteIds.slice(0, ps.limit); let redisTimeline: MiNote[] = []; diff --git a/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts b/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts index dbc3875597..1ac1d37f48 100644 --- a/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts @@ -13,7 +13,7 @@ import { DI } from '@/di-symbols.js'; import { CacheService } from '@/core/CacheService.js'; import { IdService } from '@/core/IdService.js'; import { isUserRelated } from '@/misc/is-user-related.js'; -import { FunoutTimelineService } from '@/core/FunoutTimelineService.js'; +import { FanoutTimelineService } from '@/core/FanoutTimelineService.js'; import { QueryService } from '@/core/QueryService.js'; import { MiLocalUser } from '@/models/User.js'; import { MetaService } from '@/core/MetaService.js'; @@ -81,7 +81,7 @@ export default class extends Endpoint { // eslint- private activeUsersChart: ActiveUsersChart, private cacheService: CacheService, private idService: IdService, - private funoutTimelineService: FunoutTimelineService, + private fanoutTimelineService: FanoutTimelineService, private queryService: QueryService, private metaService: MetaService, ) { @@ -123,7 +123,7 @@ export default class extends Endpoint { // eslint- this.cacheService.userBlockedCache.fetch(me.id), ]); - let noteIds = await this.funoutTimelineService.get(ps.withFiles ? `userListTimelineWithFiles:${list.id}` : `userListTimeline:${list.id}`, untilId, sinceId); + let noteIds = await this.fanoutTimelineService.get(ps.withFiles ? `userListTimelineWithFiles:${list.id}` : `userListTimeline:${list.id}`, untilId, sinceId); noteIds = noteIds.slice(0, ps.limit); let redisTimeline: MiNote[] = []; diff --git a/packages/backend/src/server/api/endpoints/roles/notes.ts b/packages/backend/src/server/api/endpoints/roles/notes.ts index daa9affc20..7010df22c9 100644 --- a/packages/backend/src/server/api/endpoints/roles/notes.ts +++ b/packages/backend/src/server/api/endpoints/roles/notes.ts @@ -11,7 +11,7 @@ import { QueryService } from '@/core/QueryService.js'; import { DI } from '@/di-symbols.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { IdService } from '@/core/IdService.js'; -import { FunoutTimelineService } from '@/core/FunoutTimelineService.js'; +import { FanoutTimelineService } from '@/core/FanoutTimelineService.js'; import { ApiError } from '../../error.js'; export const meta = { @@ -66,7 +66,7 @@ export default class extends Endpoint { // eslint- private idService: IdService, private noteEntityService: NoteEntityService, private queryService: QueryService, - private funoutTimelineService: FunoutTimelineService, + private fanoutTimelineService: FanoutTimelineService, ) { super(meta, paramDef, async (ps, me) => { const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null); @@ -84,7 +84,7 @@ export default class extends Endpoint { // eslint- return []; } - let noteIds = await this.funoutTimelineService.get(`roleTimeline:${role.id}`, untilId, sinceId); + let noteIds = await this.fanoutTimelineService.get(`roleTimeline:${role.id}`, untilId, sinceId); noteIds = noteIds.slice(0, ps.limit); if (noteIds.length === 0) { diff --git a/packages/backend/src/server/api/endpoints/users/notes.ts b/packages/backend/src/server/api/endpoints/users/notes.ts index 2e7d939b12..a775b58f03 100644 --- a/packages/backend/src/server/api/endpoints/users/notes.ts +++ b/packages/backend/src/server/api/endpoints/users/notes.ts @@ -14,7 +14,7 @@ import { CacheService } from '@/core/CacheService.js'; import { IdService } from '@/core/IdService.js'; import { isUserRelated } from '@/misc/is-user-related.js'; import { QueryService } from '@/core/QueryService.js'; -import { FunoutTimelineService } from '@/core/FunoutTimelineService.js'; +import { FanoutTimelineService } from '@/core/FanoutTimelineService.js'; import { MetaService } from '@/core/MetaService.js'; import { ApiError } from '../../error.js'; @@ -71,7 +71,7 @@ export default class extends Endpoint { // eslint- private queryService: QueryService, private cacheService: CacheService, private idService: IdService, - private funoutTimelineService: FunoutTimelineService, + private fanoutTimelineService: FanoutTimelineService, private metaService: MetaService, ) { super(meta, paramDef, async (ps, me) => { @@ -90,9 +90,9 @@ export default class extends Endpoint { // eslint- ]) : [new Set()]; const [noteIdsRes, repliesNoteIdsRes, channelNoteIdsRes] = await Promise.all([ - this.funoutTimelineService.get(ps.withFiles ? `userTimelineWithFiles:${ps.userId}` : `userTimeline:${ps.userId}`, untilId, sinceId), - ps.withReplies ? this.funoutTimelineService.get(`userTimelineWithReplies:${ps.userId}`, untilId, sinceId) : Promise.resolve([]), - ps.withChannelNotes ? this.funoutTimelineService.get(`userTimelineWithChannel:${ps.userId}`, untilId, sinceId) : Promise.resolve([]), + this.fanoutTimelineService.get(ps.withFiles ? `userTimelineWithFiles:${ps.userId}` : `userTimeline:${ps.userId}`, untilId, sinceId), + ps.withReplies ? this.fanoutTimelineService.get(`userTimelineWithReplies:${ps.userId}`, untilId, sinceId) : Promise.resolve([]), + ps.withChannelNotes ? this.fanoutTimelineService.get(`userTimelineWithChannel:${ps.userId}`, untilId, sinceId) : Promise.resolve([]), ]); let noteIds = Array.from(new Set([ From 2ee48ae04da540384214ff0d7c8df2dfb18c88fc Mon Sep 17 00:00:00 2001 From: zyoshoka <107108195+zyoshoka@users.noreply.github.com> Date: Sun, 26 Nov 2023 10:05:56 +0900 Subject: [PATCH 046/435] =?UTF-8?q?fix(backend):=20=E3=82=AE=E3=83=A3?= =?UTF-8?q?=E3=83=A9=E3=83=AA=E3=83=BC=E3=81=AE=E4=BA=BA=E6=B0=97=E3=81=AE?= =?UTF-8?q?=E6=8A=95=E7=A8=BF=E3=81=AE=E9=81=B8=E5=87=BA=E3=81=ABid?= =?UTF-8?q?=E3=82=92=E7=94=A8=E3=81=84=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= =?UTF-8?q?=20(#12448)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/backend/src/core/FeaturedService.ts | 13 ++++++- .../server/api/endpoints/gallery/featured.ts | 37 ++++++++++++++++--- .../api/endpoints/gallery/posts/like.ts | 7 ++++ .../api/endpoints/gallery/posts/unlike.ts | 10 +++++ 4 files changed, 60 insertions(+), 7 deletions(-) diff --git a/packages/backend/src/core/FeaturedService.ts b/packages/backend/src/core/FeaturedService.ts index 9617f83880..507fc464ff 100644 --- a/packages/backend/src/core/FeaturedService.ts +++ b/packages/backend/src/core/FeaturedService.ts @@ -5,11 +5,12 @@ import { Inject, Injectable } from '@nestjs/common'; import * as Redis from 'ioredis'; -import type { MiNote, MiUser } from '@/models/_.js'; +import type { MiGalleryPost, MiNote, MiUser } from '@/models/_.js'; import { DI } from '@/di-symbols.js'; import { bindThis } from '@/decorators.js'; const GLOBAL_NOTES_RANKING_WINDOW = 1000 * 60 * 60 * 24 * 3; // 3日ごと +export const GALLERY_POSTS_RANKING_WINDOW = 1000 * 60 * 60 * 24 * 3; // 3日ごと const PER_USER_NOTES_RANKING_WINDOW = 1000 * 60 * 60 * 24 * 7; // 1週間ごと const HASHTAG_RANKING_WINDOW = 1000 * 60 * 60; // 1時間ごと @@ -79,6 +80,11 @@ export class FeaturedService { return this.updateRankingOf('featuredGlobalNotesRanking', GLOBAL_NOTES_RANKING_WINDOW, noteId, score); } + @bindThis + public updateGalleryPostsRanking(galleryPostId: MiGalleryPost['id'], score = 1): Promise { + return this.updateRankingOf('featuredGalleryPostsRanking', GALLERY_POSTS_RANKING_WINDOW, galleryPostId, score); + } + @bindThis public updateInChannelNotesRanking(channelId: MiNote['channelId'], noteId: MiNote['id'], score = 1): Promise { return this.updateRankingOf(`featuredInChannelNotesRanking:${channelId}`, GLOBAL_NOTES_RANKING_WINDOW, noteId, score); @@ -99,6 +105,11 @@ export class FeaturedService { return this.getRankingOf('featuredGlobalNotesRanking', GLOBAL_NOTES_RANKING_WINDOW, threshold); } + @bindThis + public getGalleryPostsRanking(threshold: number): Promise { + return this.getRankingOf('featuredGalleryPostsRanking', GALLERY_POSTS_RANKING_WINDOW, threshold); + } + @bindThis public getInChannelNotesRanking(channelId: MiNote['channelId'], threshold: number): Promise { return this.getRankingOf(`featuredInChannelNotesRanking:${channelId}`, GLOBAL_NOTES_RANKING_WINDOW, threshold); diff --git a/packages/backend/src/server/api/endpoints/gallery/featured.ts b/packages/backend/src/server/api/endpoints/gallery/featured.ts index cbab3a83a4..cea4234065 100644 --- a/packages/backend/src/server/api/endpoints/gallery/featured.ts +++ b/packages/backend/src/server/api/endpoints/gallery/featured.ts @@ -8,6 +8,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js'; import type { GalleryPostsRepository } from '@/models/_.js'; import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js'; import { DI } from '@/di-symbols.js'; +import { FeaturedService } from '@/core/FeaturedService.js'; export const meta = { tags: ['gallery'], @@ -27,25 +28,49 @@ export const meta = { export const paramDef = { type: 'object', - properties: {}, + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + untilId: { type: 'string', format: 'misskey:id' }, + }, required: [], } as const; @Injectable() export default class extends Endpoint { // eslint-disable-line import/no-default-export + private galleryPostsRankingCache: string[] = []; + private galleryPostsRankingCacheLastFetchedAt = 0; + constructor( @Inject(DI.galleryPostsRepository) private galleryPostsRepository: GalleryPostsRepository, private galleryPostEntityService: GalleryPostEntityService, + private featuredService: FeaturedService, ) { super(meta, paramDef, async (ps, me) => { - const query = this.galleryPostsRepository.createQueryBuilder('post') - .andWhere('post.createdAt > :date', { date: new Date(Date.now() - (1000 * 60 * 60 * 24 * 3)) }) - .andWhere('post.likedCount > 0') - .orderBy('post.likedCount', 'DESC'); + let postIds: string[]; + if (this.galleryPostsRankingCacheLastFetchedAt !== 0 && (Date.now() - this.galleryPostsRankingCacheLastFetchedAt < 1000 * 60 * 30)) { + postIds = this.galleryPostsRankingCache; + } else { + postIds = await this.featuredService.getGalleryPostsRanking(100); + this.galleryPostsRankingCache = postIds; + this.galleryPostsRankingCacheLastFetchedAt = Date.now(); + } - const posts = await query.limit(10).getMany(); + postIds.sort((a, b) => a > b ? -1 : 1); + if (ps.untilId) { + postIds = postIds.filter(id => id < ps.untilId!); + } + postIds = postIds.slice(0, ps.limit); + + if (postIds.length === 0) { + return []; + } + + const query = this.galleryPostsRepository.createQueryBuilder('post') + .where('post.id IN (:...postIds)', { postIds: postIds }); + + const posts = await query.getMany(); return await this.galleryPostEntityService.packMany(posts, me); }); diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/like.ts b/packages/backend/src/server/api/endpoints/gallery/posts/like.ts index 561b2492ab..cc424261b4 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/like.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/like.ts @@ -6,6 +6,7 @@ import { Inject, Injectable } from '@nestjs/common'; import { Endpoint } from '@/server/api/endpoint-base.js'; import type { GalleryLikesRepository, GalleryPostsRepository } from '@/models/_.js'; +import { FeaturedService, GALLERY_POSTS_RANKING_WINDOW } from '@/core/FeaturedService.js'; import { IdService } from '@/core/IdService.js'; import { DI } from '@/di-symbols.js'; import { ApiError } from '../../../error.js'; @@ -57,6 +58,7 @@ export default class extends Endpoint { // eslint- @Inject(DI.galleryLikesRepository) private galleryLikesRepository: GalleryLikesRepository, + private featuredService: FeaturedService, private idService: IdService, ) { super(meta, paramDef, async (ps, me) => { @@ -88,6 +90,11 @@ export default class extends Endpoint { // eslint- userId: me.id, }); + // ランキング更新 + if (Date.now() - this.idService.parse(post.id).date.getTime() < GALLERY_POSTS_RANKING_WINDOW) { + await this.featuredService.updateGalleryPostsRanking(post.id, 1); + } + this.galleryPostsRepository.increment({ id: post.id }, 'likedCount', 1); }); } diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/unlike.ts b/packages/backend/src/server/api/endpoints/gallery/posts/unlike.ts index 832b62282f..caa4d45553 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/unlike.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/unlike.ts @@ -6,6 +6,8 @@ import { Inject, Injectable } from '@nestjs/common'; import { Endpoint } from '@/server/api/endpoint-base.js'; import type { GalleryPostsRepository, GalleryLikesRepository } from '@/models/_.js'; +import { FeaturedService, GALLERY_POSTS_RANKING_WINDOW } from '@/core/FeaturedService.js'; +import { IdService } from '@/core/IdService.js'; import { DI } from '@/di-symbols.js'; import { ApiError } from '../../../error.js'; @@ -49,6 +51,9 @@ export default class extends Endpoint { // eslint- @Inject(DI.galleryLikesRepository) private galleryLikesRepository: GalleryLikesRepository, + + private featuredService: FeaturedService, + private idService: IdService, ) { super(meta, paramDef, async (ps, me) => { const post = await this.galleryPostsRepository.findOneBy({ id: ps.postId }); @@ -68,6 +73,11 @@ export default class extends Endpoint { // eslint- // Delete like await this.galleryLikesRepository.delete(exist.id); + // ランキング更新 + if (Date.now() - this.idService.parse(post.id).date.getTime() < GALLERY_POSTS_RANKING_WINDOW) { + await this.featuredService.updateGalleryPostsRanking(post.id, -1); + } + this.galleryPostsRepository.decrement({ id: post.id }, 'likedCount', 1); }); } From d32631d1590ffe40f051e7abf75faab7bbf9c7da Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Sun, 26 Nov 2023 12:54:23 +0900 Subject: [PATCH 047/435] fix: query error in notes/featured (#12439) --- .../backend/src/server/api/endpoints/notes/featured.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/backend/src/server/api/endpoints/notes/featured.ts b/packages/backend/src/server/api/endpoints/notes/featured.ts index c456874309..bc6cbe242f 100644 --- a/packages/backend/src/server/api/endpoints/notes/featured.ts +++ b/packages/backend/src/server/api/endpoints/notes/featured.ts @@ -64,16 +64,16 @@ export default class extends Endpoint { // eslint- } } - if (noteIds.length === 0) { - return []; - } - noteIds.sort((a, b) => a > b ? -1 : 1); if (ps.untilId) { noteIds = noteIds.filter(id => id < ps.untilId!); } noteIds = noteIds.slice(0, ps.limit); + if (noteIds.length === 0) { + return []; + } + const query = this.notesRepository.createQueryBuilder('note') .where('note.id IN (:...noteIds)', { noteIds: noteIds }) .innerJoinAndSelect('note.user', 'user') From 5bdae9f6d03bbb1fc1cf341b2e6b3e5d15d03fad 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: Sun, 26 Nov 2023 13:04:44 +0900 Subject: [PATCH 048/435] =?UTF-8?q?enhance(frontend):=20=E3=83=AA=E3=82=A2?= =?UTF-8?q?=E3=82=AF=E3=82=B7=E3=83=A7=E3=83=B3=E9=81=B8=E6=8A=9E=E6=99=82?= =?UTF-8?q?=E3=81=AB=E9=9F=B3=E3=82=92=E6=B5=81=E3=81=9B=E3=82=8B=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB=20(#12441)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * (add) リアクション選択時に音を鳴らせるように * Update Changelog * tweak sound * tweak sound --------- Co-authored-by: syuilo --- CHANGELOG.md | 1 + locales/index.d.ts | 1 + locales/ja-JP.yml | 1 + .../frontend/assets/sounds/syuilo/bubble1.mp3 | Bin 0 -> 19328 bytes .../frontend/assets/sounds/syuilo/bubble2.mp3 | Bin 0 -> 19328 bytes packages/frontend/src/components/MkNote.vue | 5 +++++ .../frontend/src/components/MkNoteDetailed.vue | 5 +++++ .../components/MkReactionsViewer.reaction.vue | 7 +++++++ packages/frontend/src/pages/settings/sounds.vue | 3 ++- packages/frontend/src/scripts/sound.ts | 4 +++- packages/frontend/src/store.ts | 4 ++++ 11 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 packages/frontend/assets/sounds/syuilo/bubble1.mp3 create mode 100644 packages/frontend/assets/sounds/syuilo/bubble2.mp3 diff --git a/CHANGELOG.md b/CHANGELOG.md index fdf6709117..7f02d462b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ ### Client - Enhance: 絵文字のオートコンプリート機能強化 #12364 - Enhance: ユーザーのRawデータを表示するページが復活 +- Enhance: リアクション選択時に音を鳴らせるように - fix: 「設定のバックアップ」で一部の項目がバックアップに含まれていなかった問題を修正 - Fix: ウィジェットのジョブキューにて音声の発音方法変更に追従できていなかったのを修正 #12367 - Fix: コードエディタが正しく表示されない問題を修正 diff --git a/locales/index.d.ts b/locales/index.d.ts index 042c7750e1..6e9fe311f1 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -1943,6 +1943,7 @@ export interface Locale { "notification": string; "antenna": string; "channel": string; + "reaction": string; }; "_ago": { "future": string; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 58e0dd0b19..0b051b6190 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1848,6 +1848,7 @@ _sfx: notification: "通知" antenna: "アンテナ受信" channel: "チャンネル通知" + reaction: "リアクション選択時" _ago: future: "未来" diff --git a/packages/frontend/assets/sounds/syuilo/bubble1.mp3 b/packages/frontend/assets/sounds/syuilo/bubble1.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..05b8ef8b10056c66a6e1a9b401d86530ecdc3296 GIT binary patch literal 19328 zcmeZtF=k-^fwB;%0AB_M26hGpWRV1_mAm24+u?9EvC}0|RqOYHmS3 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 literal 0 HcmV?d00001 diff --git a/packages/frontend/assets/sounds/syuilo/bubble2.mp3 b/packages/frontend/assets/sounds/syuilo/bubble2.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..8b4f8df6e9c17daec54da10bb50e790194c767d2 GIT binary patch literal 19328 zcmeZtF=k-^fwB;%0AB_M26hGpWRV1_mAm24+u?9EvC}0|RqOYHmS3 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 literal 0 HcmV?d00001 diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue index 6349df2e30..d047495dc9 100644 --- a/packages/frontend/src/components/MkNote.vue +++ b/packages/frontend/src/components/MkNote.vue @@ -163,6 +163,7 @@ import { focusPrev, focusNext } from '@/scripts/focus.js'; import { checkWordMute } from '@/scripts/check-word-mute.js'; import { userPage } from '@/filters/user.js'; import * as os from '@/os.js'; +import * as sound from '@/scripts/sound.js'; import { defaultStore, noteViewInterruptors } from '@/store.js'; import { reactionPicker } from '@/scripts/reaction-picker.js'; import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm.js'; @@ -336,6 +337,8 @@ function react(viaKeyboard = false): void { pleaseLogin(); showMovedDialog(); if (appearNote.reactionAcceptance === 'likeOnly') { + sound.play('reaction'); + if (props.mock) { return; } @@ -354,6 +357,8 @@ function react(viaKeyboard = false): void { } else { blur(); reactionPicker.show(reactButton.value, reaction => { + sound.play('reaction'); + if (props.mock) { emit('reaction', reaction); return; diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue index d1bc3f676f..d8089ac36f 100644 --- a/packages/frontend/src/components/MkNoteDetailed.vue +++ b/packages/frontend/src/components/MkNoteDetailed.vue @@ -210,6 +210,7 @@ import { checkWordMute } from '@/scripts/check-word-mute.js'; import { userPage } from '@/filters/user.js'; import { notePage } from '@/filters/note.js'; import * as os from '@/os.js'; +import * as sound from '@/scripts/sound.js'; import { defaultStore, noteViewInterruptors } from '@/store.js'; import { reactionPicker } from '@/scripts/reaction-picker.js'; import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm.js'; @@ -369,6 +370,8 @@ function react(viaKeyboard = false): void { pleaseLogin(); showMovedDialog(); if (appearNote.reactionAcceptance === 'likeOnly') { + sound.play('reaction'); + os.api('notes/reactions/create', { noteId: appearNote.id, reaction: '❤️', @@ -383,6 +386,8 @@ function react(viaKeyboard = false): void { } else { blur(); reactionPicker.show(reactButton.value, reaction => { + sound.play('reaction'); + os.api('notes/reactions/create', { noteId: appearNote.id, reaction: reaction, diff --git a/packages/frontend/src/components/MkReactionsViewer.reaction.vue b/packages/frontend/src/components/MkReactionsViewer.reaction.vue index 9a107c3674..65a5c2374e 100644 --- a/packages/frontend/src/components/MkReactionsViewer.reaction.vue +++ b/packages/frontend/src/components/MkReactionsViewer.reaction.vue @@ -28,6 +28,7 @@ import MkReactionEffect from '@/components/MkReactionEffect.vue'; import { claimAchievement } from '@/scripts/achievements.js'; import { defaultStore } from '@/store.js'; import { i18n } from '@/i18n.js'; +import * as sound from '@/scripts/sound.js'; const props = defineProps<{ reaction: string; @@ -59,6 +60,10 @@ async function toggleReaction() { }); if (confirm.canceled) return; + if (oldReaction !== props.reaction) { + sound.play('reaction'); + } + if (mock) { emit('reactionToggled', props.reaction, (props.count - 1)); return; @@ -75,6 +80,8 @@ async function toggleReaction() { } }); } else { + sound.play('reaction'); + if (mock) { emit('reactionToggled', props.reaction, (props.count + 1)); return; diff --git a/packages/frontend/src/pages/settings/sounds.vue b/packages/frontend/src/pages/settings/sounds.vue index cd1707a594..244bb1e0e2 100644 --- a/packages/frontend/src/pages/settings/sounds.vue +++ b/packages/frontend/src/pages/settings/sounds.vue @@ -38,7 +38,7 @@ import { defaultStore } from '@/store.js'; const masterVolume = computed(defaultStore.makeGetterSetter('sound_masterVolume')); -const soundsKeys = ['note', 'noteMy', 'notification', 'antenna', 'channel'] as const; +const soundsKeys = ['note', 'noteMy', 'notification', 'antenna', 'channel', 'reaction'] as const; const sounds = ref>>({ note: defaultStore.reactiveState.sound_note, @@ -46,6 +46,7 @@ const sounds = ref>>({ notification: defaultStore.reactiveState.sound_notification, antenna: defaultStore.reactiveState.sound_antenna, channel: defaultStore.reactiveState.sound_channel, + reaction: defaultStore.reactiveState.sound_reaction, }); async function updated(type: keyof typeof sounds.value, sound) { diff --git a/packages/frontend/src/scripts/sound.ts b/packages/frontend/src/scripts/sound.ts index 2b604bd98a..4d7ef9bdee 100644 --- a/packages/frontend/src/scripts/sound.ts +++ b/packages/frontend/src/scripts/sound.ts @@ -38,6 +38,8 @@ export const soundsTypes = [ 'syuilo/waon', 'syuilo/popo', 'syuilo/triple', + 'syuilo/bubble1', + 'syuilo/bubble2', 'syuilo/poi1', 'syuilo/poi2', 'syuilo/pirori', @@ -77,7 +79,7 @@ export async function loadAudio(file: string, useCache = true) { return audioBuffer; } -export function play(type: 'noteMy' | 'note' | 'antenna' | 'channel' | 'notification') { +export function play(type: 'noteMy' | 'note' | 'antenna' | 'channel' | 'notification' | 'reaction') { const sound = defaultStore.state[`sound_${type}`]; if (_DEV_) console.log('play', type, sound); if (sound.type == null) return; diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts index 12660e9e8d..f2ed4e7c0b 100644 --- a/packages/frontend/src/store.ts +++ b/packages/frontend/src/store.ts @@ -411,6 +411,10 @@ export const defaultStore = markRaw(new Storage('base', { where: 'device', default: { type: 'syuilo/square-pico', volume: 1 }, }, + sound_reaction: { + where: 'device', + default: { type: 'syuilo/bubble2', volume: 1 }, + }, })); // TODO: 他のタブと永続化されたstateを同期 From 755ca9785779eaa120c7e4372b61979362e7ceb5 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: Sun, 26 Nov 2023 13:20:46 +0900 Subject: [PATCH 049/435] =?UTF-8?q?fix(frontend):=20=E9=80=9A=E7=9F=A5?= =?UTF-8?q?=E9=9F=B3=E3=81=8C=E3=81=BB=E3=81=BC=E5=90=8C=E6=99=82=E3=81=AB?= =?UTF-8?q?=E9=B3=B4=E3=81=A3=E3=81=9F=E5=A0=B4=E5=90=88=E3=81=AF=E5=86=8D?= =?UTF-8?q?=E7=94=9F=E3=82=92=E3=83=96=E3=83=AD=E3=83=83=E3=82=AF=E3=81=99?= =?UTF-8?q?=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=EF=BC=88=E9=9F=B3=E5=89=B2?= =?UTF-8?q?=E3=82=8C=E9=98=B2=E6=AD=A2=EF=BC=89=20(#12433)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * (fix) 通知音がダブって音割れしないように * Update Changelog --- CHANGELOG.md | 1 + packages/frontend/src/scripts/sound.ts | 12 ++++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f02d462b2..7a1bdd233d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ - Fix: ウィジェットのジョブキューにて音声の発音方法変更に追従できていなかったのを修正 #12367 - Fix: コードエディタが正しく表示されない問題を修正 - Fix: プロフィールの「ファイル」にセンシティブな画像がある際のデザインを修正 +- Fix: 一度に大量の通知が入った際に通知音が音割れする問題を修正 ### Server - Enhance: MFM `$[ruby ]` が他ソフトウェアと連合されるように diff --git a/packages/frontend/src/scripts/sound.ts b/packages/frontend/src/scripts/sound.ts index 4d7ef9bdee..47ec4171af 100644 --- a/packages/frontend/src/scripts/sound.ts +++ b/packages/frontend/src/scripts/sound.ts @@ -7,6 +7,7 @@ import { defaultStore } from '@/store.js'; const ctx = new AudioContext(); const cache = new Map(); +let canPlay = true; export const soundsTypes = [ null, @@ -82,8 +83,15 @@ export async function loadAudio(file: string, useCache = true) { export function play(type: 'noteMy' | 'note' | 'antenna' | 'channel' | 'notification' | 'reaction') { const sound = defaultStore.state[`sound_${type}`]; if (_DEV_) console.log('play', type, sound); - if (sound.type == null) return; - playFile(sound.type, sound.volume); + if (sound.type == null || !canPlay) return; + + canPlay = false; + playFile(sound.type, sound.volume).then(() => { + // ごく短時間に音が重複しないように + setTimeout(() => { + canPlay = true; + }, 25); + }); } export async function playFile(file: string, volume: number) { From ccb951f11e8cc3c884eef799bef82d09f138d28c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Sun, 26 Nov 2023 14:38:34 +0900 Subject: [PATCH 050/435] chore: create AudioContext when it is needed (#12460) --- packages/frontend/src/scripts/sound.ts | 5 ++++- packages/frontend/src/widgets/WidgetJobQueue.vue | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/scripts/sound.ts b/packages/frontend/src/scripts/sound.ts index 47ec4171af..d28d629227 100644 --- a/packages/frontend/src/scripts/sound.ts +++ b/packages/frontend/src/scripts/sound.ts @@ -5,7 +5,7 @@ import { defaultStore } from '@/store.js'; -const ctx = new AudioContext(); +let ctx: AudioContext; const cache = new Map(); let canPlay = true; @@ -65,6 +65,9 @@ export const soundsTypes = [ ] as const; export async function loadAudio(file: string, useCache = true) { + if (ctx == null) { + ctx = new AudioContext(); + } if (useCache && cache.has(file)) { return cache.get(file)!; } diff --git a/packages/frontend/src/widgets/WidgetJobQueue.vue b/packages/frontend/src/widgets/WidgetJobQueue.vue index fa82997570..8c990e8e49 100644 --- a/packages/frontend/src/widgets/WidgetJobQueue.vue +++ b/packages/frontend/src/widgets/WidgetJobQueue.vue @@ -58,6 +58,7 @@ import { useStream } from '@/stream.js'; import number from '@/filters/number.js'; import * as sound from '@/scripts/sound.js'; import { deepClone } from '@/scripts/clone.js'; +import { defaultStore } from '@/store.js'; const name = 'jobQueue'; @@ -102,7 +103,9 @@ const prev = reactive({} as typeof current); let jammedAudioBuffer: AudioBuffer | null = $ref(null); let jammedSoundNodePlaying: boolean = $ref(false); -sound.loadAudio('syuilo/queue-jammed').then(buf => jammedAudioBuffer = buf); +if (defaultStore.state.sound_masterVolume) { + sound.loadAudio('syuilo/queue-jammed').then(buf => jammedAudioBuffer = buf); +} for (const domain of ['inbox', 'deliver']) { prev[domain] = deepClone(current[domain]); From c9503da8f8e4a67cbe7ba88722b3c3893f9ab4e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?= <46447427+samunohito@users.noreply.github.com> Date: Sun, 26 Nov 2023 16:12:02 +0900 Subject: [PATCH 051/435] =?UTF-8?q?=E3=82=B5=E3=82=A6=E3=83=B3=E3=83=89?= =?UTF-8?q?=E8=A8=AD=E5=AE=9A=E3=81=AB=E3=80=8C=E3=82=B5=E3=82=A6=E3=83=B3?= =?UTF-8?q?=E3=83=89=E3=82=92=E5=87=BA=E5=8A=9B=E3=81=97=E3=81=AA=E3=81=84?= =?UTF-8?q?=E3=80=8D=E3=81=A8=E3=80=8CMisskey=E3=81=8C=E3=82=A2=E3=82=AF?= =?UTF-8?q?=E3=83=86=E3=82=A3=E3=83=96=E3=81=AA=E6=99=82=E3=81=AE=E3=81=BF?= =?UTF-8?q?=E3=82=B5=E3=82=A6=E3=83=B3=E3=83=89=E3=82=92=E5=87=BA=E5=8A=9B?= =?UTF-8?q?=E3=81=99=E3=82=8B=E3=80=8D=E3=82=92=E8=BF=BD=E5=8A=A0=20(#1234?= =?UTF-8?q?2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: osamu <46447427+sam-osamu@users.noreply.github.com> --- CHANGELOG.md | 1 + locales/index.d.ts | 2 ++ locales/ja-JP.yml | 2 ++ packages/frontend/src/pages/settings/sounds.vue | 9 +++++++++ packages/frontend/src/scripts/sound.ts | 17 ++++++++++++++++- packages/frontend/src/store.ts | 8 ++++++++ 6 files changed, 38 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a1bdd233d..bf3fecb5b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,6 +54,7 @@ - 例: `$[unixtime 1701356400]` - Enhance: プラグインでエラーが発生した場合のハンドリングを強化 - Enhance: 細かなUIのブラッシュアップ +- Enhance: サウンド設定に「サウンドを出力しない」と「Misskeyがアクティブな時のみサウンドを出力する」を追加 - Fix: 効果音が再生されるとデバイスで再生している動画や音声が停止する問題を修正 #12339 - Fix: デッキに表示されたチャンネルの表示先チャンネルを切り替えた際、即座に反映されない問題を修正 #12236 - Fix: プラグインでノートの表示を書き換えられない問題を修正 diff --git a/locales/index.d.ts b/locales/index.d.ts index 6e9fe311f1..6097ae130e 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -547,6 +547,8 @@ export interface Locale { "popout": string; "volume": string; "masterVolume": string; + "notUseSound": string; + "useSoundOnlyWhenActive": string; "details": string; "chooseEmoji": string; "unableToProcess": string; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 0b051b6190..1f6695b3e3 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -544,6 +544,8 @@ showInPage: "ページで表示" popout: "ポップアウト" volume: "音量" masterVolume: "マスター音量" +notUseSound: "サウンドを出力しない" +useSoundOnlyWhenActive: "Misskeyがアクティブな時のみサウンドを出力する" details: "詳細" chooseEmoji: "絵文字を選択" unableToProcess: "操作を完了できません" diff --git a/packages/frontend/src/pages/settings/sounds.vue b/packages/frontend/src/pages/settings/sounds.vue index 244bb1e0e2..05e4b0d14c 100644 --- a/packages/frontend/src/pages/settings/sounds.vue +++ b/packages/frontend/src/pages/settings/sounds.vue @@ -5,6 +5,12 @@ SPDX-License-Identifier: AGPL-3.0-only

+
+ +
+ + diff --git a/packages/frontend/src/pages/settings/sounds.vue b/packages/frontend/src/pages/settings/sounds.vue index 05e4b0d14c..e549901f05 100644 --- a/packages/frontend/src/pages/settings/sounds.vue +++ b/packages/frontend/src/pages/settings/sounds.vue @@ -18,11 +18,11 @@ SPDX-License-Identifier: AGPL-3.0-only
- + - + - +
@@ -33,6 +33,8 @@ SPDX-License-Identifier: AGPL-3.0-only @@ -53,6 +69,14 @@ const props = defineProps<{ min-width: 0; } +.cw { + cursor: default; + display: block; + margin: 0; + padding: 0; + overflow-wrap: break-word; +} + .header { margin-bottom: 2px; font-weight: bold; diff --git a/packages/frontend/src/components/MkNoteSimple.vue b/packages/frontend/src/components/MkNoteSimple.vue index a40dcaf003..f3ab6b2723 100644 --- a/packages/frontend/src/components/MkNoteSimple.vue +++ b/packages/frontend/src/components/MkNoteSimple.vue @@ -11,7 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only

- +

diff --git a/packages/frontend/src/components/MkNoteSub.vue b/packages/frontend/src/components/MkNoteSub.vue index 422e9094cc..1e901a1fd6 100644 --- a/packages/frontend/src/components/MkNoteSub.vue +++ b/packages/frontend/src/components/MkNoteSub.vue @@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only

- +

diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue index d163ea2487..07c7213202 100644 --- a/packages/frontend/src/components/MkPostForm.vue +++ b/packages/frontend/src/components/MkPostForm.vue @@ -73,7 +73,7 @@ SPDX-License-Identifier: AGPL-3.0-only - +
From 28cb0fc70b67abf5fe0b1a765df0d97b0b4f4902 Mon Sep 17 00:00:00 2001 From: GrapeApple0 <84321396+GrapeApple0@users.noreply.github.com> Date: Thu, 30 Nov 2023 14:35:56 +0900 Subject: [PATCH 071/435] =?UTF-8?q?enhance:=20=E8=A8=AD=E5=AE=9A=E3=81=97?= =?UTF-8?q?=E3=81=9F=E3=82=BF=E3=82=B0=E3=82=92=E3=83=88=E3=83=AC=E3=83=B3?= =?UTF-8?q?=E3=83=89=E3=81=AB=E8=A1=A8=E7=A4=BA=E3=81=95=E3=81=9B=E3=81=AA?= =?UTF-8?q?=E3=81=84=E3=82=88=E3=81=86=E3=81=AB=E3=81=99=E3=82=8B=E9=A0=85?= =?UTF-8?q?=E7=9B=AE=E3=82=92=E7=AE=A1=E7=90=86=E7=94=BB=E9=9D=A2=E3=81=A7?= =?UTF-8?q?=E8=A8=AD=E5=AE=9A=E3=81=A7=E3=81=8D=E3=82=8B=E3=82=88=E3=81=86?= =?UTF-8?q?=E3=81=AB=20(#12512)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * enhance: hiddenTagsを管理画面で設定できるように * Update locales/ja-JP.yml Co-authored-by: syuilo --------- Co-authored-by: syuilo --- locales/index.d.ts | 2 ++ locales/ja-JP.yml | 2 ++ packages/frontend/src/pages/admin/moderation.vue | 8 ++++++++ 3 files changed, 12 insertions(+) diff --git a/locales/index.d.ts b/locales/index.d.ts index 64ee30410e..d72e7d29f5 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -1030,6 +1030,8 @@ export interface Locale { "sensitiveWords": string; "sensitiveWordsDescription": string; "sensitiveWordsDescription2": string; + "hiddenTags": string; + "hiddenTagsDescription": string; "notesSearchNotAvailable": string; "license": string; "unfavoriteConfirm": string; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index f4daefa978..0f4164652c 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1027,6 +1027,8 @@ resetPasswordConfirm: "パスワードリセットしますか?" sensitiveWords: "センシティブワード" sensitiveWordsDescription: "設定したワードが含まれるノートの公開範囲をホームにします。改行で区切って複数設定できます。" sensitiveWordsDescription2: "スペースで区切るとAND指定になり、キーワードをスラッシュで囲むと正規表現になります。" +hiddenTags: "非表示ハッシュタグ" +hiddenTagsDescription: "設定したタグをトレンドに表示させないようにします。改行で区切って複数設定できます。" notesSearchNotAvailable: "ノート検索は利用できません。" license: "ライセンス" unfavoriteConfirm: "お気に入り解除しますか?" diff --git a/packages/frontend/src/pages/admin/moderation.vue b/packages/frontend/src/pages/admin/moderation.vue index 59ee041386..47f46fe6cf 100644 --- a/packages/frontend/src/pages/admin/moderation.vue +++ b/packages/frontend/src/pages/admin/moderation.vue @@ -39,6 +39,11 @@ SPDX-License-Identifier: AGPL-3.0-only + + + + +
@@ -72,6 +77,7 @@ import FormLink from '@/components/form/link.vue'; let enableRegistration: boolean = $ref(false); let emailRequiredForSignup: boolean = $ref(false); let sensitiveWords: string = $ref(''); +let hiddenTags: string = $ref(''); let preservedUsernames: string = $ref(''); let tosUrl: string | null = $ref(null); let privacyPolicyUrl: string | null = $ref(null); @@ -81,6 +87,7 @@ async function init() { enableRegistration = !meta.disableRegistration; emailRequiredForSignup = meta.emailRequiredForSignup; sensitiveWords = meta.sensitiveWords.join('\n'); + hiddenTags = meta.hiddenTags.join('\n'); preservedUsernames = meta.preservedUsernames.join('\n'); tosUrl = meta.tosUrl; privacyPolicyUrl = meta.privacyPolicyUrl; @@ -93,6 +100,7 @@ function save() { tosUrl, privacyPolicyUrl, sensitiveWords: sensitiveWords.split('\n'), + hiddenTags: hiddenTags.split('\n'), preservedUsernames: preservedUsernames.split('\n'), }).then(() => { fetchInstance(); From 47a10f6a6df1bfbb90af519e1b34996a328d28ca Mon Sep 17 00:00:00 2001 From: Kisaragi <48310258+KisaragiEffective@users.noreply.github.com> Date: Thu, 30 Nov 2023 14:46:16 +0900 Subject: [PATCH 072/435] refactor(frontend): give local variable to explicit type annotation to avoid TS7043 (#12495) * refactor: give local variable to explicit type annotation to avoid TS7043 * chore: fix lint error --- .../src/components/global/MkMisskeyFlavoredMarkdown.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts index c5f247bce9..d4c3ef60aa 100644 --- a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts +++ b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts @@ -103,7 +103,7 @@ export default function(props: MfmProps) { case 'fn': { // TODO: CSSを文字列で組み立てていくと token.props.args.~~~ 経由でCSSインジェクションできるのでよしなにやる - let style; + let style: string | undefined; switch (token.props.name) { case 'tada': { const speed = validTime(token.props.args.speed) ?? '1s'; @@ -268,7 +268,7 @@ export default function(props: MfmProps) { ]); } } - if (style == null) { + if (style === undefined) { return h('span', {}, ['$[', token.props.name, ' ', ...genEl(token.children, scale), ']']); } else { return h('span', { From 4f6e0985423950d1ad1d279cb2c019cf8814828d Mon Sep 17 00:00:00 2001 From: Cocoa Hoto Date: Thu, 30 Nov 2023 14:47:08 +0900 Subject: [PATCH 073/435] fix(docker): cannot build docker image on some environments (#12494) --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 028a3976d2..38aa5bc7b3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -67,8 +67,8 @@ RUN apt-get update \ && corepack enable \ && groupadd -g "${GID}" misskey \ && useradd -l -u "${UID}" -g "${GID}" -m -d /misskey misskey \ - && find / -type d -path /proc -prune -o -type f -perm /u+s -ignore_readdir_race -exec chmod u-s {} \; \ - && find / -type d -path /proc -prune -o -type f -perm /g+s -ignore_readdir_race -exec chmod g-s {} \; \ + && find / -type d -path /sys -prune -o -type d -path /proc -prune -o -type f -perm /u+s -ignore_readdir_race -exec chmod u-s {} \; \ + && find / -type d -path /sys -prune -o -type d -path /proc -prune -o -type f -perm /g+s -ignore_readdir_race -exec chmod g-s {} \; \ && apt-get clean \ && rm -rf /var/lib/apt/lists From 22d6fa1fdf1dd4b61673d10cac6ca866dd5f26d8 Mon Sep 17 00:00:00 2001 From: yukineko <27853966+hideki0403@users.noreply.github.com> Date: Thu, 30 Nov 2023 14:48:02 +0900 Subject: [PATCH 074/435] =?UTF-8?q?enhance(dev):=20=E9=96=8B=E7=99=BA?= =?UTF-8?q?=E3=83=A2=E3=83=BC=E3=83=89=E6=99=82=E3=81=ABlocale=E3=81=A8?= =?UTF-8?q?=E5=9E=8B=E5=AE=9A=E7=BE=A9=E3=81=8C=E8=87=AA=E5=8B=95=E7=9A=84?= =?UTF-8?q?=E3=81=AB=E5=86=8D=E7=94=9F=E6=88=90=E3=81=95=E3=82=8C=E3=82=8B?= =?UTF-8?q?=E3=82=88=E3=81=86=E3=81=AB=20(#12481)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * enhance: localeを任意のタイミングでリビルドできるように * enhance: localeも監視し、必要であればlocaleをリビルドするように * feat: devモードの時のみナビゲーションバーからキャッシュクリアができるように * refactor: キャッシュクリア部分を共通化 * fix: localesのファイル変更イベントが取れないのを修正 * fix: replaceAllでコケるのを修正 * change: 開発モードに関係なくナビゲーションバーからキャッシュクリアできるように * refactor: 必要のないリビルドをしないように * update: CHANGELOG.md --------- Co-authored-by: syuilo --- CHANGELOG.md | 1 + locales/generateDTS.js | 12 ++++ locales/index.d.ts | 1 + locales/index.js | 58 ++++++++++--------- packages/frontend/src/navbar.ts | 8 +++ .../frontend/src/pages/settings/index.vue | 12 +--- packages/frontend/src/scripts/clear-cache.ts | 14 +++++ scripts/build-assets.mjs | 18 +++--- 8 files changed, 80 insertions(+), 44 deletions(-) create mode 100644 packages/frontend/src/scripts/clear-cache.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a41c2cef4..db26ffc8ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ - Enhance: ユーザーのRawデータを表示するページが復活 - Enhance: リアクション選択時に音を鳴らせるように - Enhance: サウンドにドライブのファイルを使用できるように +- Enhance: ナビゲーションバーに項目「キャッシュを削除」を追加 - Enhance: Shareページで投稿を完了すると、親ウィンドウ(親フレーム)にpostMessageするように - Enhance: チャンネル、クリップ、ページ、Play、ギャラリーにURLのコピーボタンを設置 #11305 - Enhance: ノートプレビューに「内容を隠す」が反映されるように diff --git a/locales/generateDTS.js b/locales/generateDTS.js index 7af773f3b1..d3afdd6e15 100644 --- a/locales/generateDTS.js +++ b/locales/generateDTS.js @@ -56,6 +56,18 @@ export default function generateDTS() { ts.NodeFlags.Const | ts.NodeFlags.Ambient | ts.NodeFlags.ContextFlags, ), ), + ts.factory.createFunctionDeclaration( + [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)], + undefined, + ts.factory.createIdentifier('build'), + undefined, + [], + ts.factory.createTypeReferenceNode( + ts.factory.createIdentifier('Locale'), + undefined, + ), + undefined, + ), ts.factory.createExportDefault(ts.factory.createIdentifier('locales')), ]; const printed = ts.createPrinter({ diff --git a/locales/index.d.ts b/locales/index.d.ts index d72e7d29f5..6036c6fa66 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -2505,4 +2505,5 @@ export interface Locale { declare const locales: { [lang: string]: Locale; }; +export function build(): Locale; export default locales; diff --git a/locales/index.js b/locales/index.js index 67a406d98d..650e552337 100644 --- a/locales/index.js +++ b/locales/index.js @@ -51,33 +51,37 @@ const primaries = { // 何故か文字列にバックスペース文字が混入することがあり、YAMLが壊れるので取り除く const clean = (text) => text.replace(new RegExp(String.fromCodePoint(0x08), 'g'), ''); -const locales = languages.reduce((a, c) => (a[c] = yaml.load(clean(fs.readFileSync(new URL(`${c}.yml`, import.meta.url), 'utf-8'))) || {}, a), {}); +export function build() { + const locales = languages.reduce((a, c) => (a[c] = yaml.load(clean(fs.readFileSync(new URL(`${c}.yml`, import.meta.url), 'utf-8'))) || {}, a), {}); -// 空文字列が入ることがあり、フォールバックが動作しなくなるのでプロパティごと消す -const removeEmpty = (obj) => { - for (const [k, v] of Object.entries(obj)) { - if (v === '') { - delete obj[k]; - } else if (typeof v === 'object') { - removeEmpty(v); + // 空文字列が入ることがあり、フォールバックが動作しなくなるのでプロパティごと消す + const removeEmpty = (obj) => { + for (const [k, v] of Object.entries(obj)) { + if (v === '') { + delete obj[k]; + } else if (typeof v === 'object') { + removeEmpty(v); + } } - } - return obj; -}; -removeEmpty(locales); + return obj; + }; + removeEmpty(locales); -export default Object.entries(locales) - .reduce((a, [k ,v]) => (a[k] = (() => { - const [lang] = k.split('-'); - switch (k) { - case 'ja-JP': return v; - case 'ja-KS': - case 'en-US': return merge(locales['ja-JP'], v); - default: return merge( - locales['ja-JP'], - locales['en-US'], - locales[`${lang}-${primaries[lang]}`] ?? {}, - v - ); - } - })(), a), {}); + return Object.entries(locales) + .reduce((a, [k, v]) => (a[k] = (() => { + const [lang] = k.split('-'); + switch (k) { + case 'ja-JP': return v; + case 'ja-KS': + case 'en-US': return merge(locales['ja-JP'], v); + default: return merge( + locales['ja-JP'], + locales['en-US'], + locales[`${lang}-${primaries[lang]}`] ?? {}, + v + ); + } + })(), a), {}); +} + +export default build(); diff --git a/packages/frontend/src/navbar.ts b/packages/frontend/src/navbar.ts index f0ed773f82..78a0945ddb 100644 --- a/packages/frontend/src/navbar.ts +++ b/packages/frontend/src/navbar.ts @@ -12,6 +12,7 @@ import * as os from '@/os.js'; import { i18n } from '@/i18n.js'; import { ui } from '@/config.js'; import { unisonReload } from '@/scripts/unison-reload.js'; +import { clearCache } from './scripts/clear-cache.js'; export const navbarItemDef = reactive({ notifications: { @@ -171,4 +172,11 @@ export const navbarItemDef = reactive({ show: computed(() => $i != null), to: `/@${$i?.username}`, }, + cacheClear: { + title: i18n.ts.cacheClear, + icon: 'ti ti-trash', + action: (ev) => { + clearCache(); + }, + }, }); diff --git a/packages/frontend/src/pages/settings/index.vue b/packages/frontend/src/pages/settings/index.vue index 361a6c8c78..5a1a9aedb3 100644 --- a/packages/frontend/src/pages/settings/index.vue +++ b/packages/frontend/src/pages/settings/index.vue @@ -33,13 +33,11 @@ import { i18n } from '@/i18n.js'; import MkInfo from '@/components/MkInfo.vue'; import MkSuperMenu from '@/components/MkSuperMenu.vue'; import { signout, $i } from '@/account.js'; -import { unisonReload } from '@/scripts/unison-reload.js'; +import { clearCache } from '@/scripts/clear-cache.js'; import { instance } from '@/instance.js'; import { useRouter } from '@/router.js'; import { definePageMetadata, provideMetadataReceiver } from '@/scripts/page-metadata.js'; import * as os from '@/os.js'; -import { miLocalStorage } from '@/local-storage.js'; -import { fetchCustomEmojis } from '@/custom-emojis.js'; const indexInfo = { title: i18n.ts.settings, @@ -182,13 +180,7 @@ const menuDef = computed(() => [{ icon: 'ti ti-trash', text: i18n.ts.clearCache, action: async () => { - os.waiting(); - miLocalStorage.removeItem('locale'); - miLocalStorage.removeItem('theme'); - miLocalStorage.removeItem('emojis'); - miLocalStorage.removeItem('lastEmojisFetchedAt'); - await fetchCustomEmojis(true); - unisonReload(); + await clearCache(); }, }, { type: 'button', diff --git a/packages/frontend/src/scripts/clear-cache.ts b/packages/frontend/src/scripts/clear-cache.ts new file mode 100644 index 0000000000..5f27254b8a --- /dev/null +++ b/packages/frontend/src/scripts/clear-cache.ts @@ -0,0 +1,14 @@ +import { unisonReload } from '@/scripts/unison-reload.js'; +import * as os from '@/os.js'; +import { miLocalStorage } from '@/local-storage.js'; +import { fetchCustomEmojis } from '@/custom-emojis.js'; + +export async function clearCache() { + os.waiting(); + miLocalStorage.removeItem('locale'); + miLocalStorage.removeItem('theme'); + miLocalStorage.removeItem('emojis'); + miLocalStorage.removeItem('lastEmojisFetchedAt'); + await fetchCustomEmojis(true); + unisonReload(); +} diff --git a/scripts/build-assets.mjs b/scripts/build-assets.mjs index 1ffcec8aa3..f8f09ec2fb 100644 --- a/scripts/build-assets.mjs +++ b/scripts/build-assets.mjs @@ -9,10 +9,12 @@ import cssnano from 'cssnano'; import postcss from 'postcss'; import * as terser from 'terser'; -import locales from '../locales/index.js'; +import { build as buildLocales } from '../locales/index.js'; import generateDTS from '../locales/generateDTS.js'; import meta from '../package.json' assert { type: "json" }; +let locales = buildLocales(); + async function copyFrontendFonts() { await fs.cp('./packages/frontend/node_modules/three/examples/fonts', './built/_frontend_dist_/fonts', { dereference: true, recursive: true }); } @@ -89,10 +91,12 @@ async function build() { await build(); if (process.argv.includes("--watch")) { - const watcher = fs.watch('./packages', { recursive: true }); - for await (const event of watcher) { - if (/^[a-z]+\/src/.test(event.filename)) { - await build(); - } - } + const watcher = fs.watch('./locales'); + for await (const event of watcher) { + const filename = event.filename?.replaceAll('\\', '/'); + if (/^[a-z]+-[A-Z]+\.yml/.test(filename)) { + locales = buildLocales(); + await copyFrontendLocales() + } + } } From b05d71fabff55ac5653994a1188c6db88048e8ee 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: Thu, 30 Nov 2023 14:49:26 +0900 Subject: [PATCH 075/435] =?UTF-8?q?feat(frontend):=20=E4=BB=8A=E6=97=A5?= =?UTF-8?q?=E8=AA=95=E7=94=9F=E6=97=A5=E3=81=AE=E3=83=95=E3=82=A9=E3=83=AD?= =?UTF-8?q?=E3=83=BC=E4=B8=AD=E3=81=AE=E3=83=A6=E3=83=BC=E3=82=B6=E3=83=BC?= =?UTF-8?q?=E3=82=92=E4=B8=80=E8=A6=A7=E8=A1=A8=E7=A4=BA=E3=81=A7=E3=81=8D?= =?UTF-8?q?=E3=82=8B=E3=82=A6=E3=82=A3=E3=82=B8=E3=82=A7=E3=83=83=E3=83=88?= =?UTF-8?q?=E3=82=92=E8=BF=BD=E5=8A=A0=20(#12450)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * (add) 今日誕生日のフォロイー一覧表示 * Update Changelog * Update Changelog * 実装漏れ * create index * (fix) index --- CHANGELOG.md | 1 + locales/index.d.ts | 1 + locales/ja-JP.yml | 1 + .../migration/1700902349231-add-bday-index.js | 16 +++ packages/backend/src/models/UserProfile.ts | 1 + .../server/api/endpoints/users/following.ts | 23 ++++ .../src/widgets/WidgetBirthdayFollowings.vue | 127 ++++++++++++++++++ packages/frontend/src/widgets/index.ts | 2 + 8 files changed, 172 insertions(+) create mode 100644 packages/backend/migration/1700902349231-add-bday-index.js create mode 100644 packages/frontend/src/widgets/WidgetBirthdayFollowings.vue diff --git a/CHANGELOG.md b/CHANGELOG.md index db26ffc8ee..e40c5f0fd3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ - Fix: MFM `$[unixtime ]` に不正な値を入力した際に発生する各種エラーを修正 ### Client +- Feat: 今日誕生日のフォロー中のユーザーを一覧表示できるウィジェットを追加 - Enhance: 絵文字のオートコンプリート機能強化 #12364 - Enhance: ユーザーのRawデータを表示するページが復活 - Enhance: リアクション選択時に音を鳴らせるように diff --git a/locales/index.d.ts b/locales/index.d.ts index 6036c6fa66..d462816494 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -2110,6 +2110,7 @@ export interface Locale { "chooseList": string; }; "clicker": string; + "birthdayFollowings": string; }; "_cw": { "hide": string; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 0f4164652c..aa3cdf0750 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -2014,6 +2014,7 @@ _widgets: _userList: chooseList: "リストを選択" clicker: "クリッカー" + birthdayFollowings: "今日誕生日のユーザー" _cw: hide: "隠す" diff --git a/packages/backend/migration/1700902349231-add-bday-index.js b/packages/backend/migration/1700902349231-add-bday-index.js new file mode 100644 index 0000000000..251526fc26 --- /dev/null +++ b/packages/backend/migration/1700902349231-add-bday-index.js @@ -0,0 +1,16 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class AddBdayIndex1700902349231 { + name = 'AddBdayIndex1700902349231' + + async up(queryRunner) { + await queryRunner.query(`CREATE INDEX "IDX_de22cd2b445eee31ae51cdbe99" ON "user_profile" (SUBSTR("birthday", 6, 5))`); + } + + async down(queryRunner) { + await queryRunner.query(`DROP INDEX "public"."IDX_de22cd2b445eee31ae51cdbe99"`); + } +} diff --git a/packages/backend/src/models/UserProfile.ts b/packages/backend/src/models/UserProfile.ts index 8a43b60039..6659a01412 100644 --- a/packages/backend/src/models/UserProfile.ts +++ b/packages/backend/src/models/UserProfile.ts @@ -29,6 +29,7 @@ export class MiUserProfile { }) public location: string | null; + @Index() @Column('char', { length: 10, nullable: true, comment: 'The birthday (YYYY-MM-DD) of the User.', diff --git a/packages/backend/src/server/api/endpoints/users/following.ts b/packages/backend/src/server/api/endpoints/users/following.ts index 03487275a3..ead7ba8c40 100644 --- a/packages/backend/src/server/api/endpoints/users/following.ts +++ b/packages/backend/src/server/api/endpoints/users/following.ts @@ -42,6 +42,12 @@ export const meta = { code: 'FORBIDDEN', id: 'f6cdb0df-c19f-ec5c-7dbb-0ba84a1f92ba', }, + + birthdayInvalid: { + message: 'Birthday date format is invalid.', + code: 'BIRTHDAY_DATE_FORMAT_INVALID', + id: 'a2b007b9-4782-4eba-abd3-93b05ed4130d', + }, }, } as const; @@ -59,6 +65,8 @@ export const paramDef = { nullable: true, description: 'The local host is represented with `null`.', }, + + birthday: { type: 'string', nullable: true }, }, anyOf: [ { required: ['userId'] }, @@ -117,6 +125,21 @@ export default class extends Endpoint { // eslint- .andWhere('following.followerId = :userId', { userId: user.id }) .innerJoinAndSelect('following.followee', 'followee'); + if (ps.birthday) { + try { + const d = new Date(ps.birthday); + d.setHours(0, 0, 0, 0); + const birthday = `${(d.getMonth() + 1).toString().padStart(2, '0')}-${d.getDate().toString().padStart(2, '0')}`; + const birthdayUserQuery = this.userProfilesRepository.createQueryBuilder('user_profile'); + birthdayUserQuery.select('user_profile.userId') + .where(`SUBSTR(user_profile.birthday, 6, 5) = '${birthday}'`); + + query.andWhere(`following.followeeId IN (${ birthdayUserQuery.getQuery() })`); + } catch (err) { + throw new ApiError(meta.errors.birthdayInvalid); + } + } + const followings = await query .limit(ps.limit) .getMany(); diff --git a/packages/frontend/src/widgets/WidgetBirthdayFollowings.vue b/packages/frontend/src/widgets/WidgetBirthdayFollowings.vue new file mode 100644 index 0000000000..7c4455516d --- /dev/null +++ b/packages/frontend/src/widgets/WidgetBirthdayFollowings.vue @@ -0,0 +1,127 @@ + + + + + + + diff --git a/packages/frontend/src/widgets/index.ts b/packages/frontend/src/widgets/index.ts index 405c49ab06..36925e1bd8 100644 --- a/packages/frontend/src/widgets/index.ts +++ b/packages/frontend/src/widgets/index.ts @@ -33,6 +33,7 @@ export default function(app: App) { app.component('WidgetAichan', defineAsyncComponent(() => import('./WidgetAichan.vue'))); app.component('WidgetUserList', defineAsyncComponent(() => import('./WidgetUserList.vue'))); app.component('WidgetClicker', defineAsyncComponent(() => import('./WidgetClicker.vue'))); + app.component('WidgetBirthdayFollowings', defineAsyncComponent(() => import('./WidgetBirthdayFollowings.vue'))); } export const widgets = [ @@ -63,4 +64,5 @@ export const widgets = [ 'aichan', 'userList', 'clicker', + 'birthdayFollowings', ]; From e500fe2586cdf9a60ac75b45f33be99dfd4122bf Mon Sep 17 00:00:00 2001 From: Srgr0 <66754887+Srgr0@users.noreply.github.com> Date: Thu, 30 Nov 2023 14:59:42 +0900 Subject: [PATCH 076/435] =?UTF-8?q?=E7=B5=B5=E6=96=87=E5=AD=97=E8=A9=B3?= =?UTF-8?q?=E7=B4=B0=E3=83=9A=E3=83=BC=E3=82=B8=E3=81=AB=E8=A8=98=E8=BC=89?= =?UTF-8?q?=E3=81=99=E3=82=8B=E6=83=85=E5=A0=B1=E3=82=92=E8=BF=BD=E5=8A=A0?= =?UTF-8?q?=20(#12417)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update emojis.emoji.vue * Update CHANGELOG.md --------- Co-authored-by: syuilo --- CHANGELOG.md | 1 + packages/frontend/src/pages/emojis.emoji.vue | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e40c5f0fd3..d32b46f63d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ - Enhance: ノートプレビューに「内容を隠す」が反映されるように - fix: 「設定のバックアップ」で一部の項目がバックアップに含まれていなかった問題を修正 - Fix: ウィジェットのジョブキューにて音声の発音方法変更に追従できていなかったのを修正 #12367 +- Enhance: 絵文字の詳細ページに記載される情報を追加 - Fix: コードエディタが正しく表示されない問題を修正 - Fix: プロフィールの「ファイル」にセンシティブな画像がある際のデザインを修正 - Fix: 一度に大量の通知が入った際に通知音が音割れする問題を修正 diff --git a/packages/frontend/src/pages/emojis.emoji.vue b/packages/frontend/src/pages/emojis.emoji.vue index 9aaa7890a9..9ba9047ca3 100644 --- a/packages/frontend/src/pages/emojis.emoji.vue +++ b/packages/frontend/src/pages/emojis.emoji.vue @@ -46,7 +46,7 @@ function menu(ev) { os.apiGet('emoji', { name: props.emoji.name }).then(res => { os.alert({ type: 'info', - text: `License: ${res.license}`, + text: `Name: ${res.name}\nAliases: ${res.aliases.join(' ')}\nCategory: ${res.category}\nisSensitive: ${res.isSensitive}\nlocalOnly: ${res.localOnly}\nLicense: ${res.license}\nURL: ${res.url}`, }); }); }, From ca424df80e3072ee5f3971f0c3e97e7d3f34b57c Mon Sep 17 00:00:00 2001 From: yupix Date: Thu, 30 Nov 2023 15:56:25 +0900 Subject: [PATCH 077/435] =?UTF-8?q?fix:=20invite=E7=B3=BB=E3=81=AE?= =?UTF-8?q?=E6=88=BB=E3=82=8A=E5=80=A4=E3=81=8C=E9=96=93=E9=81=95=E3=81=A3?= =?UTF-8?q?=E3=81=A6=E3=81=84=E3=82=8B=20close=20#12517=20(#12518)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/server/api/endpoints/admin/invite/create.ts | 8 +------- .../backend/src/server/api/endpoints/admin/invite/list.ts | 1 + .../backend/src/server/api/endpoints/invite/create.ts | 8 +------- packages/backend/src/server/api/endpoints/invite/list.ts | 2 +- 4 files changed, 4 insertions(+), 15 deletions(-) diff --git a/packages/backend/src/server/api/endpoints/admin/invite/create.ts b/packages/backend/src/server/api/endpoints/admin/invite/create.ts index 4a22fd4824..c6ee45735e 100644 --- a/packages/backend/src/server/api/endpoints/admin/invite/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/invite/create.ts @@ -33,13 +33,7 @@ export const meta = { items: { type: 'object', optional: false, nullable: false, - properties: { - code: { - type: 'string', - optional: false, nullable: false, - example: 'GR6S02ERUA5VR', - }, - }, + ref: 'InviteCode', }, }, } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/invite/list.ts b/packages/backend/src/server/api/endpoints/admin/invite/list.ts index f25d3fcb33..ff57940d48 100644 --- a/packages/backend/src/server/api/endpoints/admin/invite/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/invite/list.ts @@ -21,6 +21,7 @@ export const meta = { items: { type: 'object', optional: false, nullable: false, + ref: 'InviteCode', }, }, } as const; diff --git a/packages/backend/src/server/api/endpoints/invite/create.ts b/packages/backend/src/server/api/endpoints/invite/create.ts index 94836283fa..d82fa50e4f 100644 --- a/packages/backend/src/server/api/endpoints/invite/create.ts +++ b/packages/backend/src/server/api/endpoints/invite/create.ts @@ -31,13 +31,7 @@ export const meta = { res: { type: 'object', optional: false, nullable: false, - properties: { - code: { - type: 'string', - optional: false, nullable: false, - example: 'GR6S02ERUA5VR', - }, - }, + ref: 'InviteCode', }, } as const; diff --git a/packages/backend/src/server/api/endpoints/invite/list.ts b/packages/backend/src/server/api/endpoints/invite/list.ts index 06139b6806..2107516ce4 100644 --- a/packages/backend/src/server/api/endpoints/invite/list.ts +++ b/packages/backend/src/server/api/endpoints/invite/list.ts @@ -9,7 +9,6 @@ import type { RegistrationTicketsRepository } from '@/models/_.js'; import { InviteCodeEntityService } from '@/core/entities/InviteCodeEntityService.js'; import { QueryService } from '@/core/QueryService.js'; import { DI } from '@/di-symbols.js'; -import { ApiError } from '../../error.js'; export const meta = { tags: ['meta'], @@ -23,6 +22,7 @@ export const meta = { items: { type: 'object', optional: false, nullable: false, + ref: 'InviteCode', }, }, } as const; From 749befdf63cfe12ac328546d21d26c7cb9445a20 Mon Sep 17 00:00:00 2001 From: Marie Date: Fri, 1 Dec 2023 00:29:26 +0100 Subject: [PATCH 078/435] chore: up dev version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1207e18028..df95e29ad5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sharkey", - "version": "2023.11.2.beta1", + "version": "2023.12.0.beta1", "codename": "shonk", "repository": { "type": "git", From 5cd4c36cad1fa38080f2b596b936d6b44db45cc7 Mon Sep 17 00:00:00 2001 From: nullnyat Date: Fri, 1 Dec 2023 11:19:33 +0900 Subject: [PATCH 079/435] rename docker-compose.yml.example to docker-compose_example.yml (#12530) * rename docker-compose.yml.example to docker-compose_example.yml * fix: dockle.yml --- .github/workflows/dockle.yml | 2 +- docker-compose.yml.example => docker-compose_example.yml | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename docker-compose.yml.example => docker-compose_example.yml (100%) diff --git a/.github/workflows/dockle.yml b/.github/workflows/dockle.yml index edb18b04da..eee7a78fed 100644 --- a/.github/workflows/dockle.yml +++ b/.github/workflows/dockle.yml @@ -20,7 +20,7 @@ jobs: sudo dpkg -i dockle.deb - run: | cp .config/docker_example.env .config/docker.env - cp ./docker-compose.yml.example ./docker-compose.yml + cp ./docker-compose_example.yml ./docker-compose.yml - run: | docker compose up -d web docker tag "$(docker compose images web | awk 'OFS=":" {print $4}' | tail -n +2)" misskey-web:latest diff --git a/docker-compose.yml.example b/docker-compose_example.yml similarity index 100% rename from docker-compose.yml.example rename to docker-compose_example.yml From ad5a6c1e41806da46232e2b604b55d79d905959a Mon Sep 17 00:00:00 2001 From: Marie Date: Fri, 1 Dec 2023 14:51:48 +0100 Subject: [PATCH 080/435] fix: reactions escaping view in note view --- packages/frontend/src/components/MkNoteDetailed.vue | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue index 4487582562..30198d2a6a 100644 --- a/packages/frontend/src/components/MkNoteDetailed.vue +++ b/packages/frontend/src/components/MkNoteDetailed.vue @@ -744,7 +744,8 @@ function animatedMFM() { z-index: 1; margin-top: 0.4em; width: max-content; - min-width: max-content; + min-width: min-content; + max-width: fit-content; } .replyTo { From c927d6824c3003078410e5cf38d394544accb711 Mon Sep 17 00:00:00 2001 From: Qwreey Date: Sat, 2 Dec 2023 09:28:00 +0900 Subject: [PATCH 081/435] Fix: missing receiver warn is not disappear (#12538) --- packages/frontend/src/components/MkPostForm.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue index 07c7213202..9b04f5165c 100644 --- a/packages/frontend/src/components/MkPostForm.vue +++ b/packages/frontend/src/components/MkPostForm.vue @@ -366,8 +366,8 @@ function checkMissingMention() { return; } } - hasNotSpecifiedMentions = false; } + hasNotSpecifiedMentions = false; } function addMissingMention() { From 1a4bff769825f8b7319c0f86660d78d049023229 Mon Sep 17 00:00:00 2001 From: Insert5StarName Date: Sat, 2 Dec 2023 01:39:29 +0100 Subject: [PATCH 082/435] upd: rework threading/post ui 1/2 Co-authored-by: Gaspard Wierzbinski Co-authored-by: Marie --- .../src/components/MkInstanceTicker.vue | 49 +++--- packages/frontend/src/components/MkNote.vue | 49 +++--- .../src/components/MkNoteDetailed.vue | 69 ++++++-- .../frontend/src/components/MkNoteHeader.vue | 153 +++++++++++++++++- .../frontend/src/components/MkNoteSimple.vue | 2 +- .../frontend/src/components/MkNoteSub.vue | 80 +++++++-- .../frontend/src/pages/settings/general.vue | 2 + packages/frontend/src/store.ts | 4 + 8 files changed, 327 insertions(+), 81 deletions(-) diff --git a/packages/frontend/src/components/MkInstanceTicker.vue b/packages/frontend/src/components/MkInstanceTicker.vue index f0650e48f1..4e2856388e 100644 --- a/packages/frontend/src/components/MkInstanceTicker.vue +++ b/packages/frontend/src/components/MkInstanceTicker.vue @@ -35,51 +35,48 @@ const faviconUrl = $computed(() => props.instance ? getProxiedImageUrlNullable(p const themeColor = instance.themeColor ?? '#777777'; const bg = { - background: `linear-gradient(90deg, ${themeColor}, ${themeColor}00)`, + //background: `linear-gradient(90deg, ${themeColor}, ${themeColor}00)`, + background: `${themeColor}`, }; diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue index 4da8f16df1..869164273e 100644 --- a/packages/frontend/src/components/MkNote.vue +++ b/packages/frontend/src/components/MkNote.vue @@ -47,11 +47,14 @@ SPDX-License-Identifier: AGPL-3.0-only
-
- -
- - +
+
+ +
+ +
+
+

@@ -60,7 +63,6 @@ SPDX-License-Identifier: AGPL-3.0-only

({{ i18n.ts.private }}) - -
-
- {{ i18n.ts.loadConversation }} -
- +
+ {{ i18n.ts.loadConversation }}
-
@@ -43,15 +39,29 @@ SPDX-License-Identifier: AGPL-3.0-only
+ +
-
-
- - - - bot +
+
+
+ + + + bot + + + +
+
+
+
+
+
@@ -61,9 +71,8 @@ SPDX-License-Identifier: AGPL-3.0-only
+
-
-
@@ -73,7 +82,6 @@ SPDX-License-Identifier: AGPL-3.0-only

({{ i18n.ts.private }}) - diff --git a/packages/frontend/src/components/MkNoteHeader.vue b/packages/frontend/src/components/MkNoteHeader.vue index 6121db3f8f..9984c3774d 100644 --- a/packages/frontend/src/components/MkNoteHeader.vue +++ b/packages/frontend/src/components/MkNoteHeader.vue @@ -4,19 +4,56 @@ SPDX-License-Identifier: AGPL-3.0-only --> diff --git a/packages/frontend/src/components/MkNoteSimple.vue b/packages/frontend/src/components/MkNoteSimple.vue index b1d4ed3f7e..8ebd24b322 100644 --- a/packages/frontend/src/components/MkNoteSimple.vue +++ b/packages/frontend/src/components/MkNoteSimple.vue @@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
- +

diff --git a/packages/frontend/src/components/MkNoteSub.vue b/packages/frontend/src/components/MkNoteSub.vue index 3e33c7aa69..822b4de83f 100644 --- a/packages/frontend/src/components/MkNoteSub.vue +++ b/packages/frontend/src/components/MkNoteSub.vue @@ -5,11 +5,12 @@ SPDX-License-Identifier: AGPL-3.0-only

-
+
diff --git a/packages/frontend/src/components/global/MkAvatar.vue b/packages/frontend/src/components/global/MkAvatar.vue index e238834872..51a454b2cc 100644 --- a/packages/frontend/src/components/global/MkAvatar.vue +++ b/packages/frontend/src/components/global/MkAvatar.vue @@ -83,7 +83,7 @@ const bound = $computed(() => props.link ? { to: userPage(props.user), target: props.target } : {}); -const url = $computed(() => (defaultStore.state.disableShowingAnimatedImages || defaultStore.state.enableDataSaverMode) +const url = $computed(() => (defaultStore.state.disableShowingAnimatedImages || defaultStore.state.dataSaver.avatar) ? getStaticImageUrl(props.user.avatarUrl) : props.user.avatarUrl); diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue index 313b5efc46..717021abd0 100644 --- a/packages/frontend/src/pages/settings/general.vue +++ b/packages/frontend/src/pages/settings/general.vue @@ -122,7 +122,6 @@ SPDX-License-Identifier: AGPL-3.0-only {{ i18n.ts.useSystemFont }} {{ i18n.ts.disableDrawer }} {{ i18n.ts.forceShowAds }} - {{ i18n.ts.dataSaver }}
@@ -165,6 +164,37 @@ SPDX-License-Identifier: AGPL-3.0-only + + + + +
+ {{ i18n.ts.reloadRequiredToApplySettings }} + +
+ {{ i18n.ts.enableAll }} + {{ i18n.ts.disableAll }} +
+
+ + {{ i18n.ts._dataSaver._media.title }} + + + + {{ i18n.ts._dataSaver._avatar.title }} + + + + {{ i18n.ts._dataSaver._urlPreview.title }} + + + + {{ i18n.ts._dataSaver._code.title }} + + +
+
+
@@ -198,6 +228,7 @@ import MkButton from '@/components/MkButton.vue'; import FormSection from '@/components/form/section.vue'; import FormLink from '@/components/form/link.vue'; import MkLink from '@/components/MkLink.vue'; +import MkInfo from '@/components/MkInfo.vue'; import { langs } from '@/config.js'; import { defaultStore } from '@/store.js'; import * as os from '@/os.js'; @@ -211,6 +242,7 @@ import { claimAchievement } from '@/scripts/achievements.js'; const lang = ref(miLocalStorage.getItem('lang')); const fontSize = ref(miLocalStorage.getItem('fontSize')); const useSystemFont = ref(miLocalStorage.getItem('useSystemFont') != null); +const dataSaver = ref(defaultStore.state.dataSaver); async function reloadAsk() { const { canceled } = await os.confirm({ @@ -241,7 +273,6 @@ const disableShowingAnimatedImages = computed(defaultStore.makeGetterSetter('dis const forceShowAds = computed(defaultStore.makeGetterSetter('forceShowAds')); const loadRawImages = computed(defaultStore.makeGetterSetter('loadRawImages')); const highlightSensitiveMedia = computed(defaultStore.makeGetterSetter('highlightSensitiveMedia')); -const enableDataSaverMode = computed(defaultStore.makeGetterSetter('enableDataSaverMode')); const imageNewTab = computed(defaultStore.makeGetterSetter('imageNewTab')); const nsfw = computed(defaultStore.makeGetterSetter('nsfw')); const showFixedPostForm = computed(defaultStore.makeGetterSetter('showFixedPostForm')); @@ -374,6 +405,28 @@ function testNotification(): void { }, 300); } +function enableAllDataSaver() { + const g = { ...defaultStore.state.dataSaver }; + + Object.keys(g).forEach((key) => { g[key] = true; }); + + dataSaver.value = g; +} + +function disableAllDataSaver() { + const g = { ...defaultStore.state.dataSaver }; + + Object.keys(g).forEach((key) => { g[key] = false; }); + + dataSaver.value = g; +} + +watch(dataSaver, (to) => { + defaultStore.set('dataSaver', to); +}, { + deep: true, +}); + const headerActions = $computed(() => []); const headerTabs = $computed(() => []); diff --git a/packages/frontend/src/pages/settings/preferences-backups.vue b/packages/frontend/src/pages/settings/preferences-backups.vue index 35435238fc..0362998855 100644 --- a/packages/frontend/src/pages/settings/preferences-backups.vue +++ b/packages/frontend/src/pages/settings/preferences-backups.vue @@ -71,7 +71,7 @@ const defaultStoreSaveKeys: (keyof typeof defaultStore['state'])[] = [ 'advancedMfm', 'loadRawImages', 'imageNewTab', - 'enableDataSaverMode', + 'dataSaver', 'disableShowingAnimatedImages', 'emojiStyle', 'disableDrawer', diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts index 70d2cf402d..8459a5721a 100644 --- a/packages/frontend/src/store.ts +++ b/packages/frontend/src/store.ts @@ -223,10 +223,6 @@ export const defaultStore = markRaw(new Storage('base', { where: 'device', default: false, }, - enableDataSaverMode: { - where: 'device', - default: false, - }, disableShowingAnimatedImages: { where: 'device', default: window.matchMedia('(prefers-reduced-motion)').matches, @@ -403,6 +399,15 @@ export const defaultStore = markRaw(new Storage('base', { where: 'device', default: true, }, + dataSaver: { + where: 'device', + default: { + media: false, + avatar: false, + urlPreview: false, + code: false, + } as Record, + }, sound_masterVolume: { where: 'device', diff --git a/packages/frontend/test/init.ts b/packages/frontend/test/init.ts index ab5e84b53c..dfc02378d5 100644 --- a/packages/frontend/test/init.ts +++ b/packages/frontend/test/init.ts @@ -21,7 +21,17 @@ vi.stubGlobal('WebSocket', class WebSocket extends EventTarget { static CLOSING vi.mock('@/store.js', () => { return { defaultStore: { - state: {}, + state: { + + // なんかtestがうまいこと動かないのでここに書く + dataSaver: { + media: false, + avatar: false, + urlPreview: false, + code: false, + }, + + }, }, }; }); From b4a83a22a1108354191bc822c19b5fa2b0a30a6e 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, 3 Dec 2023 12:08:40 +0900 Subject: [PATCH 106/435] may be fix ruby justify on safari (#12551) --- packages/frontend/src/style.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/frontend/src/style.scss b/packages/frontend/src/style.scss index 7bb443cece..274808b13f 100644 --- a/packages/frontend/src/style.scss +++ b/packages/frontend/src/style.scss @@ -132,6 +132,10 @@ hr { background: var(--divider); } +rt { + white-space: initial; +} + .ti { width: 1.28em; vertical-align: -12%; From e17d741f4b14e3d675f2818fab3ec30c72a39586 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?= <46447427+samunohito@users.noreply.github.com> Date: Sun, 3 Dec 2023 12:45:18 +0900 Subject: [PATCH 107/435] =?UTF-8?q?enhance(misskey-js)=20misskey-js?= =?UTF-8?q?=E3=81=AE=E3=82=B9=E3=83=88=E3=83=AA=E3=83=BC=E3=83=9F=E3=83=B3?= =?UTF-8?q?=E3=82=B0API=E5=AE=9A=E7=BE=A9=E3=82=92=E3=83=90=E3=83=83?= =?UTF-8?q?=E3=82=AF=E3=82=A8=E3=83=B3=E3=83=89=E3=81=AB=E8=BF=BD=E5=BE=93?= =?UTF-8?q?=20(#12552)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * (enhance) misskey-jsのストリーミングAPI定義をバックエンドに追従 * fix ci * fix ci --- packages/backend/src/misc/json-schema.ts | 2 + .../backend/src/models/json-schema/signin.ts | 26 +++ .../server/api/endpoints/i/signin-history.ts | 11 +- packages/misskey-js/etc/misskey-js.api.md | 180 ++++++++++++++++-- packages/misskey-js/src/autogen/endpoint.ts | 4 +- packages/misskey-js/src/autogen/entities.ts | 4 +- packages/misskey-js/src/autogen/models.ts | 5 +- packages/misskey-js/src/autogen/types.ts | 42 ++-- packages/misskey-js/src/entities.ts | 56 +++++- packages/misskey-js/src/streaming.types.ts | 140 ++++++++++++-- 10 files changed, 414 insertions(+), 56 deletions(-) create mode 100644 packages/backend/src/models/json-schema/signin.ts diff --git a/packages/backend/src/misc/json-schema.ts b/packages/backend/src/misc/json-schema.ts index 80c1041c62..7e7fc447c3 100644 --- a/packages/backend/src/misc/json-schema.ts +++ b/packages/backend/src/misc/json-schema.ts @@ -36,6 +36,7 @@ import { packedGalleryPostSchema } from '@/models/json-schema/gallery-post.js'; import { packedEmojiDetailedSchema, packedEmojiSimpleSchema } from '@/models/json-schema/emoji.js'; import { packedFlashSchema } from '@/models/json-schema/flash.js'; import { packedAnnouncementSchema } from '@/models/json-schema/announcement.js'; +import { packedSigninSchema } from '@/models/json-schema/signin.js'; export const refs = { UserLite: packedUserLiteSchema, @@ -71,6 +72,7 @@ export const refs = { EmojiSimple: packedEmojiSimpleSchema, EmojiDetailed: packedEmojiDetailedSchema, Flash: packedFlashSchema, + Signin: packedSigninSchema, }; export type Packed = SchemaType; diff --git a/packages/backend/src/models/json-schema/signin.ts b/packages/backend/src/models/json-schema/signin.ts new file mode 100644 index 0000000000..d27d2490c5 --- /dev/null +++ b/packages/backend/src/models/json-schema/signin.ts @@ -0,0 +1,26 @@ +export const packedSigninSchema = { + type: 'object', + properties: { + id: { + type: 'string', + optional: false, nullable: false, + }, + createdAt: { + type: 'string', + optional: false, nullable: false, + format: 'date-time', + }, + ip: { + type: 'string', + optional: false, nullable: false, + }, + headers: { + type: 'object', + optional: false, nullable: false, + }, + success: { + type: 'boolean', + optional: false, nullable: false, + }, + }, +} as const; diff --git a/packages/backend/src/server/api/endpoints/i/signin-history.ts b/packages/backend/src/server/api/endpoints/i/signin-history.ts index 139bede7bc..f82e3f9b28 100644 --- a/packages/backend/src/server/api/endpoints/i/signin-history.ts +++ b/packages/backend/src/server/api/endpoints/i/signin-history.ts @@ -12,8 +12,17 @@ import { DI } from '@/di-symbols.js'; export const meta = { requireCredential: true, - secure: true, + + res: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'object', + optional: false, nullable: false, + ref: 'Signin', + }, + }, } as const; export const paramDef = { diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index 4e6e2adc02..e2e3349c08 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -292,6 +292,11 @@ type AdminUpdateUserNoteRequest = operations['admin/update-user-note']['requestB // @public (undocumented) type Announcement = components['schemas']['Announcement']; +// @public (undocumented) +type AnnouncementCreated = { + announcement: Announcement; +}; + // @public (undocumented) type AnnouncementsRequest = operations['announcements']['requestBody']['content']['application/json']; @@ -488,9 +493,7 @@ export type Channels = { unreadAntenna: (payload: Antenna) => void; readAllAnnouncements: () => void; myTokenRegenerated: () => void; - reversiNoInvites: () => void; - reversiInvited: (payload: FIXME) => void; - signin: (payload: FIXME) => void; + signin: (payload: Signin) => void; registryUpdated: (payload: { scope?: string[]; key: string; @@ -498,41 +501,116 @@ export type Channels = { }) => void; driveFileCreated: (payload: DriveFile) => void; readAntenna: (payload: Antenna) => void; + receiveFollowRequest: (payload: User) => void; + announcementCreated: (payload: AnnouncementCreated) => void; }; receives: null; }; homeTimeline: { - params: null; + params: { + withRenotes?: boolean; + withFiles?: boolean; + }; events: { note: (payload: Note) => void; }; receives: null; }; localTimeline: { - params: null; + params: { + withRenotes?: boolean; + withReplies?: boolean; + withFiles?: boolean; + }; events: { note: (payload: Note) => void; }; receives: null; }; hybridTimeline: { - params: null; + params: { + withRenotes?: boolean; + withReplies?: boolean; + withFiles?: boolean; + }; events: { note: (payload: Note) => void; }; receives: null; }; globalTimeline: { - params: null; + params: { + withRenotes?: boolean; + withFiles?: boolean; + }; events: { note: (payload: Note) => void; }; receives: null; }; + userList: { + params: { + listId: string; + withFiles?: boolean; + }; + events: { + note: (payload: Note) => void; + }; + receives: null; + }; + hashtag: { + params: { + q?: string; + }; + events: { + note: (payload: Note) => void; + }; + receives: null; + }; + roleTimeline: { + params: { + roleId: string; + }; + events: { + note: (payload: Note) => void; + }; + receives: null; + }; + antenna: { + params: { + antennaId: string; + }; + events: { + note: (payload: Note) => void; + }; + receives: null; + }; + channel: { + params: { + channelId: string; + }; + events: { + note: (payload: Note) => void; + }; + receives: null; + }; + drive: { + params: null; + events: { + fileCreated: (payload: DriveFile) => void; + fileDeleted: (payload: DriveFile['id']) => void; + fileUpdated: (payload: DriveFile) => void; + folderCreated: (payload: DriveFolder) => void; + folderDeleted: (payload: DriveFolder['id']) => void; + folderUpdated: (payload: DriveFile) => void; + }; + receives: null; + }; serverStats: { params: null; events: { - stats: (payload: FIXME) => void; + stats: (payload: ServerStats) => void; + statsLog: (payload: ServerStatsLog) => void; }; receives: { requestLog: { @@ -544,7 +622,8 @@ export type Channels = { queueStats: { params: null; events: { - stats: (payload: FIXME) => void; + stats: (payload: QueueStats) => void; + statsLog: (payload: QueueStatsLog) => void; }; receives: { requestLog: { @@ -553,6 +632,18 @@ export type Channels = { }; }; }; + admin: { + params: null; + events: { + newAbuseUserReport: { + id: string; + targetUserId: string; + reporterId: string; + comment: string; + }; + }; + receives: null; + }; }; // @public (undocumented) @@ -846,6 +937,16 @@ type EmailAddressAvailableRequest = operations['email-address/available']['reque // @public (undocumented) type EmailAddressAvailableResponse = operations['email-address/available']['responses']['200']['content']['application/json']; +// @public (undocumented) +type EmojiAdded = { + emoji: EmojiDetailed; +}; + +// @public (undocumented) +type EmojiDeleted = { + emojis: EmojiDetailed[]; +}; + // @public (undocumented) type EmojiDetailed = components['schemas']['EmojiDetailed']; @@ -861,6 +962,11 @@ type EmojiSimple = components['schemas']['EmojiSimple']; // @public (undocumented) type EmojisResponse = operations['emojis']['responses']['200']['content']['application/json']; +// @public (undocumented) +type EmojiUpdated = { + emojis: EmojiDetailed[]; +}; + // @public (undocumented) type EmptyRequest = Record | undefined; @@ -902,6 +1008,14 @@ declare namespace entities { DateString, PageEvent, ModerationLog, + ServerStats, + ServerStatsLog, + QueueStats, + QueueStatsLog, + EmojiAdded, + EmojiUpdated, + EmojiDeleted, + AnnouncementCreated, EmptyRequest, EmptyResponse, AdminMetaResponse, @@ -1404,7 +1518,8 @@ declare namespace entities { GalleryPost, EmojiSimple, EmojiDetailed, - Flash + Flash, + Signin } } export { entities } @@ -2154,6 +2269,25 @@ type PromoReadRequest = operations['promo/read']['requestBody']['content']['appl // @public (undocumented) type QueueCount = components['schemas']['QueueCount']; +// @public (undocumented) +type QueueStats = { + deliver: { + activeSincePrevTick: number; + active: number; + waiting: number; + delayed: number; + }; + inbox: { + activeSincePrevTick: number; + active: number; + waiting: number; + delayed: number; + }; +}; + +// @public (undocumented) +type QueueStatsLog = string[]; + // @public (undocumented) type RenoteMuteCreateRequest = operations['renote-mute/create']['requestBody']['content']['application/json']; @@ -2190,6 +2324,29 @@ type RolesShowRequest = operations['roles/show']['requestBody']['content']['appl // @public (undocumented) type RolesUsersRequest = operations['roles/users']['requestBody']['content']['application/json']; +// @public (undocumented) +type ServerStats = { + cpu: number; + mem: { + used: number; + active: number; + }; + net: { + rx: number; + tx: number; + }; + fs: { + r: number; + w: number; + }; +}; + +// @public (undocumented) +type ServerStatsLog = string[]; + +// @public (undocumented) +type Signin = components['schemas']['Signin']; + // @public (undocumented) type StatsResponse = operations['stats']['responses']['200']['content']['application/json']; @@ -2448,8 +2605,7 @@ type UsersUpdateMemoRequest = operations['users/update-memo']['requestBody']['co // Warnings were encountered during analysis: // -// src/entities.ts:24:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts -// src/streaming.types.ts:31:4 - (ae-forgotten-export) The symbol "FIXME" needs to be exported by the entry point index.d.ts +// src/entities.ts:25:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) diff --git a/packages/misskey-js/src/autogen/endpoint.ts b/packages/misskey-js/src/autogen/endpoint.ts index 64739a65d0..b46e69f691 100644 --- a/packages/misskey-js/src/autogen/endpoint.ts +++ b/packages/misskey-js/src/autogen/endpoint.ts @@ -1,6 +1,6 @@ /* - * version: 2023.11.1 - * generatedAt: 2023-11-27T02:24:45.113Z + * version: 2023.12.0-beta.1 + * generatedAt: 2023-12-03T02:04:45.058Z */ import type { diff --git a/packages/misskey-js/src/autogen/entities.ts b/packages/misskey-js/src/autogen/entities.ts index 133a30b4ca..a51ee037d0 100644 --- a/packages/misskey-js/src/autogen/entities.ts +++ b/packages/misskey-js/src/autogen/entities.ts @@ -1,6 +1,6 @@ /* - * version: 2023.11.1 - * generatedAt: 2023-11-27T02:24:45.111Z + * version: 2023.12.0-beta.1 + * generatedAt: 2023-12-03T02:04:45.053Z */ import { operations } from './types.js'; diff --git a/packages/misskey-js/src/autogen/models.ts b/packages/misskey-js/src/autogen/models.ts index bc7ab1f3b9..c2b27b2c58 100644 --- a/packages/misskey-js/src/autogen/models.ts +++ b/packages/misskey-js/src/autogen/models.ts @@ -1,6 +1,6 @@ /* - * version: 2023.11.1 - * generatedAt: 2023-11-27T02:24:45.109Z + * version: 2023.12.0-beta.1 + * generatedAt: 2023-12-03T02:04:45.051Z */ import { components } from './types.js'; @@ -37,3 +37,4 @@ export type GalleryPost = components['schemas']['GalleryPost']; export type EmojiSimple = components['schemas']['EmojiSimple']; export type EmojiDetailed = components['schemas']['EmojiDetailed']; export type Flash = components['schemas']['Flash']; +export type Signin = components['schemas']['Signin']; diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts index c7f5c6c82d..44ed4dbaa8 100644 --- a/packages/misskey-js/src/autogen/types.ts +++ b/packages/misskey-js/src/autogen/types.ts @@ -2,8 +2,8 @@ /* eslint @typescript-eslint/no-explicit-any: 0 */ /* - * version: 2023.11.1 - * generatedAt: 2023-11-27T02:24:44.994Z + * version: 2023.12.0-beta.1 + * generatedAt: 2023-12-03T02:04:44.864Z */ /** @@ -3388,6 +3388,7 @@ export type components = { uri?: string; url?: string; reactionAndUserPairCache?: string[]; + clippedCount?: number; myReaction?: Record | null; }; NoteReaction: { @@ -3786,6 +3787,14 @@ export type components = { likedCount: number | null; isLiked?: boolean; }; + Signin: { + id: string; + /** Format: date-time */ + createdAt: string; + ip: string; + headers: Record; + success: boolean; + }; }; responses: never; parameters: never; @@ -6405,10 +6414,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': { - /** @example GR6S02ERUA5VR */ - code: string; - }[]; + 'application/json': components['schemas']['InviteCode'][]; }; }; /** @description Client error */ @@ -6471,7 +6477,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': Record[]; + 'application/json': components['schemas']['InviteCode'][]; }; }; /** @description Client error */ @@ -9600,6 +9606,8 @@ export type operations = { untilId?: string; sinceDate?: number; untilDate?: number; + /** @default false */ + allowPartial?: boolean; }; }; }; @@ -15893,10 +15901,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': { - /** @example GR6S02ERUA5VR */ - code: string; - }; + 'application/json': components['schemas']['InviteCode']; }; }; /** @description Client error */ @@ -17349,6 +17354,8 @@ export type operations = { untilId?: string; sinceDate?: number; untilDate?: number; + /** @default false */ + allowPartial?: boolean; /** @default true */ includeMyRenotes?: boolean; /** @default true */ @@ -17419,14 +17426,14 @@ export type operations = { withRenotes?: boolean; /** @default false */ withReplies?: boolean; - /** @default false */ - excludeNsfw?: boolean; /** @default 10 */ limit?: number; /** Format: misskey:id */ sinceId?: string; /** Format: misskey:id */ untilId?: string; + /** @default false */ + allowPartial?: boolean; sinceDate?: number; untilDate?: number; }; @@ -18317,6 +18324,8 @@ export type operations = { untilId?: string; sinceDate?: number; untilDate?: number; + /** @default false */ + allowPartial?: boolean; /** @default true */ includeMyRenotes?: boolean; /** @default true */ @@ -18502,6 +18511,8 @@ export type operations = { untilId?: string; sinceDate?: number; untilDate?: number; + /** @default false */ + allowPartial?: boolean; /** @default true */ includeMyRenotes?: boolean; /** @default true */ @@ -20799,6 +20810,7 @@ export type operations = { username?: string; /** @description The local host is represented with `null`. */ host?: string | null; + birthday?: string | null; }; }; }; @@ -21704,9 +21716,9 @@ export type operations = { sinceDate?: number; untilDate?: number; /** @default false */ - withFiles?: boolean; + allowPartial?: boolean; /** @default false */ - excludeNsfw?: boolean; + withFiles?: boolean; }; }; }; diff --git a/packages/misskey-js/src/entities.ts b/packages/misskey-js/src/entities.ts index b1d6b5c10f..99f433cc02 100644 --- a/packages/misskey-js/src/entities.ts +++ b/packages/misskey-js/src/entities.ts @@ -1,5 +1,6 @@ -import { ModerationLogPayloads, notificationTypes } from './consts.js'; -import { Page, User, UserDetailed } from './autogen/models'; +import { ModerationLogPayloads } from './consts.js'; +import { Announcement, EmojiDetailed, Page, User, UserDetailed } from './autogen/models'; + export * from './autogen/entities'; export * from './autogen/models'; @@ -131,3 +132,54 @@ export type ModerationLog = { type: 'unsetUserBanner'; info: ModerationLogPayloads['unsetUserBanner']; }); + +export type ServerStats = { + cpu: number; + mem: { + used: number; + active: number; + }; + net: { + rx: number; + tx: number; + }; + fs: { + r: number; + w: number; + } +}; + +export type ServerStatsLog = string[]; + +export type QueueStats = { + deliver: { + activeSincePrevTick: number; + active: number; + waiting: number; + delayed: number; + }; + inbox: { + activeSincePrevTick: number; + active: number; + waiting: number; + delayed: number; + }; +}; + +export type QueueStatsLog = string[]; + +export type EmojiAdded = { + emoji: EmojiDetailed +}; + +export type EmojiUpdated = { + emojis: EmojiDetailed[] +}; + +export type EmojiDeleted = { + emojis: EmojiDetailed[] +}; + +export type AnnouncementCreated = { + announcement: Announcement; +}; diff --git a/packages/misskey-js/src/streaming.types.ts b/packages/misskey-js/src/streaming.types.ts index 7981c280f6..6f575ce585 100644 --- a/packages/misskey-js/src/streaming.types.ts +++ b/packages/misskey-js/src/streaming.types.ts @@ -1,7 +1,23 @@ -import { Antenna, DriveFile, EmojiDetailed, MeDetailed, Note, User, Notification } from './autogen/models.js'; -import { PageEvent } from './entities.js'; - -type FIXME = any; +import { + Antenna, + DriveFile, + DriveFolder, + MeDetailed, + Note, + Notification, + Signin, + User, +} from './autogen/models.js'; +import { + AnnouncementCreated, + EmojiAdded, EmojiDeleted, + EmojiUpdated, + PageEvent, + QueueStats, + QueueStatsLog, + ServerStats, + ServerStatsLog, +} from './entities.js'; export type Channels = { main: { @@ -27,9 +43,7 @@ export type Channels = { unreadAntenna: (payload: Antenna) => void; readAllAnnouncements: () => void; myTokenRegenerated: () => void; - reversiNoInvites: () => void; - reversiInvited: (payload: FIXME) => void; - signin: (payload: FIXME) => void; + signin: (payload: Signin) => void; registryUpdated: (payload: { scope?: string[]; key: string; @@ -37,41 +51,116 @@ export type Channels = { }) => void; driveFileCreated: (payload: DriveFile) => void; readAntenna: (payload: Antenna) => void; + receiveFollowRequest: (payload: User) => void; + announcementCreated: (payload: AnnouncementCreated) => void; }; receives: null; }; homeTimeline: { - params: null; + params: { + withRenotes?: boolean; + withFiles?: boolean; + }; events: { note: (payload: Note) => void; }; receives: null; }; localTimeline: { - params: null; + params: { + withRenotes?: boolean; + withReplies?: boolean; + withFiles?: boolean; + }; events: { note: (payload: Note) => void; }; receives: null; }; hybridTimeline: { - params: null; + params: { + withRenotes?: boolean; + withReplies?: boolean; + withFiles?: boolean; + }; events: { note: (payload: Note) => void; }; receives: null; }; globalTimeline: { - params: null; + params: { + withRenotes?: boolean; + withFiles?: boolean; + }; events: { note: (payload: Note) => void; }; receives: null; }; + userList: { + params: { + listId: string; + withFiles?: boolean; + }; + events: { + note: (payload: Note) => void; + }; + receives: null; + }; + hashtag: { + params: { + q?: string; + }; + events: { + note: (payload: Note) => void; + }; + receives: null; + }; + roleTimeline: { + params: { + roleId: string; + }; + events: { + note: (payload: Note) => void; + }; + receives: null; + }; + antenna: { + params: { + antennaId: string; + }; + events: { + note: (payload: Note) => void; + }; + receives: null; + }; + channel: { + params: { + channelId: string; + }; + events: { + note: (payload: Note) => void; + }; + receives: null; + }; + drive: { + params: null; + events: { + fileCreated: (payload: DriveFile) => void; + fileDeleted: (payload: DriveFile['id']) => void; + fileUpdated: (payload: DriveFile) => void; + folderCreated: (payload: DriveFolder) => void; + folderDeleted: (payload: DriveFolder['id']) => void; + folderUpdated: (payload: DriveFile) => void; + }; + receives: null; + }; serverStats: { params: null; events: { - stats: (payload: FIXME) => void; + stats: (payload: ServerStats) => void; + statsLog: (payload: ServerStatsLog) => void; }; receives: { requestLog: { @@ -83,7 +172,8 @@ export type Channels = { queueStats: { params: null; events: { - stats: (payload: FIXME) => void; + stats: (payload: QueueStats) => void; + statsLog: (payload: QueueStatsLog) => void; }; receives: { requestLog: { @@ -92,30 +182,39 @@ export type Channels = { }; }; }; + admin: { + params: null; + events: { + newAbuseUserReport: { + id: string; + targetUserId: string; + reporterId: string; + comment: string; + } + }; + receives: null; + } }; export type NoteUpdatedEvent = { - id: Note['id']; type: 'reacted'; body: { reaction: string; + emoji: string | null; userId: User['id']; }; } | { - id: Note['id']; type: 'unreacted'; body: { reaction: string; userId: User['id']; }; } | { - id: Note['id']; type: 'deleted'; body: { deletedAt: string; }; } | { - id: Note['id']; type: 'pollVoted'; body: { choice: number; @@ -125,7 +224,8 @@ export type NoteUpdatedEvent = { export type BroadcastEvents = { noteUpdated: (payload: NoteUpdatedEvent) => void; - emojiAdded: (payload: { - emoji: EmojiDetailed; - }) => void; + emojiAdded: (payload: EmojiAdded) => void; + emojiUpdated: (payload: EmojiUpdated) => void; + emojiDeleted: (payload: EmojiDeleted) => void; + announcementCreated: (payload: AnnouncementCreated) => void; }; From 34223f3da41f1d006e950573952ee062256a0ed5 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sun, 3 Dec 2023 05:42:41 +0100 Subject: [PATCH 108/435] fix(backend): enhance nodeinfo by export instance admin via nodeAdmins key (#12503) https://codeberg.org/thefederationinfo/nodeinfo_extension --- packages/backend/src/server/NodeinfoServerService.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/backend/src/server/NodeinfoServerService.ts b/packages/backend/src/server/NodeinfoServerService.ts index 79b0a57f2b..4d94fcdd54 100644 --- a/packages/backend/src/server/NodeinfoServerService.ts +++ b/packages/backend/src/server/NodeinfoServerService.ts @@ -96,6 +96,11 @@ export class NodeinfoServerService { metadata: { nodeName: meta.name, nodeDescription: meta.description, + nodeAdmins: [{ + name: meta.maintainerName, + email: meta.maintainerEmail, + }], + // deprecated maintainer: { name: meta.maintainerName, email: meta.maintainerEmail, From af15f8d09db6c1709950bf9d00ffb77613fbcf8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Sun, 3 Dec 2023 14:38:42 +0900 Subject: [PATCH 109/435] fix(backend): reject malformed timestamp (#12554) --- packages/backend/src/core/IdService.ts | 23 +++++++++++++++---- .../src/core/activitypub/ApInboxService.ts | 8 ++++++- .../core/activitypub/models/ApNoteService.ts | 4 ++++ packages/backend/src/misc/id/aid.ts | 4 ++++ packages/backend/src/misc/id/aidx.ts | 4 ++++ packages/backend/src/misc/id/meid.ts | 4 ++++ packages/backend/src/misc/id/meidg.ts | 4 ++++ packages/backend/src/misc/id/object-id.ts | 4 ++++ 8 files changed, 49 insertions(+), 6 deletions(-) diff --git a/packages/backend/src/core/IdService.ts b/packages/backend/src/core/IdService.ts index c98b8ea6fc..43e72d2d7b 100644 --- a/packages/backend/src/core/IdService.ts +++ b/packages/backend/src/core/IdService.ts @@ -7,11 +7,11 @@ import { Inject, Injectable } from '@nestjs/common'; import { ulid } from 'ulid'; import { DI } from '@/di-symbols.js'; import type { Config } from '@/config.js'; -import { genAid, parseAid } from '@/misc/id/aid.js'; -import { genAidx, parseAidx } from '@/misc/id/aidx.js'; -import { genMeid, parseMeid } from '@/misc/id/meid.js'; -import { genMeidg, parseMeidg } from '@/misc/id/meidg.js'; -import { genObjectId, parseObjectId } from '@/misc/id/object-id.js'; +import { genAid, isSafeAidT, parseAid } from '@/misc/id/aid.js'; +import { genAidx, isSafeAidxT, parseAidx } from '@/misc/id/aidx.js'; +import { genMeid, isSafeMeidT, parseMeid } from '@/misc/id/meid.js'; +import { genMeidg, isSafeMeidgT, parseMeidg } from '@/misc/id/meidg.js'; +import { genObjectId, isSafeObjectIdT, parseObjectId } from '@/misc/id/object-id.js'; import { bindThis } from '@/decorators.js'; import { parseUlid } from '@/misc/id/ulid.js'; @@ -26,6 +26,19 @@ export class IdService { this.method = config.id.toLowerCase(); } + @bindThis + public isSafeT(t: number): boolean { + switch (this.method) { + case 'aid': return isSafeAidT(t); + case 'aidx': return isSafeAidxT(t); + case 'meid': return isSafeMeidT(t); + case 'meidg': return isSafeMeidgT(t); + case 'ulid': return t > 0; + case 'objectid': return isSafeObjectIdT(t); + default: throw new Error('unrecognized id generation method'); + } + } + /** * 時間を元にIDを生成します(省略時は現在日時) * @param time 日時 diff --git a/packages/backend/src/core/activitypub/ApInboxService.ts b/packages/backend/src/core/activitypub/ApInboxService.ts index 7aba140689..baaab67e48 100644 --- a/packages/backend/src/core/activitypub/ApInboxService.ts +++ b/packages/backend/src/core/activitypub/ApInboxService.ts @@ -306,9 +306,15 @@ export class ApInboxService { this.logger.info(`Creating the (Re)Note: ${uri}`); const activityAudience = await this.apAudienceService.parseAudience(actor, activity.to, activity.cc); + const createdAt = activity.published ? new Date(activity.published) : null; + + if (createdAt && createdAt < this.idService.parse(renote.id).date) { + this.logger.warn('skip: malformed createdAt'); + return; + } await this.noteCreateService.create(actor, { - createdAt: activity.published ? new Date(activity.published) : null, + createdAt, renote, visibility: activityAudience.visibility, visibleUsers: activityAudience.visibleUsers, diff --git a/packages/backend/src/core/activitypub/models/ApNoteService.ts b/packages/backend/src/core/activitypub/models/ApNoteService.ts index 1979cdda9c..05d5ca15db 100644 --- a/packages/backend/src/core/activitypub/models/ApNoteService.ts +++ b/packages/backend/src/core/activitypub/models/ApNoteService.ts @@ -92,6 +92,10 @@ export class ApNoteService { return new Error(`invalid Note: attributedTo has different host. expected: ${expectHost}, actual: ${actualHost}`); } + if (object.published && !this.idService.isSafeT(new Date(object.published).valueOf())) { + return new Error('invalid Note: published timestamp is malformed'); + } + return null; } diff --git a/packages/backend/src/misc/id/aid.ts b/packages/backend/src/misc/id/aid.ts index e7b59f262b..de03f6793f 100644 --- a/packages/backend/src/misc/id/aid.ts +++ b/packages/backend/src/misc/id/aid.ts @@ -34,3 +34,7 @@ export function parseAid(id: string): { date: Date; } { const time = parseInt(id.slice(0, 8), 36) + TIME2000; return { date: new Date(time) }; } + +export function isSafeAidT(t: number): boolean { + return t > TIME2000; +} diff --git a/packages/backend/src/misc/id/aidx.ts b/packages/backend/src/misc/id/aidx.ts index bed223225a..9f457f6f0a 100644 --- a/packages/backend/src/misc/id/aidx.ts +++ b/packages/backend/src/misc/id/aidx.ts @@ -41,3 +41,7 @@ export function parseAidx(id: string): { date: Date; } { const time = parseInt(id.slice(0, TIME_LENGTH), 36) + TIME2000; return { date: new Date(time) }; } + +export function isSafeAidxT(t: number): boolean { + return t > TIME2000; +} diff --git a/packages/backend/src/misc/id/meid.ts b/packages/backend/src/misc/id/meid.ts index 366738de05..7646282edb 100644 --- a/packages/backend/src/misc/id/meid.ts +++ b/packages/backend/src/misc/id/meid.ts @@ -38,3 +38,7 @@ export function parseMeid(id: string): { date: Date; } { date: new Date(parseInt(id.slice(0, 12), 16) - 0x800000000000), }; } + +export function isSafeMeidT(t: number): boolean { + return t > 0; +} diff --git a/packages/backend/src/misc/id/meidg.ts b/packages/backend/src/misc/id/meidg.ts index 426a46970b..f2a55443ef 100644 --- a/packages/backend/src/misc/id/meidg.ts +++ b/packages/backend/src/misc/id/meidg.ts @@ -38,3 +38,7 @@ export function parseMeidg(id: string): { date: Date; } { date: new Date(parseInt(id.slice(1, 12), 16)), }; } + +export function isSafeMeidgT(t: number): boolean { + return t > 0; +} diff --git a/packages/backend/src/misc/id/object-id.ts b/packages/backend/src/misc/id/object-id.ts index 49bd9591c0..f5c3619fdb 100644 --- a/packages/backend/src/misc/id/object-id.ts +++ b/packages/backend/src/misc/id/object-id.ts @@ -38,3 +38,7 @@ export function parseObjectId(id: string): { date: Date; } { date: new Date(parseInt(id.slice(0, 8), 16) * 1000), }; } + +export function isSafeObjectIdT(t: number): boolean { + return t > 0; +} From 5e1d87240426e08858b7fc5ccad5ca235bd3c6e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?= <46447427+samunohito@users.noreply.github.com> Date: Sun, 3 Dec 2023 17:25:34 +0900 Subject: [PATCH 110/435] =?UTF-8?q?=E5=85=A5=E5=8A=9B=E3=83=95=E3=82=A9?= =?UTF-8?q?=E3=83=BC=E3=83=A0=E3=81=A7=E3=82=82=E3=83=AA=E3=82=A2=E3=82=AF?= =?UTF-8?q?=E3=82=B7=E3=83=A7=E3=83=B3=E9=81=B8=E6=8A=9E=E6=99=82=E3=81=AB?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E3=81=99=E3=82=8B=E3=83=94=E3=83=83=E3=82=AB?= =?UTF-8?q?=E3=83=BC=E3=82=92=E4=BD=BF=E3=81=86=E3=82=88=E3=81=86=E3=81=AB?= =?UTF-8?q?=E3=81=97=E3=81=9F=E3=81=84=20(#12337)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 入力フォームでもリアクション選択時に使用するピッカーを使うようにしたい * erase console.log * fix CHANGELOG.md * reaction-picker.ts を戻し、今回の対応を入れた emoji-picker.ts を新たに作成 * fix CHANGELOG.md * tweak --------- Co-authored-by: osamu <46447427+sam-osamu@users.noreply.github.com> Co-authored-by: syuilo --- CHANGELOG.md | 1 + packages/frontend/src/boot/main-boot.ts | 2 + .../frontend/src/components/MkEmojiPicker.vue | 5 +- .../src/components/MkEmojiPickerDialog.vue | 19 ++++--- .../frontend/src/components/MkPostForm.vue | 11 +++- packages/frontend/src/scripts/emoji-picker.ts | 57 +++++++++++++++++++ 6 files changed, 84 insertions(+), 11 deletions(-) create mode 100644 packages/frontend/src/scripts/emoji-picker.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 99ef3a36ab..694f330120 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ ### Client - Feat: 今日誕生日のフォロー中のユーザーを一覧表示できるウィジェットを追加 - Feat: データセーバーでコードハイライトの読み込みを削減できるように +- Enhance: 投稿フォームの絵文字ピッカーをリアクション時に使用するものと同じのを使用するように #12336 - Enhance: 絵文字のオートコンプリート機能強化 #12364 - Enhance: ユーザーのRawデータを表示するページが復活 - Enhance: リアクション選択時に音を鳴らせるように diff --git a/packages/frontend/src/boot/main-boot.ts b/packages/frontend/src/boot/main-boot.ts index 71236e4c53..88e2f83895 100644 --- a/packages/frontend/src/boot/main-boot.ts +++ b/packages/frontend/src/boot/main-boot.ts @@ -19,6 +19,7 @@ import { claimAchievement, claimedAchievements } from '@/scripts/achievements.js import { mainRouter } from '@/router.js'; import { initializeSw } from '@/scripts/initialize-sw.js'; import { deckStore } from '@/ui/deck/deck-store.js'; +import { emojiPicker } from '@/scripts/emoji-picker.js'; export async function mainBoot() { const { isClientUpdated } = await common(() => createApp( @@ -30,6 +31,7 @@ export async function mainBoot() { )); reactionPicker.init(); + emojiPicker.init(); if (isClientUpdated && $i) { popup(defineAsyncComponent(() => import('@/components/MkUpdated.vue')), {}, {}, 'closed'); diff --git a/packages/frontend/src/components/MkEmojiPicker.vue b/packages/frontend/src/components/MkEmojiPicker.vue index ecff2b5ace..b5e5a0260c 100644 --- a/packages/frontend/src/components/MkEmojiPicker.vue +++ b/packages/frontend/src/components/MkEmojiPicker.vue @@ -36,7 +36,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-
+
-
+
+
+ +
{{ i18n.ts.userPagePinTip }}