implement mandatory CW for notes (resolves #910)
This commit is contained in:
parent
6f8d831e09
commit
92750240eb
29 changed files with 305 additions and 11 deletions
|
|
@ -13,6 +13,11 @@ Displays a placeholder for a muted note.
|
|||
<!-- If hard muted, we want to hide *everything*, including the placeholders and controls to expand. -->
|
||||
<div v-else-if="!mute.hardMuted" :class="[$style.muted, mutedClass]" class="_gaps_s" @click.stop="expandNote = true">
|
||||
<!-- Mandatory CWs -->
|
||||
<I18n v-if="mute.noteMandatoryCW" :src="i18n.ts.noteIsFlaggedAs" tag="small">
|
||||
<template #cw>
|
||||
{{ mute.noteMandatoryCW }}
|
||||
</template>
|
||||
</I18n>
|
||||
<I18n v-if="mute.userMandatoryCW" :src="i18n.ts.userIsFlaggedAs" tag="small">
|
||||
<template #name>
|
||||
<MkUserName :user="note.user"/>
|
||||
|
|
@ -84,7 +89,7 @@ const expandNote = ref(false);
|
|||
|
||||
const mute = computed(() => checkMute(props.note, props.withHardMute));
|
||||
const mutedWords = computed(() => mute.value.softMutedWords?.join(', '));
|
||||
const isMuted = computed(() => mute.value.hardMuted || mutedWords.value || mute.value.userMandatoryCW || mute.value.noteMuted || mute.value.threadMuted || mute.value.sensitiveMuted);
|
||||
const isMuted = computed(() => mute.value.hardMuted || mutedWords.value || mute.value.noteMandatoryCW || mute.value.userMandatoryCW || mute.value.noteMuted || mute.value.threadMuted || mute.value.sensitiveMuted);
|
||||
const isExpanded = computed(() => expandNote.value || !isMuted.value);
|
||||
const rootClass = computed(() => isExpanded.value ? props.expandedClass : undefined);
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
'markSensitiveDriveFile',
|
||||
'resetPassword',
|
||||
'setMandatoryCW',
|
||||
'setMandatoryCWForNote',
|
||||
'suspendRemoteInstance',
|
||||
'setRemoteInstanceNSFW',
|
||||
'unsetRemoteInstanceNSFW',
|
||||
|
|
@ -79,6 +80,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<span v-else-if="log.type === 'unsuspend'">: @{{ log.info.userUsername }}{{ log.info.userHost ? '@' + log.info.userHost : '' }}</span>
|
||||
<span v-else-if="log.type === 'resetPassword'">: @{{ log.info.userUsername }}{{ log.info.userHost ? '@' + log.info.userHost : '' }}</span>
|
||||
<span v-else-if="log.type === 'setMandatoryCW'">: @{{ log.info.userUsername }}{{ log.info.userHost ? '@' + log.info.userHost : '' }}</span>
|
||||
<span v-else-if="log.type === 'setMandatoryCWForNote'">: @{{ log.info.noteUserUsername }}{{ log.info.noteUserHost ? '@' + log.info.noteUserHost : '' }}</span>
|
||||
<span v-else-if="log.type === 'assignRole'">: @{{ log.info.userUsername }}{{ log.info.userHost ? '@' + log.info.userHost : '' }} <i class="ti ti-arrow-right"></i> {{ log.info.roleName }}</span>
|
||||
<span v-else-if="log.type === 'unassignRole'">: @{{ log.info.userUsername }}{{ log.info.userHost ? '@' + log.info.userHost : '' }} <i class="ti ti-equal-not"></i> {{ log.info.roleName }}</span>
|
||||
<span v-else-if="log.type === 'createRole'">: {{ log.info.role.name }}</span>
|
||||
|
|
@ -208,6 +210,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<CodeDiff :context="0" :hideHeader="true" :oldString="log.info.oldCW ?? ''" :newString="log.info.newCW ?? ''" maxHeight="150px"/>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="log.type === 'setMandatoryCWForNote'">
|
||||
<div>{{ i18n.ts.user }}: <MkA :to="`/admin/user/${log.info.noteUserId}`" class="_link">@{{ log.info.noteUserUsername }}{{ log.info.noteUserHost ? '@' + log.info.noteUserHost : '' }}</MkA></div>
|
||||
<div>{{ i18n.ts.note }}: <MkA :to="`/notes/${log.info.noteId}`" class="_link">{{ log.info.noteId }}</MkA></div>
|
||||
<div :class="$style.diff">
|
||||
<CodeDiff :context="0" :hideHeader="true" :oldString="log.info.oldCW ?? ''" :newString="log.info.newCW ?? ''" maxHeight="150px"/>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="log.type === 'unsuspend'">
|
||||
<div>{{ i18n.ts.user }}: <MkA :to="`/admin/user/${log.info.userId}`" class="_link">@{{ log.info.userUsername }}{{ log.info.userHost ? '@' + log.info.userHost : '' }}</MkA></div>
|
||||
</template>
|
||||
|
|
@ -323,6 +332,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<MkUrlPreview v-if="'noteId' in log.info" :url="`${url}/notes/${log.info.noteId}`" :compact="false" :detail="false" :showAsQuote="true"></MkUrlPreview>
|
||||
|
||||
<details>
|
||||
<summary>raw</summary>
|
||||
<pre>{{ JSON5.stringify(log, null, '\t') }}</pre>
|
||||
|
|
@ -338,6 +349,8 @@ import JSON5 from 'json5';
|
|||
import { i18n } from '@/i18n.js';
|
||||
import MkFolder from '@/components/MkFolder.vue';
|
||||
import SkFetchNote from '@/components/SkFetchNote.vue';
|
||||
import MkUrlPreview from '@/components/MkUrlPreview.vue';
|
||||
import { url } from '@@/js/config.js';
|
||||
|
||||
const props = defineProps<{
|
||||
log: Misskey.entities.ModerationLog;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ export interface Mute {
|
|||
threadMuted?: boolean;
|
||||
noteMuted?: boolean;
|
||||
|
||||
noteMandatoryCW?: string | null;
|
||||
// TODO show this as a single block on user timelines
|
||||
userMandatoryCW?: string | null;
|
||||
}
|
||||
|
|
@ -32,21 +33,22 @@ export function checkMute(note: Misskey.entities.Note, withHardMute?: boolean):
|
|||
|
||||
const threadMuted = note.isMutingThread;
|
||||
const noteMuted = note.isMutingNote;
|
||||
const noteMandatoryCW = note.mandatoryCW;
|
||||
const userMandatoryCW = note.user.mandatoryCW;
|
||||
|
||||
// Hard mute
|
||||
if (withHardMute && isHardMuted(note)) {
|
||||
return { hardMuted: true, sensitiveMuted, threadMuted, noteMuted, userMandatoryCW };
|
||||
return { hardMuted: true, sensitiveMuted, threadMuted, noteMuted, noteMandatoryCW, userMandatoryCW };
|
||||
}
|
||||
|
||||
// Soft mute
|
||||
const softMutedWords = isSoftMuted(note);
|
||||
if (softMutedWords.length > 0) {
|
||||
return { softMutedWords, sensitiveMuted, threadMuted, noteMuted, userMandatoryCW };
|
||||
return { softMutedWords, sensitiveMuted, threadMuted, noteMuted, noteMandatoryCW, userMandatoryCW };
|
||||
}
|
||||
|
||||
// Other / no mute
|
||||
return { sensitiveMuted, threadMuted, noteMuted, userMandatoryCW };
|
||||
return { sensitiveMuted, threadMuted, noteMuted, noteMandatoryCW, userMandatoryCW };
|
||||
}
|
||||
|
||||
function isHardMuted(note: Misskey.entities.Note): boolean {
|
||||
|
|
|
|||
|
|
@ -151,6 +151,28 @@ export function getAbuseNoteMenu(note: Misskey.entities.Note, text: string): Men
|
|||
};
|
||||
}
|
||||
|
||||
export function getMandatoryCWMenu(note: Misskey.entities.Note): MenuItem {
|
||||
return {
|
||||
icon: 'ph-warning ph-bold ph-lg',
|
||||
text: i18n.ts.mandatoryCWForNote,
|
||||
action: async () => {
|
||||
const result = await os.inputText({
|
||||
type: 'text',
|
||||
title: i18n.ts.mandatoryCWForNote,
|
||||
text: i18n.ts.mandatoryCWForNoteDescription,
|
||||
default: note.mandatoryCW ?? '',
|
||||
});
|
||||
|
||||
if (result.canceled) return;
|
||||
|
||||
await os.apiWithDialog('admin/cw-note', {
|
||||
noteId: note.id,
|
||||
cw: result.result || null,
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function getCopyNoteLinkMenu(note: Misskey.entities.Note, text: string): MenuItem {
|
||||
return {
|
||||
icon: 'ti ti-link',
|
||||
|
|
@ -442,6 +464,10 @@ export function getNoteMenu(props: {
|
|||
if (appearNote.userId !== $i.id) {
|
||||
menuItems.push({ type: 'divider' });
|
||||
menuItems.push(getAbuseNoteMenu(appearNote, i18n.ts.reportAbuse));
|
||||
|
||||
if ($i.isModerator || $i.isAdmin) {
|
||||
menuItems.push(getMandatoryCWMenu(appearNote));
|
||||
}
|
||||
}
|
||||
|
||||
if (appearNote.channel && (appearNote.channel.userId === $i.id || $i.isModerator || $i.isAdmin)) {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@ export const getNoteSummary = (note?: Misskey.entities.Note | null): string => {
|
|||
|
||||
// Append mandatory CW, if applicable
|
||||
let cw = note.cw;
|
||||
if (note.mandatoryCW) {
|
||||
cw = appendContentWarning(cw, note.mandatoryCW);
|
||||
}
|
||||
if (note.user.mandatoryCW) {
|
||||
cw = appendContentWarning(cw, note.user.mandatoryCW);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue