mirror of
				https://codeberg.org/yeentown/barkey.git
				synced 2025-11-04 07:24:13 +00:00 
			
		
		
		
	feat: sensitive channel (#11438)
* feat(backend): add isSensitive to Channel * feat(backend): support isSensitive in channel endpoints * feat(frontend/channel-editor): support isSensitive in create/edit channel page * feat(frontend/channel): show sensitive indicator for sensitive channels * docs(changelog): add チャンネルをセンシティブ指定できるようになりました * chore: license header for each file * chore: add isSensitive of channel to Note object
This commit is contained in:
		
							parent
							
								
									79966d33b5
								
							
						
					
					
						commit
						c5b8766a18
					
				
					 12 changed files with 73 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -51,6 +51,7 @@
 | 
			
		|||
- ユーザーにロールが期限付きでアサインされている場合、その期限をユーザーのモデレーションページで確認できるようになりました
 | 
			
		||||
- identicon生成を無効にしてパフォーマンスを向上させることができるようになりました
 | 
			
		||||
- サーバーのマシン情報の公開を無効にしてパフォーマンスを向上させることができるようになりました
 | 
			
		||||
- チャンネルをセンシティブ指定できるようになりました
 | 
			
		||||
 | 
			
		||||
### Client
 | 
			
		||||
- deck UIのカラムのメニューからアンテナとリストの編集画面を開けるように
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										17
									
								
								packages/backend/migration/1690782653311-SensitiveChannel.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								packages/backend/migration/1690782653311-SensitiveChannel.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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"`);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -92,6 +92,7 @@ export class ChannelEntityService {
 | 
			
		|||
			isArchived: channel.isArchived,
 | 
			
		||||
			usersCount: channel.usersCount,
 | 
			
		||||
			notesCount: channel.notesCount,
 | 
			
		||||
			isSensitive: channel.isSensitive,
 | 
			
		||||
 | 
			
		||||
			...(me ? {
 | 
			
		||||
				isFollowing,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -94,4 +94,9 @@ export class Channel {
 | 
			
		|||
		comment: 'The count of users.',
 | 
			
		||||
	})
 | 
			
		||||
	public usersCount: number;
 | 
			
		||||
 | 
			
		||||
	@Column('boolean', {
 | 
			
		||||
		default: false,
 | 
			
		||||
	})
 | 
			
		||||
	public isSensitive: boolean;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -72,5 +72,9 @@ export const packedChannelSchema = {
 | 
			
		|||
			type: 'string',
 | 
			
		||||
			optional: false, nullable: false,
 | 
			
		||||
		},
 | 
			
		||||
		isSensitive: {
 | 
			
		||||
			type: 'boolean',
 | 
			
		||||
			optional: false, nullable: false,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
} as const;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -139,6 +139,10 @@ export const packedNoteSchema = {
 | 
			
		|||
						type: 'string',
 | 
			
		||||
						optional: false, nullable: true,
 | 
			
		||||
					},
 | 
			
		||||
					isSensitive: {
 | 
			
		||||
						type: 'boolean',
 | 
			
		||||
						optional: true, nullable: false,
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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]));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue