From 44cafbb9f238e13e079135b96c4a791fb3b7faf0 Mon Sep 17 00:00:00 2001
From: Kisaragi <48310258+KisaragiEffective@users.noreply.github.com>
Date: Wed, 29 May 2024 07:11:29 +0900
Subject: [PATCH 1/9] refactor: avoid `as any[]` on
 FetchInstanceMetadataService.ts (#13905)

* refactor: avoid `as any[]` on FetchInstanceMetadataService.ts

* apply suggestion

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
---
 packages/backend/src/core/FetchInstanceMetadataService.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/backend/src/core/FetchInstanceMetadataService.ts b/packages/backend/src/core/FetchInstanceMetadataService.ts
index 8d173855f3..aa16468ecb 100644
--- a/packages/backend/src/core/FetchInstanceMetadataService.ts
+++ b/packages/backend/src/core/FetchInstanceMetadataService.ts
@@ -154,7 +154,7 @@ export class FetchInstanceMetadataService {
 				throw new Error('No wellknown links');
 			}
 
-			const links = wellknown.links as any[];
+			const links = wellknown.links as ({ rel: string, href: string; })[];
 
 			const link1_0 = links.find(link => link.rel === 'http://nodeinfo.diaspora.software/ns/schema/1.0');
 			const link2_0 = links.find(link => link.rel === 'http://nodeinfo.diaspora.software/ns/schema/2.0');

From e57ce4fa0f663210514ecda728562a73c0fe9c5e Mon Sep 17 00:00:00 2001
From: Kisaragi <48310258+KisaragiEffective@users.noreply.github.com>
Date: Wed, 29 May 2024 07:12:20 +0900
Subject: [PATCH 2/9] chore(backend): rename local variable (#13904)

much -> matched
---
 packages/backend/src/core/DriveService.ts | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/packages/backend/src/core/DriveService.ts b/packages/backend/src/core/DriveService.ts
index 63fa26f69d..26cf532c70 100644
--- a/packages/backend/src/core/DriveService.ts
+++ b/packages/backend/src/core/DriveService.ts
@@ -497,20 +497,20 @@ export class DriveService {
 
 		if (user && !force) {
 		// Check if there is a file with the same hash
-			const much = await this.driveFilesRepository.findOneBy({
+			const matched = await this.driveFilesRepository.findOneBy({
 				md5: info.md5,
 				userId: user.id,
 			});
 
-			if (much) {
-				this.registerLogger.info(`file with same hash is found: ${much.id}`);
-				if (sensitive && !much.isSensitive) {
+			if (matched) {
+				this.registerLogger.info(`file with same hash is found: ${matched.id}`);
+				if (sensitive && !matched.isSensitive) {
 					// The file is federated as sensitive for this time, but was federated as non-sensitive before.
 					// Therefore, update the file to sensitive.
-					await this.driveFilesRepository.update({ id: much.id }, { isSensitive: true });
-					much.isSensitive = true;
+					await this.driveFilesRepository.update({ id: matched.id }, { isSensitive: true });
+					matched.isSensitive = true;
 				}
-				return much;
+				return matched;
 			}
 		}
 

From cf670e8a3dc9830110312b54eceaea29cf20495c Mon Sep 17 00:00:00 2001
From: Kisaragi <48310258+KisaragiEffective@users.noreply.github.com>
Date: Wed, 29 May 2024 07:12:50 +0900
Subject: [PATCH 3/9] refactor(backend): avoid `as any` on
 CustomEmojiService.ts (#13903)

---
 packages/backend/src/core/CustomEmojiService.ts | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/packages/backend/src/core/CustomEmojiService.ts b/packages/backend/src/core/CustomEmojiService.ts
index 1c75566755..b1feca7fb4 100644
--- a/packages/backend/src/core/CustomEmojiService.ts
+++ b/packages/backend/src/core/CustomEmojiService.ts
@@ -346,10 +346,11 @@ export class CustomEmojiService implements OnApplicationShutdown {
 	@bindThis
 	public async populateEmojis(emojiNames: string[], noteUserHost: string | null): Promise<Record<string, string>> {
 		const emojis = await Promise.all(emojiNames.map(x => this.populateEmoji(x, noteUserHost)));
-		const res = {} as any;
+		const res = {} as Record<string, string>;
 		for (let i = 0; i < emojiNames.length; i++) {
-			if (emojis[i] != null) {
-				res[emojiNames[i]] = emojis[i];
+			const resolvedEmoji = emojis[i];
+			if (resolvedEmoji != null) {
+				res[emojiNames[i]] = resolvedEmoji;
 			}
 		}
 		return res;

From eaadd643ebdfb7b9cc5bd04eb68af740ced52c87 Mon Sep 17 00:00:00 2001
From: zyoshoka <107108195+zyoshoka@users.noreply.github.com>
Date: Wed, 29 May 2024 20:57:48 +0900
Subject: [PATCH 4/9] chore(misskey-js): fix `repository` and add `license` in
 `package.json` (#13902)

---
 packages/misskey-js/package.json | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json
index 6badc7f3ee..f496d8bb1d 100644
--- a/packages/misskey-js/package.json
+++ b/packages/misskey-js/package.json
@@ -3,6 +3,7 @@
 	"name": "misskey-js",
 	"version": "2024.3.1",
 	"description": "Misskey SDK for JavaScript",
+	"license": "MIT",
 	"main": "./built/index.js",
 	"types": "./built/index.d.ts",
 	"exports": {
@@ -30,7 +31,8 @@
 	},
 	"repository": {
 		"type": "git",
-		"url": "git+https://github.com/misskey-dev/misskey.js.git"
+		"url": "https://github.com/misskey-dev/misskey.git",
+		"directory": "packages/misskey-js"
 	},
 	"devDependencies": {
 		"@microsoft/api-extractor": "7.43.1",

From 24d4124ffcd3b26d2f9fbec87f917b584f494ece Mon Sep 17 00:00:00 2001
From: KanariKanaru <93921745+kanarikanaru@users.noreply.github.com>
Date: Thu, 30 May 2024 17:36:58 +0900
Subject: [PATCH 5/9] =?UTF-8?q?fix(frontend):=20=E3=83=8E=E3=83=BC?=
 =?UTF-8?q?=E3=83=88=E3=81=AB=E3=83=86=E3=82=AD=E3=82=B9=E3=83=88=E3=81=8C?=
 =?UTF-8?q?=E3=81=AA=E3=81=8F=E3=81=A6=E3=82=82=E3=83=95=E3=82=A1=E3=82=A4?=
 =?UTF-8?q?=E3=83=AB=E3=81=8C5=E3=81=A4=E4=BB=A5=E4=B8=8A=E3=81=82?=
 =?UTF-8?q?=E3=82=8B=E3=81=A8=E3=81=8D=E3=81=AF=E6=8A=98=E3=82=8A=E3=81=9F?=
 =?UTF-8?q?=E3=81=9F=E3=82=80=E3=82=88=E3=81=86=E3=81=AB=20(#13907)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix: ノートにテキストがなくてもファイルが5つ以上あるときは折りたたむように

* 冗長な記述を修正

* Update CHANGELOG.md
---
 CHANGELOG.md                               |  1 +
 packages/frontend/src/scripts/collapsed.ts | 19 ++++++++++---------
 2 files changed, 11 insertions(+), 9 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4091668b54..865684aa20 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -73,6 +73,7 @@
 - Fix: 通知をグループ化している際に、人数が正常に表示されないことがある問題を修正
 - Fix: 連合なしの状態の読み書きができない問題を修正
 - Fix: `/share` で日本語等を含むurlがurlエンコードされない問題を修正
+- Fix: ファイルを5つ以上添付してもテキストがないとノートが折りたたまれない問題を修正
 
 ### Server
 - Enhance: エンドポイント`antennas/update`の必須項目を`antennaId`のみに
diff --git a/packages/frontend/src/scripts/collapsed.ts b/packages/frontend/src/scripts/collapsed.ts
index 237bd37c7a..4ec88a3c65 100644
--- a/packages/frontend/src/scripts/collapsed.ts
+++ b/packages/frontend/src/scripts/collapsed.ts
@@ -6,15 +6,16 @@
 import * as Misskey from 'misskey-js';
 
 export function shouldCollapsed(note: Misskey.entities.Note, urls: string[]): boolean {
-	const collapsed = note.cw == null && note.text != null && (
-		(note.text.includes('$[x2')) ||
-		(note.text.includes('$[x3')) ||
-		(note.text.includes('$[x4')) ||
-		(note.text.includes('$[scale')) ||
-		(note.text.split('\n').length > 9) ||
-		(note.text.length > 500) ||
-		(note.files.length >= 5) ||
-		(urls.length >= 4)
+	const collapsed = note.cw == null && (
+		note.text != null && (
+			(note.text.includes('$[x2')) ||
+			(note.text.includes('$[x3')) ||
+			(note.text.includes('$[x4')) ||
+			(note.text.includes('$[scale')) ||
+			(note.text.split('\n').length > 9) ||
+			(note.text.length > 500) ||
+			(urls.length >= 4)
+		) || note.files.length >= 5
 	);
 
 	return collapsed;

From ac4a001e9f193e4727a8e65e59978a9464a56d75 Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Fri, 31 May 2024 10:11:11 +0900
Subject: [PATCH 6/9] fix code style

---
 .../MkCustomEmojiDetailedDialog.vue           | 108 +++++++++---------
 1 file changed, 56 insertions(+), 52 deletions(-)

diff --git a/packages/frontend/src/components/MkCustomEmojiDetailedDialog.vue b/packages/frontend/src/components/MkCustomEmojiDetailedDialog.vue
index 84b5375a41..c7f1288729 100644
--- a/packages/frontend/src/components/MkCustomEmojiDetailedDialog.vue
+++ b/packages/frontend/src/components/MkCustomEmojiDetailedDialog.vue
@@ -4,77 +4,81 @@ SPDX-License-Identifier: AGPL-3.0-only
 -->
 
 <template>
-  <MkModalWindow ref="dialogEl" @close="cancel()" @closed="$emit('closed')">
-    <template #header>:{{ emoji.name }}:</template>
-    <template #default>
-      <MkSpacer>
-        <div style="display: flex; flex-direction: column; gap: 1em;">
-          <div :class="$style.emojiImgWrapper">
-            <MkCustomEmoji :name="emoji.name" :normal="true" :useOriginalSize="true" style="height: 100%;"></MkCustomEmoji>
-          </div>
-          <MkKeyValue :copy="`:${emoji.name}:`">
-            <template #key>{{ i18n.ts.name }}</template>
-            <template #value>{{ emoji.name }}</template>
-          </MkKeyValue>
-          <MkKeyValue>
-            <template #key>{{ i18n.ts.tags }}</template>
-            <template #value>
-              <div v-if="emoji.aliases.length === 0">{{ i18n.ts.none }}</div>
-              <div v-else :class="$style.aliases">
-                <span v-for="alias in emoji.aliases" :key="alias" :class="$style.alias">
-                  {{ alias }}
-                </span>
-              </div>
-            </template>
-          </MkKeyValue>
-          <MkKeyValue>
-            <template #key>{{ i18n.ts.category }}</template>
-            <template #value>{{ emoji.category ?? i18n.ts.none }}</template>
-          </MkKeyValue>
-          <MkKeyValue>
-            <template #key>{{ i18n.ts.sensitive }}</template>
-            <template #value>{{ emoji.isSensitive ? i18n.ts.yes : i18n.ts.no }}</template>
-          </MkKeyValue>
-          <MkKeyValue>
-            <template #key>{{ i18n.ts.localOnly }}</template>
-            <template #value>{{ emoji.localOnly ? i18n.ts.yes : i18n.ts.no }}</template>
-          </MkKeyValue>
-          <MkKeyValue>
-            <template #key>{{ i18n.ts.license }}</template>
-            <template #value><Mfm :text="emoji.license ?? i18n.ts.none" /></template>
-          </MkKeyValue>
-          <MkKeyValue :copy="emoji.url">
-            <template #key>{{ i18n.ts.emojiUrl }}</template>
-            <template #value>
-              <MkLink :url="emoji.url" target="_blank">{{ emoji.url }}</MkLink>
-            </template>
-          </MkKeyValue>
-        </div>
-      </MkSpacer>
-    </template>
-  </MkModalWindow>
+<MkModalWindow ref="dialogEl" @close="cancel()" @closed="$emit('closed')">
+	<template #header>:{{ emoji.name }}:</template>
+	<template #default>
+		<MkSpacer>
+			<div style="display: flex; flex-direction: column; gap: 1em;">
+				<div :class="$style.emojiImgWrapper">
+					<MkCustomEmoji :name="emoji.name" :normal="true" :useOriginalSize="true" style="height: 100%;"></MkCustomEmoji>
+				</div>
+				<MkKeyValue :copy="`:${emoji.name}:`">
+					<template #key>{{ i18n.ts.name }}</template>
+					<template #value>{{ emoji.name }}</template>
+				</MkKeyValue>
+				<MkKeyValue>
+					<template #key>{{ i18n.ts.tags }}</template>
+					<template #value>
+						<div v-if="emoji.aliases.length === 0">{{ i18n.ts.none }}</div>
+						<div v-else :class="$style.aliases">
+							<span v-for="alias in emoji.aliases" :key="alias" :class="$style.alias">
+								{{ alias }}
+							</span>
+						</div>
+					</template>
+				</MkKeyValue>
+				<MkKeyValue>
+					<template #key>{{ i18n.ts.category }}</template>
+					<template #value>{{ emoji.category ?? i18n.ts.none }}</template>
+				</MkKeyValue>
+				<MkKeyValue>
+					<template #key>{{ i18n.ts.sensitive }}</template>
+					<template #value>{{ emoji.isSensitive ? i18n.ts.yes : i18n.ts.no }}</template>
+				</MkKeyValue>
+				<MkKeyValue>
+					<template #key>{{ i18n.ts.localOnly }}</template>
+					<template #value>{{ emoji.localOnly ? i18n.ts.yes : i18n.ts.no }}</template>
+				</MkKeyValue>
+				<MkKeyValue>
+					<template #key>{{ i18n.ts.license }}</template>
+					<template #value><Mfm :text="emoji.license ?? i18n.ts.none"/></template>
+				</MkKeyValue>
+				<MkKeyValue :copy="emoji.url">
+					<template #key>{{ i18n.ts.emojiUrl }}</template>
+					<template #value>
+						<MkLink :url="emoji.url" target="_blank">{{ emoji.url }}</MkLink>
+					</template>
+				</MkKeyValue>
+			</div>
+		</MkSpacer>
+	</template>
+</MkModalWindow>
 </template>
 
 <script lang="ts" setup>
 import * as Misskey from 'misskey-js';
 import { defineProps, shallowRef } from 'vue';
+import MkLink from '@/components/MkLink.vue';
 import { i18n } from '@/i18n.js';
 import MkModalWindow from '@/components/MkModalWindow.vue';
 import MkKeyValue from '@/components/MkKeyValue.vue';
-import MkLink from './MkLink.vue';
+
 const props = defineProps<{
   emoji: Misskey.entities.EmojiDetailed,
 }>();
+
 const emit = defineEmits<{
 	(ev: 'ok', cropped: Misskey.entities.DriveFile): void;
 	(ev: 'cancel'): void;
 	(ev: 'closed'): void;
 }>();
+
 const dialogEl = shallowRef<InstanceType<typeof MkModalWindow>>();
-const cancel = () => {
+
+function cancel() {
 	emit('cancel');
 	dialogEl.value!.close();
-};
+}
 </script>
 
 <style lang="scss" module>

From be11fd75085e8f8c000a42b40bd583894121a708 Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Fri, 31 May 2024 10:12:23 +0900
Subject: [PATCH 7/9] =?UTF-8?q?enhance:=20=E3=82=B5=E3=83=BC=E3=83=90?=
 =?UTF-8?q?=E3=83=BC=E3=81=AE=E3=81=8A=E5=95=8F=E3=81=84=E5=90=88=E3=82=8F?=
 =?UTF-8?q?=E3=81=9B=E5=85=88URL=E3=82=92=E8=A8=AD=E5=AE=9A=E3=81=A7?=
 =?UTF-8?q?=E3=81=8D=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 CHANGELOG.md                                  |  1 +
 locales/index.d.ts                            |  8 ++++++++
 locales/ja-JP.yml                             |  2 ++
 .../migration/1717117195275-inquiryUrl.js     | 20 +++++++++++++++++++
 .../src/core/entities/MetaEntityService.ts    |  1 +
 packages/backend/src/models/Meta.ts           |  6 ++++++
 .../backend/src/models/json-schema/meta.ts    |  4 ++++
 .../src/server/NodeinfoServerService.ts       | 13 ++++++------
 .../src/server/api/endpoints/admin/meta.ts    |  5 +++++
 .../server/api/endpoints/admin/update-meta.ts |  5 +++++
 .../frontend/src/pages/admin/moderation.vue   |  9 +++++++++
 packages/frontend/src/pages/contact.vue       | 18 ++++++++++++++++-
 packages/misskey-js/src/autogen/types.ts      |  3 +++
 13 files changed, 88 insertions(+), 7 deletions(-)
 create mode 100644 packages/backend/migration/1717117195275-inquiryUrl.js

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 865684aa20..efd07da891 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -20,6 +20,7 @@
 - Enhance: Goneを出さずに終了したサーバーへの配信停止を自動的に行うように
   - もしそのようなサーバーからから配信が届いた場合には自動的に配信を再開します
 - Enhance: 配信停止の理由を表示するように
+- Enhance: サーバーのお問い合わせ先URLを設定できるようになりました
 - Fix: Play作成時に設定した公開範囲が機能していない問題を修正
 - Fix: 正規化されていない状態のhashtagが連合されてきたhtmlに含まれているとhashtagが正しくhashtagに復元されない問題を修正
 - Fix: みつけるのアンケート欄にてチャンネルのアンケートが含まれてしまう問題を修正
diff --git a/locales/index.d.ts b/locales/index.d.ts
index d4ded0bb5b..91bbe4ccb6 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -5471,6 +5471,14 @@ export interface Locale extends ILocale {
          * 有効にすると、タイムラインがキャッシュされていない場合にDBへ追加で問い合わせを行うフォールバック処理を行います。無効にすると、フォールバック処理を行わないことでさらにサーバーの負荷を軽減することができますが、タイムラインが取得できる範囲に制限が生じます。
          */
         "fanoutTimelineDbFallbackDescription": string;
+        /**
+         * 問い合わせ先URL
+         */
+        "inquiryUrl": string;
+        /**
+         * サーバー運営者へのお問い合わせフォームのURLや、運営者の連絡先等が記載されたWebページのURLを指定します。
+         */
+        "inquiryUrlDescription": string;
     };
     "_accountMigration": {
         /**
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index d7ceb971af..b7083b4942 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1383,6 +1383,8 @@ _serverSettings:
   fanoutTimelineDescription: "有効にすると、各種タイムラインを取得する際のパフォーマンスが大幅に向上し、データベースへの負荷を軽減することが可能です。ただし、Redisのメモリ使用量は増加します。サーバーのメモリ容量が少ない場合、または動作が不安定な場合は無効にすることができます。"
   fanoutTimelineDbFallback: "データベースへのフォールバック"
   fanoutTimelineDbFallbackDescription: "有効にすると、タイムラインがキャッシュされていない場合にDBへ追加で問い合わせを行うフォールバック処理を行います。無効にすると、フォールバック処理を行わないことでさらにサーバーの負荷を軽減することができますが、タイムラインが取得できる範囲に制限が生じます。"
+  inquiryUrl: "問い合わせ先URL"
+  inquiryUrlDescription: "サーバー運営者へのお問い合わせフォームのURLや、運営者の連絡先等が記載されたWebページのURLを指定します。"
 
 _accountMigration:
   moveFrom: "別のアカウントからこのアカウントに移行"
diff --git a/packages/backend/migration/1717117195275-inquiryUrl.js b/packages/backend/migration/1717117195275-inquiryUrl.js
new file mode 100644
index 0000000000..3834df06d4
--- /dev/null
+++ b/packages/backend/migration/1717117195275-inquiryUrl.js
@@ -0,0 +1,20 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+export class InquiryUrl1717117195275 {
+    name = 'InquiryUrl1717117195275'
+
+    async up(queryRunner) {
+        await queryRunner.query(`ALTER TABLE "meta" RENAME COLUMN "trustedLinkUrlPatterns" TO "inquiryUrl"`);
+        await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "inquiryUrl"`);
+        await queryRunner.query(`ALTER TABLE "meta" ADD "inquiryUrl" character varying(1024)`);
+    }
+
+    async down(queryRunner) {
+        await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "inquiryUrl"`);
+        await queryRunner.query(`ALTER TABLE "meta" ADD "inquiryUrl" character varying(3072) array NOT NULL DEFAULT '{}'`);
+        await queryRunner.query(`ALTER TABLE "meta" RENAME COLUMN "inquiryUrl" TO "trustedLinkUrlPatterns"`);
+    }
+}
diff --git a/packages/backend/src/core/entities/MetaEntityService.ts b/packages/backend/src/core/entities/MetaEntityService.ts
index 9d054ab6a1..5dfec589e1 100644
--- a/packages/backend/src/core/entities/MetaEntityService.ts
+++ b/packages/backend/src/core/entities/MetaEntityService.ts
@@ -67,6 +67,7 @@ export class MetaEntityService {
 			feedbackUrl: instance.feedbackUrl,
 			impressumUrl: instance.impressumUrl,
 			privacyPolicyUrl: instance.privacyPolicyUrl,
+			inquiryUrl: instance.inquiryUrl,
 			disableRegistration: instance.disableRegistration,
 			emailRequiredForSignup: instance.emailRequiredForSignup,
 			enableHcaptcha: instance.enableHcaptcha,
diff --git a/packages/backend/src/models/Meta.ts b/packages/backend/src/models/Meta.ts
index 04a34bbbb4..ad306fcad6 100644
--- a/packages/backend/src/models/Meta.ts
+++ b/packages/backend/src/models/Meta.ts
@@ -376,6 +376,12 @@ export class MiMeta {
 	})
 	public privacyPolicyUrl: string | null;
 
+	@Column('varchar', {
+		length: 1024,
+		nullable: true,
+	})
+	public inquiryUrl: string | null;
+
 	@Column('varchar', {
 		length: 8192,
 		nullable: true,
diff --git a/packages/backend/src/models/json-schema/meta.ts b/packages/backend/src/models/json-schema/meta.ts
index 473339a1ad..e7bc6356e5 100644
--- a/packages/backend/src/models/json-schema/meta.ts
+++ b/packages/backend/src/models/json-schema/meta.ts
@@ -227,6 +227,10 @@ export const packedMetaLiteSchema = {
 			type: 'string',
 			optional: false, nullable: true,
 		},
+		inquiryUrl: {
+			type: 'string',
+			optional: false, nullable: true,
+		},
 		serverRules: {
 			type: 'array',
 			optional: false, nullable: false,
diff --git a/packages/backend/src/server/NodeinfoServerService.ts b/packages/backend/src/server/NodeinfoServerService.ts
index c1e5af08c9..cc18997fdc 100644
--- a/packages/backend/src/server/NodeinfoServerService.ts
+++ b/packages/backend/src/server/NodeinfoServerService.ts
@@ -37,12 +37,12 @@ export class NodeinfoServerService {
 	@bindThis
 	public getLinks() {
 		return [{
-				rel: 'http://nodeinfo.diaspora.software/ns/schema/2.1',
-				href: this.config.url + nodeinfo2_1path
-			}, {
-				rel: 'http://nodeinfo.diaspora.software/ns/schema/2.0',
-				href: this.config.url + nodeinfo2_0path,
-			}];
+			rel: 'http://nodeinfo.diaspora.software/ns/schema/2.1',
+			href: this.config.url + nodeinfo2_1path,
+		}, {
+			rel: 'http://nodeinfo.diaspora.software/ns/schema/2.0',
+			href: this.config.url + nodeinfo2_0path,
+		}];
 	}
 
 	@bindThis
@@ -108,6 +108,7 @@ export class NodeinfoServerService {
 					langs: meta.langs,
 					tosUrl: meta.termsOfServiceUrl,
 					privacyPolicyUrl: meta.privacyPolicyUrl,
+					inquiryUrl: meta.inquiryUrl,
 					impressumUrl: meta.impressumUrl,
 					repositoryUrl: meta.repositoryUrl,
 					feedbackUrl: meta.feedbackUrl,
diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts
index f4ff573271..eee02a7123 100644
--- a/packages/backend/src/server/api/endpoints/admin/meta.ts
+++ b/packages/backend/src/server/api/endpoints/admin/meta.ts
@@ -427,6 +427,10 @@ export const meta = {
 				type: 'string',
 				optional: false, nullable: true,
 			},
+			inquiryUrl: {
+				type: 'string',
+				optional: false, nullable: true,
+			},
 			repositoryUrl: {
 				type: 'string',
 				optional: false, nullable: true,
@@ -513,6 +517,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				feedbackUrl: instance.feedbackUrl,
 				impressumUrl: instance.impressumUrl,
 				privacyPolicyUrl: instance.privacyPolicyUrl,
+				inquiryUrl: instance.inquiryUrl,
 				disableRegistration: instance.disableRegistration,
 				emailRequiredForSignup: instance.emailRequiredForSignup,
 				enableHcaptcha: instance.enableHcaptcha,
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 2f62d30ada..4e28ee6877 100644
--- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts
+++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts
@@ -107,6 +107,7 @@ export const paramDef = {
 		feedbackUrl: { type: 'string', nullable: true },
 		impressumUrl: { type: 'string', nullable: true },
 		privacyPolicyUrl: { type: 'string', nullable: true },
+		inquiryUrl: { type: 'string', nullable: true },
 		useObjectStorage: { type: 'boolean' },
 		objectStorageBaseUrl: { type: 'string', nullable: true },
 		objectStorageBucket: { type: 'string', nullable: true },
@@ -422,6 +423,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				set.privacyPolicyUrl = ps.privacyPolicyUrl;
 			}
 
+			if (ps.inquiryUrl !== undefined) {
+				set.inquiryUrl = ps.inquiryUrl;
+			}
+
 			if (ps.useObjectStorage !== undefined) {
 				set.useObjectStorage = ps.useObjectStorage;
 			}
diff --git a/packages/frontend/src/pages/admin/moderation.vue b/packages/frontend/src/pages/admin/moderation.vue
index 9efb34ac9a..a75799696d 100644
--- a/packages/frontend/src/pages/admin/moderation.vue
+++ b/packages/frontend/src/pages/admin/moderation.vue
@@ -30,6 +30,12 @@ SPDX-License-Identifier: AGPL-3.0-only
 						<template #label>{{ i18n.ts.privacyPolicyUrl }}</template>
 					</MkInput>
 
+					<MkInput v-model="inquiryUrl" type="url">
+						<template #prefix><i class="ti ti-link"></i></template>
+						<template #label>{{ i18n.ts._serverSettings.inquiryUrl }}</template>
+						<template #caption>{{ i18n.ts._serverSettings.inquiryUrlDescription }}</template>
+					</MkInput>
+
 					<MkTextarea v-model="preservedUsernames">
 						<template #label>{{ i18n.ts.preservedUsernames }}</template>
 						<template #caption>{{ i18n.ts.preservedUsernamesDescription }}</template>
@@ -86,6 +92,7 @@ const hiddenTags = ref<string>('');
 const preservedUsernames = ref<string>('');
 const tosUrl = ref<string | null>(null);
 const privacyPolicyUrl = ref<string | null>(null);
+const inquiryUrl = ref<string | null>(null);
 
 async function init() {
 	const meta = await misskeyApi('admin/meta');
@@ -97,6 +104,7 @@ async function init() {
 	preservedUsernames.value = meta.preservedUsernames.join('\n');
 	tosUrl.value = meta.tosUrl;
 	privacyPolicyUrl.value = meta.privacyPolicyUrl;
+	inquiryUrl.value = meta.inquiryUrl;
 }
 
 function save() {
@@ -105,6 +113,7 @@ function save() {
 		emailRequiredForSignup: emailRequiredForSignup.value,
 		tosUrl: tosUrl.value,
 		privacyPolicyUrl: privacyPolicyUrl.value,
+		inquiryUrl: inquiryUrl.value,
 		sensitiveWords: sensitiveWords.value.split('\n'),
 		prohibitedWords: prohibitedWords.value.split('\n'),
 		hiddenTags: hiddenTags.value.split('\n'),
diff --git a/packages/frontend/src/pages/contact.vue b/packages/frontend/src/pages/contact.vue
index 3a694a7132..bcdcf43275 100644
--- a/packages/frontend/src/pages/contact.vue
+++ b/packages/frontend/src/pages/contact.vue
@@ -7,7 +7,21 @@ SPDX-License-Identifier: AGPL-3.0-only
 <MkStickyContainer>
 	<template #header><MkPageHeader/></template>
 	<MkSpacer :contentMax="600" :marginMin="20">
-		<div>{{ instance.maintainerEmail }}</div>
+		<div class="_gaps">
+			<MkKeyValue>
+				<template #key>{{ i18n.ts.inquiry }}</template>
+				<template #value>
+					<MkLink :url="instance.inquiryUrl" target="_blank">{{ instance.inquiryUrl }}</MkLink>
+				</template>
+			</MkKeyValue>
+
+			<MkKeyValue>
+				<template #key>{{ i18n.ts.email }}</template>
+				<template #value>
+					<div>{{ instance.maintainerEmail }}</div>
+				</template>
+			</MkKeyValue>
+		</div>
 	</MkSpacer>
 </MkStickyContainer>
 </template>
@@ -16,6 +30,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 import { i18n } from '@/i18n.js';
 import { definePageMetadata } from '@/scripts/page-metadata.js';
 import { instance } from '@/instance.js';
+import MkKeyValue from '@/components/MkKeyValue.vue';
+import MkLink from '@/components/MkLink.vue';
 
 definePageMetadata(() => ({
 	title: i18n.ts.inquiry,
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index 11567677c9..9beb49fb64 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -4831,6 +4831,7 @@ export type components = {
       impressumUrl: string | null;
       logoImageUrl: string | null;
       privacyPolicyUrl: string | null;
+      inquiryUrl: string | null;
       serverRules: string[];
       themeColor: string | null;
       policies: components['schemas']['RolePolicies'];
@@ -4978,6 +4979,7 @@ export type operations = {
             shortName: string | null;
             objectStorageS3ForcePathStyle: boolean;
             privacyPolicyUrl: string | null;
+            inquiryUrl: string | null;
             repositoryUrl: string | null;
             /**
              * @deprecated
@@ -8906,6 +8908,7 @@ export type operations = {
           feedbackUrl?: string | null;
           impressumUrl?: string | null;
           privacyPolicyUrl?: string | null;
+          inquiryUrl?: string | null;
           useObjectStorage?: boolean;
           objectStorageBaseUrl?: string | null;
           objectStorageBucket?: string | null;

From 5b8f8e7087cb447e43724bd28b4bdfdf03d328c2 Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Fri, 31 May 2024 11:24:17 +0900
Subject: [PATCH 8/9] fix(backend): fix backward compatibility of antenna

---
 packages/backend/src/core/entities/AntennaEntityService.ts | 1 +
 packages/backend/src/models/json-schema/antenna.ts         | 5 +++++
 2 files changed, 6 insertions(+)

diff --git a/packages/backend/src/core/entities/AntennaEntityService.ts b/packages/backend/src/core/entities/AntennaEntityService.ts
index 4a17a3d80f..e770028af3 100644
--- a/packages/backend/src/core/entities/AntennaEntityService.ts
+++ b/packages/backend/src/core/entities/AntennaEntityService.ts
@@ -43,6 +43,7 @@ export class AntennaEntityService {
 			withFile: antenna.withFile,
 			isActive: antenna.isActive,
 			hasUnreadNote: false, // TODO
+			notify: false, // 後方互換性のため
 		};
 	}
 }
diff --git a/packages/backend/src/models/json-schema/antenna.ts b/packages/backend/src/models/json-schema/antenna.ts
index c4ac358fa6..b5b9a5b42c 100644
--- a/packages/backend/src/models/json-schema/antenna.ts
+++ b/packages/backend/src/models/json-schema/antenna.ts
@@ -95,5 +95,10 @@ export const packedAntennaSchema = {
 			optional: false, nullable: false,
 			default: false,
 		},
+		notify: {
+			type: 'boolean',
+			optional: false, nullable: false,
+			default: false,
+		},
 	},
 } as const;

From 00827472374554c9795fe372d1a605ea733441fc Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Fri, 31 May 2024 13:19:37 +0900
Subject: [PATCH 9/9] New Crowdin updates (#13892)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Chinese Traditional)
---
 locales/zh-CN.yml |  2 ++
 locales/zh-TW.yml | 11 ++++++++---
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml
index 3e500f8642..f92d997b5a 100644
--- a/locales/zh-CN.yml
+++ b/locales/zh-CN.yml
@@ -316,6 +316,7 @@ selectFile: "选择文件"
 selectFiles: "选择文件"
 selectFolder: "选择文件夹"
 selectFolders: "选择多个文件夹"
+fileNotSelected: "未选择文件"
 renameFile: "重命名文件"
 folderName: "文件夹名称"
 createFolder: "创建文件夹"
@@ -2358,6 +2359,7 @@ _deck:
   alwaysShowMainColumn: "总是显示主列"
   columnAlign: "列对齐"
   addColumn: "添加列"
+  newNoteNotificationSettings: "新帖子通知设定"
   configureColumn: "列设置"
   swapLeft: "向左移动"
   swapRight: "向右移动"
diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml
index fed7b642dc..aac3f7662c 100644
--- a/locales/zh-TW.yml
+++ b/locales/zh-TW.yml
@@ -316,6 +316,7 @@ selectFile: "選擇檔案"
 selectFiles: "選擇檔案"
 selectFolder: "選擇資料夾"
 selectFolders: "選擇資料夾"
+fileNotSelected: "尚未選擇檔案"
 renameFile: "重新命名檔案"
 folderName: "資料夾名稱"
 createFolder: "新增資料夾"
@@ -471,7 +472,7 @@ retype: "重新輸入"
 noteOf: "{user}的貼文"
 quoteAttached: "引用"
 quoteQuestion: "是否要引用?"
-attachAsFileQuestion: "剪貼簿的文字較長。請問是否要改成附加檔案呢?"
+attachAsFileQuestion: "剪貼簿的文字較長。請問是否要將其以文字檔的方式附加呢?"
 noMessagesYet: "沒有訊息"
 newMessageExists: "有新的訊息"
 onlyOneFileCanBeAttached: "只能加入一個附件"
@@ -1025,6 +1026,7 @@ thisPostMayBeAnnoyingHome: "發佈到首頁"
 thisPostMayBeAnnoyingCancel: "退出"
 thisPostMayBeAnnoyingIgnore: "直接發佈貼文"
 collapseRenotes: "省略顯示已看過的轉發貼文"
+collapseRenotesDescription: "將已做過反應和轉發的貼文折疊顯示。"
 internalServerError: "內部伺服器錯誤"
 internalServerErrorDescription: "內部伺服器出現意外錯誤。"
 copyErrorInfo: "複製錯誤資訊"
@@ -1241,8 +1243,8 @@ alwaysConfirmFollow: "點擊追隨時總是顯示確認訊息"
 inquiry: "聯絡我們"
 _delivery:
   status: "傳送狀態"
-  stop: "已凍結"
-  resume: "繼續傳送"
+  stop: "停止傳送"
+  resume: "恢復傳送"
   _type:
     none: "直播中"
     manuallySuspended: "手動暫停中"
@@ -1373,6 +1375,8 @@ _serverSettings:
   fanoutTimelineDescription: "如果啟用的話,檢索各個時間軸的性能會顯著提昇,資料庫的負荷也會減少。不過,Redis 的記憶體使用量會增加。如果伺服器的記憶體容量比較少或者運行不穩定,可以停用。"
   fanoutTimelineDbFallback: "資料庫的回退"
   fanoutTimelineDbFallbackDescription: "若啟用,在時間軸沒有快取的情況下將執行回退處理以額外查詢資料庫。若停用,可以透過不執行回退處理來進一步減少伺服器的負荷,但會限制可取得的時間軸範圍。"
+  inquiryUrl: "聯絡表單網址"
+  inquiryUrlDescription: "指定伺服器運營者的聯絡表單網址或包含運營者聯絡資訊網頁的網址。"
 _accountMigration:
   moveFrom: "從其他帳戶遷移到這個帳戶"
   moveFromSub: "為另一個帳戶建立別名"
@@ -2358,6 +2362,7 @@ _deck:
   alwaysShowMainColumn: "總是顯示主欄"
   columnAlign: "對齊欄位"
   addColumn: "新增欄位"
+  newNoteNotificationSettings: "新貼文通知的設定"
   configureColumn: "欄位的設定"
   swapLeft: "向左移動"
   swapRight: "向右移動"