センシティブなファイルを選択できないように

This commit is contained in:
kakkokari-gtyih 2024-04-08 18:39:35 +09:00
parent fafe980315
commit 16e92e6447
8 changed files with 56 additions and 15 deletions

9
locales/index.d.ts vendored
View File

@ -4936,6 +4936,15 @@ export interface Locale extends ILocale {
* UIを使用する * UIを使用する
*/ */
"useNativeUIForVideoAudioPlayer": string; "useNativeUIForVideoAudioPlayer": string;
/**
*
*/
"cannotSelectSensitiveMedia": string;
/**
*
*
*/
"cannotSelectSensitiveMediaDescription": string;
"_bubbleGame": { "_bubbleGame": {
/** /**
* *

View File

@ -1230,6 +1230,8 @@ useTotp: "ワンタイムパスワードを使う"
useBackupCode: "バックアップコードを使う" useBackupCode: "バックアップコードを使う"
launchApp: "アプリを起動" launchApp: "アプリを起動"
useNativeUIForVideoAudioPlayer: "動画・音声の再生にブラウザのUIを使用する" useNativeUIForVideoAudioPlayer: "動画・音声の再生にブラウザのUIを使用する"
cannotSelectSensitiveMedia: "センシティブなメディアは選択できません"
cannotSelectSensitiveMediaDescription: "自分でセンシティブ設定を行っていないのにこのエラーが出ている場合、自動判定によりセンシティブなメディアとされている可能性があります。\nサーバーの規則に照らして不要な場合は、ファイルのセンシティブ設定を解除してもう一度お試しください。"
_bubbleGame: _bubbleGame:
howToPlay: "遊び方" howToPlay: "遊び方"

View File

@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template> <template>
<div <div
:class="[$style.root, { [$style.isSelected]: isSelected }]" :class="[$style.root, { [$style.isSelected]: isSelected, [$style.isDisabled]: isDisabled }]"
draggable="true" draggable="true"
:title="title" :title="title"
@click="onClick" @click="onClick"
@ -55,9 +55,11 @@ const props = withDefaults(defineProps<{
file: Misskey.entities.DriveFile; file: Misskey.entities.DriveFile;
folder: Misskey.entities.DriveFolder | null; folder: Misskey.entities.DriveFolder | null;
isSelected?: boolean; isSelected?: boolean;
isDisabled?: boolean;
selectMode?: boolean; selectMode?: boolean;
}>(), { }>(), {
isSelected: false, isSelected: false,
isDisabled: false,
selectMode: false, selectMode: false,
}); });
@ -72,6 +74,8 @@ const isDragging = ref(false);
const title = computed(() => `${props.file.name}\n${props.file.type} ${bytes(props.file.size)}`); const title = computed(() => `${props.file.name}\n${props.file.type} ${bytes(props.file.size)}`);
function onClick(ev: MouseEvent) { function onClick(ev: MouseEvent) {
if (props.isDisabled) return;
if (props.selectMode) { if (props.selectMode) {
emit('chosen', props.file); emit('chosen', props.file);
} else { } else {
@ -88,6 +92,8 @@ function onContextmenu(ev: MouseEvent) {
} }
function onDragstart(ev: DragEvent) { function onDragstart(ev: DragEvent) {
if (props.isDisabled) return;
if (ev.dataTransfer) { if (ev.dataTransfer) {
ev.dataTransfer.effectAllowed = 'move'; ev.dataTransfer.effectAllowed = 'move';
ev.dataTransfer.setData(_DATA_TRANSFER_DRIVE_FILE_, JSON.stringify(props.file)); ev.dataTransfer.setData(_DATA_TRANSFER_DRIVE_FILE_, JSON.stringify(props.file));
@ -173,6 +179,12 @@ function onDragend() {
color: #fff; color: #fff;
} }
} }
&.isDisabled {
opacity: 0.5;
pointer-events: none;
cursor: not-allowed;
}
} }
.label { .label {

View File

@ -73,6 +73,7 @@ SPDX-License-Identifier: AGPL-3.0-only
:folder="folder" :folder="folder"
:selectMode="select === 'file'" :selectMode="select === 'file'"
:isSelected="selectedFiles.some(x => x.id === file.id)" :isSelected="selectedFiles.some(x => x.id === file.id)"
:isDisabled="excludeSensitive && file.isSensitive"
@chosen="chooseFile" @chosen="chooseFile"
@dragstart="isDragSource = true" @dragstart="isDragSource = true"
@dragend="isDragSource = false" @dragend="isDragSource = false"
@ -114,9 +115,11 @@ const props = withDefaults(defineProps<{
initialFolder?: Misskey.entities.DriveFolder; initialFolder?: Misskey.entities.DriveFolder;
type?: string; type?: string;
multiple?: boolean; multiple?: boolean;
excludeSensitive?: boolean;
select?: 'file' | 'folder' | null; select?: 'file' | 'folder' | null;
}>(), { }>(), {
multiple: false, multiple: false,
excludeSensitive: false,
select: null, select: null,
}); });

View File

@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ multiple ? ((type === 'file') ? i18n.ts.selectFiles : i18n.ts.selectFolders) : ((type === 'file') ? i18n.ts.selectFile : i18n.ts.selectFolder) }} {{ multiple ? ((type === 'file') ? i18n.ts.selectFiles : i18n.ts.selectFolders) : ((type === 'file') ? i18n.ts.selectFile : i18n.ts.selectFolder) }}
<span v-if="selected.length > 0" style="margin-left: 8px; opacity: 0.5;">({{ number(selected.length) }})</span> <span v-if="selected.length > 0" style="margin-left: 8px; opacity: 0.5;">({{ number(selected.length) }})</span>
</template> </template>
<XDrive :multiple="multiple" :select="type" @changeSelection="onChangeSelection" @selected="ok()"/> <XDrive :multiple="multiple" :excludeSensitive="excludeSensitive" :select="type" @changeSelection="onChangeSelection" @selected="ok()"/>
</MkModalWindow> </MkModalWindow>
</template> </template>
@ -34,6 +34,7 @@ import { i18n } from '@/i18n.js';
withDefaults(defineProps<{ withDefaults(defineProps<{
type?: 'file' | 'folder'; type?: 'file' | 'folder';
multiple: boolean; multiple: boolean;
excludeSensitive: boolean;
}>(), { }>(), {
type: 'file', type: 'file',
}); });

View File

@ -541,11 +541,12 @@ export async function selectUser(opts: { includeSelf?: boolean; localOnly?: bool
}); });
} }
export async function selectDriveFile(multiple: boolean): Promise<Misskey.entities.DriveFile[]> { export async function selectDriveFile(multiple: boolean, excludeSensitive: boolean): Promise<Misskey.entities.DriveFile[]> {
return new Promise(resolve => { return new Promise(resolve => {
popup(defineAsyncComponent(() => import('@/components/MkDriveSelectDialog.vue')), { popup(defineAsyncComponent(() => import('@/components/MkDriveSelectDialog.vue')), {
type: 'file', type: 'file',
multiple, multiple,
excludeSensitive,
}, { }, {
done: files => { done: files => {
if (files) { if (files) {

View File

@ -204,7 +204,7 @@ function save() {
} }
function changeAvatar(ev) { function changeAvatar(ev) {
selectFile(ev.currentTarget ?? ev.target, i18n.ts.avatar).then(async (file) => { selectFile(ev.currentTarget ?? ev.target, i18n.ts.avatar, true).then(async (file) => {
let originalOrCropped = file; let originalOrCropped = file;
const { canceled } = await os.confirm({ const { canceled } = await os.confirm({
@ -231,7 +231,7 @@ function changeAvatar(ev) {
} }
function changeBanner(ev) { function changeBanner(ev) {
selectFile(ev.currentTarget ?? ev.target, i18n.ts.banner).then(async (file) => { selectFile(ev.currentTarget ?? ev.target, i18n.ts.banner, true).then(async (file) => {
let originalOrCropped = file; let originalOrCropped = file;
const { canceled } = await os.confirm({ const { canceled } = await os.confirm({

View File

@ -39,9 +39,9 @@ export function chooseFileFromPc(multiple: boolean, keepOriginal = false): Promi
}); });
} }
export function chooseFileFromDrive(multiple: boolean): Promise<Misskey.entities.DriveFile[]> { export function chooseFileFromDrive(multiple: boolean, excludeSensitive: boolean): Promise<Misskey.entities.DriveFile[]> {
return new Promise((res, rej) => { return new Promise((res, rej) => {
os.selectDriveFile(multiple).then(files => { os.selectDriveFile(multiple, excludeSensitive).then(files => {
res(files); res(files);
}); });
}); });
@ -80,10 +80,23 @@ export function chooseFileFromUrl(): Promise<Misskey.entities.DriveFile> {
}); });
} }
function select(src: any, label: string | null, multiple: boolean): Promise<Misskey.entities.DriveFile[]> { function select(src: any, label: string | null, multiple: boolean, excludeSensitive: boolean): Promise<Misskey.entities.DriveFile[]> {
return new Promise((res, rej) => { return new Promise((res, rej) => {
const keepOriginal = ref(defaultStore.state.keepOriginalUploading); const keepOriginal = ref(defaultStore.state.keepOriginalUploading);
function _resolve(files: Misskey.entities.DriveFile[]) {
if (excludeSensitive && files.some(file => file.isSensitive)) {
os.alert({
title: i18n.ts.cannotSelectSensitiveMedia,
text: i18n.ts.cannotSelectSensitiveMediaDescription,
});
rej();
return;
}
res(files);
}
os.popupMenu([label ? { os.popupMenu([label ? {
text: label, text: label,
type: 'label', type: 'label',
@ -94,23 +107,23 @@ function select(src: any, label: string | null, multiple: boolean): Promise<Miss
}, { }, {
text: i18n.ts.upload, text: i18n.ts.upload,
icon: 'ti ti-upload', icon: 'ti ti-upload',
action: () => chooseFileFromPc(multiple, keepOriginal.value).then(files => res(files)), action: () => chooseFileFromPc(multiple, keepOriginal.value).then(files => _resolve(files)),
}, { }, {
text: i18n.ts.fromDrive, text: i18n.ts.fromDrive,
icon: 'ti ti-cloud', icon: 'ti ti-cloud',
action: () => chooseFileFromDrive(multiple).then(files => res(files)), action: () => chooseFileFromDrive(multiple, excludeSensitive).then(files => _resolve(files)),
}, { }, {
text: i18n.ts.fromUrl, text: i18n.ts.fromUrl,
icon: 'ti ti-link', icon: 'ti ti-link',
action: () => chooseFileFromUrl().then(file => res([file])), action: () => chooseFileFromUrl().then(file => _resolve([file])),
}], src); }], src);
}); });
} }
export function selectFile(src: any, label: string | null = null): Promise<Misskey.entities.DriveFile> { export function selectFile(src: any, label: string | null = null, excludeSensitive = false): Promise<Misskey.entities.DriveFile> {
return select(src, label, false).then(files => files[0]); return select(src, label, false, excludeSensitive).then(files => files[0]);
} }
export function selectFiles(src: any, label: string | null = null): Promise<Misskey.entities.DriveFile[]> { export function selectFiles(src: any, label: string | null = null, excludeSensitive = false): Promise<Misskey.entities.DriveFile[]> {
return select(src, label, true); return select(src, label, true, excludeSensitive);
} }