diff --git a/CHANGELOG.md b/CHANGELOG.md index 10ddc33d9d..4fa6c98f96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,7 @@ - ユーザーにロールが期限付きでアサインされている場合、その期限をユーザーのモデレーションページで確認できるようになりました - identicon生成を無効にしてパフォーマンスを向上させることができるようになりました - サーバーのマシン情報の公開を無効にしてパフォーマンスを向上させることができるようになりました +- チャンネルをセンシティブ指定できるようになりました ### Client - deck UIのカラムのメニューからアンテナとリストの編集画面を開けるように diff --git a/packages/backend/migration/1690782653311-SensitiveChannel.js b/packages/backend/migration/1690782653311-SensitiveChannel.js new file mode 100644 index 0000000000..e76dda5180 --- /dev/null +++ b/packages/backend/migration/1690782653311-SensitiveChannel.js @@ -0,0 +1,17 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class SensitiveChannel1690782653311 { + name = 'SensitiveChannel1690782653311' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "channel" + ADD "isSensitive" boolean NOT NULL DEFAULT false`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "channel" DROP COLUMN "isSensitive"`); + } +} diff --git a/packages/backend/src/core/entities/ChannelEntityService.ts b/packages/backend/src/core/entities/ChannelEntityService.ts index f62daa21c9..042e7c3005 100644 --- a/packages/backend/src/core/entities/ChannelEntityService.ts +++ b/packages/backend/src/core/entities/ChannelEntityService.ts @@ -92,6 +92,7 @@ export class ChannelEntityService { isArchived: channel.isArchived, usersCount: channel.usersCount, notesCount: channel.notesCount, + isSensitive: channel.isSensitive, ...(me ? { isFollowing, diff --git a/packages/backend/src/core/entities/NoteEntityService.ts b/packages/backend/src/core/entities/NoteEntityService.ts index da1d0a952a..7d7183dc8b 100644 --- a/packages/backend/src/core/entities/NoteEntityService.ts +++ b/packages/backend/src/core/entities/NoteEntityService.ts @@ -333,6 +333,7 @@ export class NoteEntityService implements OnModuleInit { id: channel.id, name: channel.name, color: channel.color, + isSensitive: channel.isSensitive, } : undefined, mentions: note.mentions.length > 0 ? note.mentions : undefined, uri: note.uri ?? undefined, diff --git a/packages/backend/src/models/entities/Channel.ts b/packages/backend/src/models/entities/Channel.ts index e04bb5e62c..4df8b5aed5 100644 --- a/packages/backend/src/models/entities/Channel.ts +++ b/packages/backend/src/models/entities/Channel.ts @@ -94,4 +94,9 @@ export class Channel { comment: 'The count of users.', }) public usersCount: number; + + @Column('boolean', { + default: false, + }) + public isSensitive: boolean; } diff --git a/packages/backend/src/models/json-schema/channel.ts b/packages/backend/src/models/json-schema/channel.ts index ec8bc32376..f1019d1461 100644 --- a/packages/backend/src/models/json-schema/channel.ts +++ b/packages/backend/src/models/json-schema/channel.ts @@ -72,5 +72,9 @@ export const packedChannelSchema = { type: 'string', optional: false, nullable: false, }, + isSensitive: { + type: 'boolean', + optional: false, 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 dc7c0462fa..eb744aa109 100644 --- a/packages/backend/src/models/json-schema/note.ts +++ b/packages/backend/src/models/json-schema/note.ts @@ -139,6 +139,10 @@ export const packedNoteSchema = { type: 'string', optional: false, nullable: true, }, + isSensitive: { + type: 'boolean', + optional: true, nullable: false, + } }, }, }, diff --git a/packages/backend/src/server/api/endpoints/channels/create.ts b/packages/backend/src/server/api/endpoints/channels/create.ts index a63f99f827..8364fd65d1 100644 --- a/packages/backend/src/server/api/endpoints/channels/create.ts +++ b/packages/backend/src/server/api/endpoints/channels/create.ts @@ -49,6 +49,7 @@ export const paramDef = { description: { type: 'string', nullable: true, minLength: 1, maxLength: 2048 }, bannerId: { type: 'string', format: 'misskey:id', nullable: true }, color: { type: 'string', minLength: 1, maxLength: 16 }, + isSensitive: { type: 'boolean', nullable: true }, }, required: ['name'], } as const; @@ -86,6 +87,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { name: ps.name, description: ps.description ?? null, bannerId: banner ? banner.id : null, + isSensitive: ps.isSensitive ?? false, ...(ps.color !== undefined ? { color: ps.color } : {}), } as Channel).then(x => this.channelsRepository.findOneByOrFail(x.identifiers[0])); diff --git a/packages/backend/src/server/api/endpoints/channels/update.ts b/packages/backend/src/server/api/endpoints/channels/update.ts index 701b73148d..528e5cb38c 100644 --- a/packages/backend/src/server/api/endpoints/channels/update.ts +++ b/packages/backend/src/server/api/endpoints/channels/update.ts @@ -60,6 +60,7 @@ export const paramDef = { }, }, color: { type: 'string', minLength: 1, maxLength: 16 }, + isSensitive: { type: 'boolean', nullable: true }, }, required: ['channelId'], } as const; @@ -114,6 +115,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { ...(ps.color !== undefined ? { color: ps.color } : {}), ...(typeof ps.isArchived === 'boolean' ? { isArchived: ps.isArchived } : {}), ...(banner ? { bannerId: banner.id } : {}), + ...(typeof ps.isSensitive === 'boolean' ? { isSensitive: ps.isSensitive } : {}), }); return await this.channelEntityService.pack(channel.id, me); diff --git a/packages/frontend/src/components/MkChannelPreview.vue b/packages/frontend/src/components/MkChannelPreview.vue index 9c08efb6c7..2583ee3831 100644 --- a/packages/frontend/src/components/MkChannelPreview.vue +++ b/packages/frontend/src/components/MkChannelPreview.vue @@ -8,6 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only <div class="banner" :style="bannerStyle"> <div class="fade"></div> <div class="name"><i class="ti ti-device-tv"></i> {{ channel.name }}</div> + <div v-if="channel.isSensitive" class="sensitiveIndicator">{{ i18n.ts.sensitive }}</div> <div class="status"> <div> <i class="ti ti-users ti-fw"></i> @@ -102,6 +103,19 @@ const bannerStyle = computed(() => { border-radius: 6px; color: #fff; } + + > .sensitiveIndicator { + position: absolute; + z-index: 1; + bottom: 16px; + left: 16px; + background: rgba(0, 0, 0, 0.7); + color: var(--warn); + border-radius: 6px; + font-weight: bold; + font-size: 1em; + padding: 4px 7px; + } } > article { diff --git a/packages/frontend/src/pages/channel-editor.vue b/packages/frontend/src/pages/channel-editor.vue index fbf589f244..59d6d14cee 100644 --- a/packages/frontend/src/pages/channel-editor.vue +++ b/packages/frontend/src/pages/channel-editor.vue @@ -20,6 +20,10 @@ SPDX-License-Identifier: AGPL-3.0-only <template #label>{{ i18n.ts.color }}</template> </MkColorInput> + <MkSwitch v-model="isSensitive"> + <template #label>{{ i18n.ts.sensitive }}</template> + </MkSwitch> + <div> <MkButton v-if="bannerId == null" @click="setBannerImage"><i class="ti ti-plus"></i> {{ i18n.ts._channel.setBanner }}</MkButton> <div v-else-if="bannerUrl"> @@ -72,6 +76,7 @@ import { useRouter } from '@/router'; import { definePageMetadata } from '@/scripts/page-metadata'; import { i18n } from '@/i18n'; import MkFolder from '@/components/MkFolder.vue'; +import MkSwitch from "@/components/MkSwitch.vue"; const Sortable = defineAsyncComponent(() => import('vuedraggable').then(x => x.default)); @@ -87,6 +92,7 @@ let description = $ref(null); let bannerUrl = $ref<string | null>(null); let bannerId = $ref<string | null>(null); let color = $ref('#000'); +let isSensitive = $ref(false); const pinnedNotes = ref([]); watch(() => bannerId, async () => { @@ -110,6 +116,7 @@ async function fetchChannel() { description = channel.description; bannerId = channel.bannerId; bannerUrl = channel.bannerUrl; + isSensitive = channel.isSensitive; pinnedNotes.value = channel.pinnedNoteIds.map(id => ({ id, })); @@ -142,6 +149,7 @@ function save() { bannerId: bannerId, pinnedNoteIds: pinnedNotes.value.map(x => x.id), color: color, + isSensitive: isSensitive, }; if (props.channelId) { diff --git a/packages/frontend/src/pages/channel.vue b/packages/frontend/src/pages/channel.vue index 5049b6ba2b..be0917871a 100644 --- a/packages/frontend/src/pages/channel.vue +++ b/packages/frontend/src/pages/channel.vue @@ -17,6 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only <div><i class="ti ti-users ti-fw"></i><I18n :src="i18n.ts._channel.usersCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.usersCount }}</b></template></I18n></div> <div><i class="ti ti-pencil ti-fw"></i><I18n :src="i18n.ts._channel.notesCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.notesCount }}</b></template></I18n></div> </div> + <div v-if="channel.isSensitive" :class="$style.sensitiveIndicator">{{ i18n.ts.sensitive }}</div> <div :class="$style.bannerFade"></div> </div> <div v-if="channel.description" :class="$style.description"> @@ -274,4 +275,17 @@ definePageMetadata(computed(() => channel ? { .description { padding: 16px; } + +.sensitiveIndicator { + position: absolute; + z-index: 1; + bottom: 16px; + left: 16px; + background: rgba(0, 0, 0, 0.7); + color: var(--warn); + border-radius: 6px; + font-weight: bold; + font-size: 1em; + padding: 4px 7px; +} </style>