add mandatory CW for instances
This commit is contained in:
parent
595c004a74
commit
5e0115335a
26 changed files with 282 additions and 8 deletions
22
locales/index.d.ts
vendored
22
locales/index.d.ts
vendored
|
|
@ -9216,6 +9216,10 @@ export interface Locale extends ILocale {
|
|||
* Apply mandatory CW on notes
|
||||
*/
|
||||
"write:admin:cw-note": string;
|
||||
/**
|
||||
* Apply mandatory CW on instances
|
||||
*/
|
||||
"write:admin:cw-instance": string;
|
||||
/**
|
||||
* Silence users
|
||||
*/
|
||||
|
|
@ -10956,6 +10960,10 @@ export interface Locale extends ILocale {
|
|||
* Set content warning for note
|
||||
*/
|
||||
"setMandatoryCWForNote": string;
|
||||
/**
|
||||
* Set content warning for instance
|
||||
*/
|
||||
"setMandatoryCWForInstance": string;
|
||||
/**
|
||||
* Set remote instance as NSFW
|
||||
*/
|
||||
|
|
@ -12100,6 +12108,10 @@ export interface Locale extends ILocale {
|
|||
* Note is flagged: "{cw}"
|
||||
*/
|
||||
"noteIsFlaggedAs": ParameterizedString<"cw">;
|
||||
/**
|
||||
* {name} is flagged: "{cw}"
|
||||
*/
|
||||
"instanceIsFlaggedAs": ParameterizedString<"name" | "cw">;
|
||||
/**
|
||||
* Mark all media from user as NSFW
|
||||
*/
|
||||
|
|
@ -13054,13 +13066,21 @@ export interface Locale extends ILocale {
|
|||
*/
|
||||
"mandatoryCWDescription": string;
|
||||
/**
|
||||
* Add content warning
|
||||
* Force content warning
|
||||
*/
|
||||
"mandatoryCWForNote": string;
|
||||
/**
|
||||
* Applies an additional content warning to this post. The new warning will appear like a word mute to distinguish it from the author's own content warning.
|
||||
*/
|
||||
"mandatoryCWForNoteDescription": string;
|
||||
/**
|
||||
* Force content warning
|
||||
*/
|
||||
"mandatoryCWForInstance": string;
|
||||
/**
|
||||
* Applies a content warning to all posts originating from this instance. The forced warnings will appear like a word mute to distinguish them from the notes' own content warnings.
|
||||
*/
|
||||
"mandatoryCWForInstanceDescription": string;
|
||||
/**
|
||||
* Fetch linked note
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export class AddInstanceMandatoryCW1751078046239 {
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "instance" ADD "mandatoryCW" text`);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "mandatoryCW"`);
|
||||
}
|
||||
}
|
||||
|
|
@ -34,6 +34,7 @@ import { QueryService } from '@/core/QueryService.js';
|
|||
import { UtilityService } from '@/core/UtilityService.js';
|
||||
import { CacheService } from '@/core/CacheService.js';
|
||||
import { isPureRenote, isQuote, isRenote } from '@/misc/is-renote.js';
|
||||
import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
|
||||
import { JsonLdService } from './JsonLdService.js';
|
||||
import { ApMfmService } from './ApMfmService.js';
|
||||
import { CONTEXT } from './misc/contexts.js';
|
||||
|
|
@ -75,9 +76,10 @@ export class ApRendererService {
|
|||
private apMfmService: ApMfmService,
|
||||
private mfmService: MfmService,
|
||||
private idService: IdService,
|
||||
private readonly queryService: QueryService,
|
||||
private utilityService: UtilityService,
|
||||
private readonly queryService: QueryService,
|
||||
private readonly cacheService: CacheService,
|
||||
private readonly federatedInstanceService: FederatedInstanceService,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -398,6 +400,8 @@ export class ApRendererService {
|
|||
return ids.map(id => items.find(item => item.id === id)).filter(x => x != null);
|
||||
};
|
||||
|
||||
const instance = author.instance ?? (author.host ? await this.federatedInstanceService.fetch(author.host) : null);
|
||||
|
||||
let inReplyTo;
|
||||
let inReplyToNote: MiNote | null;
|
||||
|
||||
|
|
@ -503,6 +507,9 @@ export class ApRendererService {
|
|||
if (author.mandatoryCW) {
|
||||
summary = appendContentWarning(summary, author.mandatoryCW);
|
||||
}
|
||||
if (instance?.mandatoryCW) {
|
||||
summary = appendContentWarning(summary, instance.mandatoryCW);
|
||||
}
|
||||
|
||||
const { content } = this.apMfmService.getNoteHtml(note, apAppend);
|
||||
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ export class InstanceEntityService {
|
|||
rejectQuotes: instance.rejectQuotes,
|
||||
moderationNote: iAmModerator ? instance.moderationNote : null,
|
||||
isBubbled: this.utilityService.isBubbledHost(instance.host),
|
||||
mandatoryCW: instance.mandatoryCW,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -578,6 +578,7 @@ export class UserEntityService implements OnModuleInit {
|
|||
faviconUrl: instance.faviconUrl,
|
||||
themeColor: instance.themeColor,
|
||||
isSilenced: instance.isSilenced,
|
||||
mandatoryCW: instance.mandatoryCW,
|
||||
} : undefined) : undefined,
|
||||
followersCount: followersCount ?? 0,
|
||||
followingCount: followingCount ?? 0,
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@ export const getNoteSummary = (note: Packed<'Note'>): string => {
|
|||
if (note.user.mandatoryCW) {
|
||||
cw = appendContentWarning(cw, note.user.mandatoryCW);
|
||||
}
|
||||
if (note.user.instance?.mandatoryCW) {
|
||||
cw = appendContentWarning(cw, note.user.instance.mandatoryCW);
|
||||
}
|
||||
|
||||
// 本文
|
||||
if (cw != null) {
|
||||
|
|
|
|||
|
|
@ -228,4 +228,13 @@ export class MiInstance {
|
|||
length: 16384, default: '',
|
||||
})
|
||||
public moderationNote: string;
|
||||
|
||||
/**
|
||||
* Specifies a Content Warning that should be forcibly applied to all notes from this instance
|
||||
* If null (default), then no Content Warning is applied.
|
||||
*/
|
||||
@Column('text', {
|
||||
nullable: true,
|
||||
})
|
||||
public mandatoryCW: string | null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,5 +139,9 @@ export const packedFederationInstanceSchema = {
|
|||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
mandatoryCW: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
|
|
|||
|
|
@ -228,6 +228,10 @@ export const packedUserLiteSchema = {
|
|||
type: 'boolean',
|
||||
nullable: false, optional: false,
|
||||
},
|
||||
mandatoryCW: {
|
||||
type: 'string',
|
||||
nullable: true, optional: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
followersCount: {
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ export * as 'admin/avatar-decorations/list' from './endpoints/admin/avatar-decor
|
|||
export * as 'admin/avatar-decorations/update' from './endpoints/admin/avatar-decorations/update.js';
|
||||
export * as 'admin/captcha/current' from './endpoints/admin/captcha/current.js';
|
||||
export * as 'admin/captcha/save' from './endpoints/admin/captcha/save.js';
|
||||
export * as 'admin/cw-instance' from './endpoints/admin/cw-instance.js';
|
||||
export * as 'admin/cw-note' from './endpoints/admin/cw-note.js';
|
||||
export * as 'admin/cw-user' from './endpoints/admin/cw-user.js';
|
||||
export * as 'admin/decline-user' from './endpoints/admin/decline-user.js';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
||||
import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
||||
requireCredential: true,
|
||||
requireModerator: true,
|
||||
kind: 'write:admin:cw-instance',
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
host: { type: 'string' },
|
||||
cw: { type: 'string', nullable: true },
|
||||
},
|
||||
required: ['host', 'cw'],
|
||||
} as const;
|
||||
|
||||
@Injectable()
|
||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||
constructor(
|
||||
private readonly moderationLogService: ModerationLogService,
|
||||
private readonly federatedInstanceService: FederatedInstanceService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const instance = await this.federatedInstanceService.fetchOrRegister(ps.host);
|
||||
|
||||
// Skip if there's nothing to do
|
||||
if (instance.mandatoryCW === ps.cw) return;
|
||||
|
||||
// Log event first.
|
||||
// This ensures that we don't "lose" the log if an error occurs
|
||||
await this.moderationLogService.log(me, 'setMandatoryCWForInstance', {
|
||||
newCW: ps.cw,
|
||||
oldCW: instance.mandatoryCW,
|
||||
host: ps.host,
|
||||
});
|
||||
|
||||
await this.federatedInstanceService.update(instance.id, {
|
||||
// Collapse empty strings to null
|
||||
mandatoryCW: ps.cw || null,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -23,6 +23,7 @@ import { MastodonDataService } from '@/server/api/mastodon/MastodonDataService.j
|
|||
import { GetterService } from '@/server/api/GetterService.js';
|
||||
import { appendContentWarning } from '@/misc/append-content-warning.js';
|
||||
import { isRenote } from '@/misc/is-renote.js';
|
||||
import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
|
||||
|
||||
// Missing from Megalodon apparently
|
||||
// https://docs.joinmastodon.org/entities/StatusEdit/
|
||||
|
|
@ -68,6 +69,7 @@ export class MastodonConverters {
|
|||
private readonly idService: IdService,
|
||||
private readonly driveFileEntityService: DriveFileEntityService,
|
||||
private readonly mastodonDataService: MastodonDataService,
|
||||
private readonly federatedInstanceService: FederatedInstanceService,
|
||||
) {}
|
||||
|
||||
private encode(u: MiUser, m: IMentionedRemoteUsers): MastodonEntity.Mention {
|
||||
|
|
@ -210,6 +212,7 @@ export class MastodonConverters {
|
|||
}
|
||||
|
||||
const noteUser = await this.getUser(note.userId);
|
||||
const noteInstance = noteUser.instance ?? (noteUser.host ? await this.federatedInstanceService.fetch(noteUser.host) : null);
|
||||
const account = await this.convertAccount(noteUser);
|
||||
const edits = await this.noteEditRepository.find({ where: { noteId: note.id }, order: { id: 'ASC' } });
|
||||
const history: StatusEdit[] = [];
|
||||
|
|
@ -231,6 +234,9 @@ export class MastodonConverters {
|
|||
if (noteUser.mandatoryCW) {
|
||||
cw = appendContentWarning(cw, noteUser.mandatoryCW);
|
||||
}
|
||||
if (noteInstance?.mandatoryCW) {
|
||||
cw = appendContentWarning(cw, noteInstance.mandatoryCW);
|
||||
}
|
||||
|
||||
const isQuote = renote && (edit.cw || edit.newText || edit.fileIds.length > 0 || note.replyId);
|
||||
const quoteUri = isQuote
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@ export const moderationLogTypes = [
|
|||
'resetPassword',
|
||||
'setMandatoryCW',
|
||||
'setMandatoryCWForNote',
|
||||
'setMandatoryCWForInstance',
|
||||
'setRemoteInstanceNSFW',
|
||||
'unsetRemoteInstanceNSFW',
|
||||
'suspendRemoteInstance',
|
||||
|
|
@ -303,6 +304,11 @@ export type ModerationLogPayloads = {
|
|||
noteUserUsername: string;
|
||||
noteUserHost: string | null;
|
||||
};
|
||||
setMandatoryCWForInstance: {
|
||||
newCW: string | null;
|
||||
oldCW: string | null;
|
||||
host: string;
|
||||
};
|
||||
setRemoteInstanceNSFW: {
|
||||
id: string;
|
||||
host: string;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@ export function computeMergedCw(note: Misskey.entities.Note): string | null {
|
|||
if (note.user.mandatoryCW) {
|
||||
cw = appendContentWarning(cw, note.user.mandatoryCW);
|
||||
}
|
||||
if (note.user.instance?.mandatoryCW) {
|
||||
cw = appendContentWarning(cw, note.user.instance.mandatoryCW);
|
||||
}
|
||||
|
||||
return cw ?? null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,14 @@ Displays a placeholder for a muted note.
|
|||
{{ mute.userMandatoryCW }}
|
||||
</template>
|
||||
</I18n>
|
||||
<I18n v-if="mute.instanceMandatoryCW" :src="i18n.ts.instanceIsFlaggedAs" tag="small">
|
||||
<template #name>
|
||||
{{ note.user.instance?.name ?? note.user.host }}
|
||||
</template>
|
||||
<template #cw>
|
||||
{{ mute.instanceMandatoryCW }}
|
||||
</template>
|
||||
</I18n>
|
||||
|
||||
<!-- Muted notes/threads -->
|
||||
<I18n v-if="mute.noteMuted" :src="i18n.ts.userSaysSomethingInMutedNote" tag="small">
|
||||
|
|
@ -89,7 +97,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.noteMandatoryCW || 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.instanceMandatoryCW || mute.value.noteMuted || mute.value.threadMuted || mute.value.sensitiveMuted);
|
||||
const isExpanded = computed(() => expandNote.value || !isMuted.value);
|
||||
const rootClass = computed(() => isExpanded.value ? props.expandedClass : undefined);
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
'resetPassword',
|
||||
'setMandatoryCW',
|
||||
'setMandatoryCWForNote',
|
||||
'setMandatoryCWForInstance',
|
||||
'suspendRemoteInstance',
|
||||
'setRemoteInstanceNSFW',
|
||||
'unsetRemoteInstanceNSFW',
|
||||
|
|
@ -81,6 +82,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<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 === 'setMandatoryCWForInstance'">: {{ log.info.host }}</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>
|
||||
|
|
@ -217,6 +219,11 @@ 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 === 'setMandatoryCWForInstance'">
|
||||
<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>
|
||||
|
|
|
|||
|
|
@ -123,6 +123,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<MkInfo v-if="isBaseMediaSilenced" warn>{{ i18n.ts.mediaSilencedByBase }}</MkInfo>
|
||||
<MkSwitch v-model="isMediaSilenced" :disabled="!meta || !instance || isBaseMediaSilenced" @update:modelValue="toggleMediaSilenced">{{ i18n.ts.mediaSilenceThisInstance }}</MkSwitch>
|
||||
|
||||
<MkInput v-model="mandatoryCW" type="text" manualSave @update:modelValue="onMandatoryCWChanged">
|
||||
<template #label>{{ i18n.ts.mandatoryCW }}</template>
|
||||
<template #caption>{{ i18n.ts.mandatoryCWDescription }}</template>
|
||||
</MkInput>
|
||||
|
||||
<div :class="$style.buttonStrip">
|
||||
<MkButton inline :disabled="!instance" @click="refreshMetadata"><i class="ph-cloud-arrow-down ph-bold ph-lg"></i> {{ i18n.ts.updateRemoteUser }}</MkButton>
|
||||
<MkButton inline :disabled="!instance" danger @click="deleteAllFiles"><i class="ph-trash ph-bold ph-lg"></i> {{ i18n.ts.deleteAllFiles }}</MkButton>
|
||||
|
|
@ -234,6 +239,7 @@ import { copyToClipboard } from '@/utility/copy-to-clipboard';
|
|||
import MkFolder from '@/components/MkFolder.vue';
|
||||
import MkNumber from '@/components/MkNumber.vue';
|
||||
import SkBadgeStrip from '@/components/SkBadgeStrip.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
host: string;
|
||||
|
|
@ -259,6 +265,7 @@ const rejectReports = ref(false);
|
|||
const isMediaSilenced = ref(false);
|
||||
const faviconUrl = ref<string | null>(null);
|
||||
const moderationNote = ref('');
|
||||
const mandatoryCW = ref<string | null>(null);
|
||||
|
||||
const baseDomains = computed(() => {
|
||||
const domains: string[] = [];
|
||||
|
|
@ -306,6 +313,13 @@ const badges = computed(() => {
|
|||
style: 'warning',
|
||||
});
|
||||
}
|
||||
if (instance.value.mandatoryCW) {
|
||||
arr.push({
|
||||
key: 'cw',
|
||||
label: i18n.ts.cw,
|
||||
style: 'warning',
|
||||
});
|
||||
}
|
||||
if (instance.value.isNSFW) {
|
||||
arr.push({
|
||||
key: 'nsfw',
|
||||
|
|
@ -365,6 +379,13 @@ async function saveModerationNote() {
|
|||
}
|
||||
}
|
||||
|
||||
async function onMandatoryCWChanged(value: string | number) {
|
||||
await os.promiseDialog(async () => {
|
||||
await misskeyApi('admin/cw-instance', { host: props.host, cw: String(value) || null });
|
||||
await fetch();
|
||||
});
|
||||
}
|
||||
|
||||
async function fetch(withHint = false): Promise<void> {
|
||||
const [m, i] = await Promise.all([
|
||||
(withHint && props.metaHint)
|
||||
|
|
@ -389,6 +410,7 @@ async function fetch(withHint = false): Promise<void> {
|
|||
isMediaSilenced.value = instance.value?.isMediaSilenced ?? false;
|
||||
faviconUrl.value = getProxiedImageUrlNullable(instance.value?.faviconUrl, 'preview') ?? getProxiedImageUrlNullable(instance.value?.iconUrl, 'preview');
|
||||
moderationNote.value = instance.value?.moderationNote ?? '';
|
||||
mandatoryCW.value = instance.value?.mandatoryCW ?? '';
|
||||
}
|
||||
|
||||
async function toggleBlock(): Promise<void> {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ export interface Mute {
|
|||
noteMandatoryCW?: string | null;
|
||||
// TODO show this as a single block on user timelines
|
||||
userMandatoryCW?: string | null;
|
||||
instanceMandatoryCW?: string | null;
|
||||
}
|
||||
|
||||
export function checkMute(note: Misskey.entities.Note, withHardMute?: boolean): Mute {
|
||||
|
|
@ -35,20 +36,21 @@ export function checkMute(note: Misskey.entities.Note, withHardMute?: boolean):
|
|||
const noteMuted = note.isMutingNote;
|
||||
const noteMandatoryCW = note.mandatoryCW;
|
||||
const userMandatoryCW = note.user.mandatoryCW;
|
||||
const instanceMandatoryCW = note.user.instance?.mandatoryCW;
|
||||
|
||||
// Hard mute
|
||||
if (withHardMute && isHardMuted(note)) {
|
||||
return { hardMuted: true, sensitiveMuted, threadMuted, noteMuted, noteMandatoryCW, userMandatoryCW };
|
||||
return { hardMuted: true, sensitiveMuted, threadMuted, noteMuted, noteMandatoryCW, userMandatoryCW, instanceMandatoryCW };
|
||||
}
|
||||
|
||||
// Soft mute
|
||||
const softMutedWords = isSoftMuted(note);
|
||||
if (softMutedWords.length > 0) {
|
||||
return { softMutedWords, sensitiveMuted, threadMuted, noteMuted, noteMandatoryCW, userMandatoryCW };
|
||||
return { softMutedWords, sensitiveMuted, threadMuted, noteMuted, noteMandatoryCW, userMandatoryCW, instanceMandatoryCW };
|
||||
}
|
||||
|
||||
// Other / no mute
|
||||
return { sensitiveMuted, threadMuted, noteMuted, noteMandatoryCW, userMandatoryCW };
|
||||
return { sensitiveMuted, threadMuted, noteMuted, noteMandatoryCW, userMandatoryCW, instanceMandatoryCW };
|
||||
}
|
||||
|
||||
function isHardMuted(note: Misskey.entities.Note): boolean {
|
||||
|
|
|
|||
|
|
@ -152,6 +152,9 @@ type AdminCaptchaCurrentResponse = operations['admin___captcha___current']['resp
|
|||
// @public (undocumented)
|
||||
type AdminCaptchaSaveRequest = operations['admin___captcha___save']['requestBody']['content']['application/json'];
|
||||
|
||||
// @public (undocumented)
|
||||
type AdminCwInstanceRequest = operations['admin___cw-instance']['requestBody']['content']['application/json'];
|
||||
|
||||
// @public (undocumented)
|
||||
type AdminCwNoteRequest = operations['admin___cw-note']['requestBody']['content']['application/json'];
|
||||
|
||||
|
|
@ -1545,6 +1548,7 @@ declare namespace entities {
|
|||
AdminAvatarDecorationsUpdateRequest,
|
||||
AdminCaptchaCurrentResponse,
|
||||
AdminCaptchaSaveRequest,
|
||||
AdminCwInstanceRequest,
|
||||
AdminCwNoteRequest,
|
||||
AdminCwUserRequest,
|
||||
AdminDeclineUserRequest,
|
||||
|
|
@ -2954,6 +2958,12 @@ type ModerationLog = {
|
|||
} | {
|
||||
type: 'setMandatoryCW';
|
||||
info: ModerationLogPayloads['setMandatoryCW'];
|
||||
} | {
|
||||
type: 'setMandatoryCWForNote';
|
||||
info: ModerationLogPayloads['setMandatoryCWForNote'];
|
||||
} | {
|
||||
type: 'setMandatoryCWForInstance';
|
||||
info: ModerationLogPayloads['setMandatoryCWForInstance'];
|
||||
} | {
|
||||
type: 'setRemoteInstanceNSFW';
|
||||
info: ModerationLogPayloads['setRemoteInstanceNSFW'];
|
||||
|
|
@ -3101,7 +3111,7 @@ type ModerationLog = {
|
|||
});
|
||||
|
||||
// @public (undocumented)
|
||||
export const moderationLogTypes: readonly ["updateServerSettings", "suspend", "approve", "decline", "unsuspend", "updateUserNote", "addCustomEmoji", "updateCustomEmoji", "deleteCustomEmoji", "assignRole", "unassignRole", "createRole", "updateRole", "deleteRole", "clearQueue", "promoteQueue", "deleteDriveFile", "deleteNote", "createGlobalAnnouncement", "createUserAnnouncement", "updateGlobalAnnouncement", "updateUserAnnouncement", "deleteGlobalAnnouncement", "deleteUserAnnouncement", "resetPassword", "setMandatoryCW", "setMandatoryCWForNote", "setRemoteInstanceNSFW", "unsetRemoteInstanceNSFW", "suspendRemoteInstance", "unsuspendRemoteInstance", "rejectRemoteInstanceReports", "acceptRemoteInstanceReports", "updateRemoteInstanceNote", "markSensitiveDriveFile", "unmarkSensitiveDriveFile", "resolveAbuseReport", "forwardAbuseReport", "updateAbuseReportNote", "createInvitation", "createAd", "updateAd", "deleteAd", "createAvatarDecoration", "updateAvatarDecoration", "deleteAvatarDecoration", "unsetUserAvatar", "unsetUserBanner", "createSystemWebhook", "updateSystemWebhook", "deleteSystemWebhook", "createAbuseReportNotificationRecipient", "updateAbuseReportNotificationRecipient", "deleteAbuseReportNotificationRecipient", "deleteAccount", "deletePage", "deleteFlash", "deleteGalleryPost", "deleteChatRoom"];
|
||||
export const moderationLogTypes: readonly ["updateServerSettings", "suspend", "approve", "decline", "unsuspend", "updateUserNote", "addCustomEmoji", "updateCustomEmoji", "deleteCustomEmoji", "assignRole", "unassignRole", "createRole", "updateRole", "deleteRole", "clearQueue", "promoteQueue", "deleteDriveFile", "deleteNote", "createGlobalAnnouncement", "createUserAnnouncement", "updateGlobalAnnouncement", "updateUserAnnouncement", "deleteGlobalAnnouncement", "deleteUserAnnouncement", "resetPassword", "setMandatoryCW", "setMandatoryCWForNote", "setMandatoryCWForInstance", "setRemoteInstanceNSFW", "unsetRemoteInstanceNSFW", "suspendRemoteInstance", "unsuspendRemoteInstance", "rejectRemoteInstanceReports", "acceptRemoteInstanceReports", "updateRemoteInstanceNote", "markSensitiveDriveFile", "unmarkSensitiveDriveFile", "resolveAbuseReport", "forwardAbuseReport", "updateAbuseReportNote", "createInvitation", "createAd", "updateAd", "deleteAd", "createAvatarDecoration", "updateAvatarDecoration", "deleteAvatarDecoration", "unsetUserAvatar", "unsetUserBanner", "createSystemWebhook", "updateSystemWebhook", "deleteSystemWebhook", "createAbuseReportNotificationRecipient", "updateAbuseReportNotificationRecipient", "deleteAbuseReportNotificationRecipient", "deleteAccount", "deletePage", "deleteFlash", "deleteGalleryPost", "deleteChatRoom"];
|
||||
|
||||
// @public (undocumented)
|
||||
type MuteCreateRequest = operations['mute___create']['requestBody']['content']['application/json'];
|
||||
|
|
@ -3411,7 +3421,7 @@ type PartialRolePolicyOverride = Partial<{
|
|||
}>;
|
||||
|
||||
// @public (undocumented)
|
||||
export const permissions: readonly ["read:account", "write:account", "read:blocks", "write:blocks", "read:drive", "write:drive", "read:favorites", "write:favorites", "read:following", "write:following", "read:messaging", "write:messaging", "read:mutes", "write:mutes", "write:notes", "read:notes-schedule", "write:notes-schedule", "read:notifications", "write:notifications", "read:reactions", "write:reactions", "write:votes", "read:pages", "write:pages", "write:page-likes", "read:page-likes", "read:user-groups", "write:user-groups", "read:channels", "write:channels", "read:gallery", "write:gallery", "read:gallery-likes", "write:gallery-likes", "read:flash", "write:flash", "read:flash-likes", "write:flash-likes", "read:admin:abuse-user-reports", "write:admin:delete-account", "write:admin:delete-all-files-of-a-user", "read:admin:index-stats", "read:admin:table-stats", "read:admin:user-ips", "read:admin:meta", "write:admin:reset-password", "write:admin:resolve-abuse-user-report", "write:admin:send-email", "read:admin:server-info", "read:admin:show-moderation-log", "read:admin:show-user", "write:admin:suspend-user", "write:admin:approve-user", "write:admin:decline-user", "write:admin:nsfw-user", "write:admin:unnsfw-user", "write:admin:cw-user", "write:admin:cw-note", "write:admin:silence-user", "write:admin:unsilence-user", "write:admin:unset-user-avatar", "write:admin:unset-user-banner", "write:admin:unsuspend-user", "write:admin:reject-quotes", "write:admin:meta", "write:admin:user-note", "write:admin:roles", "read:admin:roles", "write:admin:relays", "read:admin:relays", "write:admin:invite-codes", "read:admin:invite-codes", "write:admin:announcements", "read:admin:announcements", "write:admin:avatar-decorations", "read:admin:avatar-decorations", "write:admin:federation", "write:admin:account", "read:admin:account", "write:admin:emoji", "read:admin:emoji", "write:admin:queue", "read:admin:queue", "write:admin:promo", "write:admin:drive", "read:admin:drive", "write:admin:ad", "read:admin:ad", "write:invite-codes", "read:invite-codes", "write:clip-favorite", "read:clip-favorite", "read:federation", "write:report-abuse", "write:chat", "read:chat"];
|
||||
export const permissions: readonly ["read:account", "write:account", "read:blocks", "write:blocks", "read:drive", "write:drive", "read:favorites", "write:favorites", "read:following", "write:following", "read:messaging", "write:messaging", "read:mutes", "write:mutes", "write:notes", "read:notes-schedule", "write:notes-schedule", "read:notifications", "write:notifications", "read:reactions", "write:reactions", "write:votes", "read:pages", "write:pages", "write:page-likes", "read:page-likes", "read:user-groups", "write:user-groups", "read:channels", "write:channels", "read:gallery", "write:gallery", "read:gallery-likes", "write:gallery-likes", "read:flash", "write:flash", "read:flash-likes", "write:flash-likes", "read:admin:abuse-user-reports", "write:admin:delete-account", "write:admin:delete-all-files-of-a-user", "read:admin:index-stats", "read:admin:table-stats", "read:admin:user-ips", "read:admin:meta", "write:admin:reset-password", "write:admin:resolve-abuse-user-report", "write:admin:send-email", "read:admin:server-info", "read:admin:show-moderation-log", "read:admin:show-user", "write:admin:suspend-user", "write:admin:approve-user", "write:admin:decline-user", "write:admin:nsfw-user", "write:admin:unnsfw-user", "write:admin:cw-user", "write:admin:cw-note", "write:admin:cw-instance", "write:admin:silence-user", "write:admin:unsilence-user", "write:admin:unset-user-avatar", "write:admin:unset-user-banner", "write:admin:unsuspend-user", "write:admin:reject-quotes", "write:admin:meta", "write:admin:user-note", "write:admin:roles", "read:admin:roles", "write:admin:relays", "read:admin:relays", "write:admin:invite-codes", "read:admin:invite-codes", "write:admin:announcements", "read:admin:announcements", "write:admin:avatar-decorations", "read:admin:avatar-decorations", "write:admin:federation", "write:admin:account", "read:admin:account", "write:admin:emoji", "read:admin:emoji", "write:admin:queue", "read:admin:queue", "write:admin:promo", "write:admin:drive", "read:admin:drive", "write:admin:ad", "read:admin:ad", "write:invite-codes", "read:invite-codes", "write:clip-favorite", "read:clip-favorite", "read:federation", "write:report-abuse", "write:chat", "read:chat"];
|
||||
|
||||
// @public (undocumented)
|
||||
type PingResponse = operations['ping']['responses']['200']['content']['application/json'];
|
||||
|
|
|
|||
|
|
@ -272,6 +272,17 @@ declare module '../api.js' {
|
|||
credential?: string | null,
|
||||
): Promise<SwitchCaseResponseType<E, P>>;
|
||||
|
||||
/**
|
||||
* No description provided.
|
||||
*
|
||||
* **Credential required**: *Yes* / **Permission**: *write:admin:cw-instance*
|
||||
*/
|
||||
request<E extends 'admin/cw-instance', P extends Endpoints[E]['req']>(
|
||||
endpoint: E,
|
||||
params: P,
|
||||
credential?: string | null,
|
||||
): Promise<SwitchCaseResponseType<E, P>>;
|
||||
|
||||
/**
|
||||
* No description provided.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ import type {
|
|||
AdminAvatarDecorationsUpdateRequest,
|
||||
AdminCaptchaCurrentResponse,
|
||||
AdminCaptchaSaveRequest,
|
||||
AdminCwInstanceRequest,
|
||||
AdminCwNoteRequest,
|
||||
AdminCwUserRequest,
|
||||
AdminDeclineUserRequest,
|
||||
|
|
@ -690,6 +691,7 @@ export type Endpoints = {
|
|||
'admin/avatar-decorations/update': { req: AdminAvatarDecorationsUpdateRequest; res: EmptyResponse };
|
||||
'admin/captcha/current': { req: EmptyRequest; res: AdminCaptchaCurrentResponse };
|
||||
'admin/captcha/save': { req: AdminCaptchaSaveRequest; res: EmptyResponse };
|
||||
'admin/cw-instance': { req: AdminCwInstanceRequest; res: EmptyResponse };
|
||||
'admin/cw-note': { req: AdminCwNoteRequest; res: EmptyResponse };
|
||||
'admin/cw-user': { req: AdminCwUserRequest; res: EmptyResponse };
|
||||
'admin/decline-user': { req: AdminDeclineUserRequest; res: EmptyResponse };
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ export type AdminAvatarDecorationsListResponse = operations['admin___avatar-deco
|
|||
export type AdminAvatarDecorationsUpdateRequest = operations['admin___avatar-decorations___update']['requestBody']['content']['application/json'];
|
||||
export type AdminCaptchaCurrentResponse = operations['admin___captcha___current']['responses']['200']['content']['application/json'];
|
||||
export type AdminCaptchaSaveRequest = operations['admin___captcha___save']['requestBody']['content']['application/json'];
|
||||
export type AdminCwInstanceRequest = operations['admin___cw-instance']['requestBody']['content']['application/json'];
|
||||
export type AdminCwNoteRequest = operations['admin___cw-note']['requestBody']['content']['application/json'];
|
||||
export type AdminCwUserRequest = operations['admin___cw-user']['requestBody']['content']['application/json'];
|
||||
export type AdminDeclineUserRequest = operations['admin___decline-user']['requestBody']['content']['application/json'];
|
||||
|
|
|
|||
|
|
@ -233,6 +233,15 @@ export type paths = {
|
|||
*/
|
||||
post: operations['admin___captcha___save'];
|
||||
};
|
||||
'/admin/cw-instance': {
|
||||
/**
|
||||
* admin/cw-instance
|
||||
* @description No description provided.
|
||||
*
|
||||
* **Credential required**: *Yes* / **Permission**: *write:admin:cw-instance*
|
||||
*/
|
||||
post: operations['admin___cw-instance'];
|
||||
};
|
||||
'/admin/cw-note': {
|
||||
/**
|
||||
* admin/cw-note
|
||||
|
|
@ -4309,6 +4318,7 @@ export type components = {
|
|||
faviconUrl: string | null;
|
||||
themeColor: string | null;
|
||||
isSilenced: boolean;
|
||||
mandatoryCW: string | null;
|
||||
};
|
||||
followersCount: number;
|
||||
followingCount: number;
|
||||
|
|
@ -5341,6 +5351,7 @@ export type components = {
|
|||
rejectQuotes: boolean;
|
||||
moderationNote?: string | null;
|
||||
isBubbled: boolean;
|
||||
mandatoryCW: string | null;
|
||||
};
|
||||
GalleryPost: {
|
||||
/**
|
||||
|
|
@ -7399,6 +7410,58 @@ export type operations = {
|
|||
};
|
||||
};
|
||||
};
|
||||
/**
|
||||
* admin/cw-instance
|
||||
* @description No description provided.
|
||||
*
|
||||
* **Credential required**: *Yes* / **Permission**: *write:admin:cw-instance*
|
||||
*/
|
||||
'admin___cw-instance': {
|
||||
requestBody: {
|
||||
content: {
|
||||
'application/json': {
|
||||
host: string;
|
||||
cw: string | null;
|
||||
};
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description OK (without any results) */
|
||||
204: {
|
||||
content: never;
|
||||
};
|
||||
/** @description Client error */
|
||||
400: {
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description Authentication error */
|
||||
401: {
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description Forbidden error */
|
||||
403: {
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description I'm Ai */
|
||||
418: {
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description Internal server error */
|
||||
500: {
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
/**
|
||||
* admin/cw-note
|
||||
* @description No description provided.
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ export const permissions = [
|
|||
'write:admin:unnsfw-user',
|
||||
'write:admin:cw-user',
|
||||
'write:admin:cw-note',
|
||||
'write:admin:cw-instance',
|
||||
'write:admin:silence-user',
|
||||
'write:admin:unsilence-user',
|
||||
'write:admin:unset-user-avatar',
|
||||
|
|
@ -150,6 +151,7 @@ export const moderationLogTypes = [
|
|||
'resetPassword',
|
||||
'setMandatoryCW',
|
||||
'setMandatoryCWForNote',
|
||||
'setMandatoryCWForInstance',
|
||||
'setRemoteInstanceNSFW',
|
||||
'unsetRemoteInstanceNSFW',
|
||||
'suspendRemoteInstance',
|
||||
|
|
@ -353,6 +355,11 @@ export type ModerationLogPayloads = {
|
|||
noteUserUsername: string;
|
||||
noteUserHost: string | null;
|
||||
};
|
||||
setMandatoryCWForInstance: {
|
||||
newCW: string | null;
|
||||
oldCW: string | null;
|
||||
host: string;
|
||||
};
|
||||
setRemoteInstanceNSFW: {
|
||||
id: string;
|
||||
host: string;
|
||||
|
|
|
|||
|
|
@ -136,6 +136,9 @@ export type ModerationLog = {
|
|||
} | {
|
||||
type: 'setMandatoryCWForNote';
|
||||
info: ModerationLogPayloads['setMandatoryCWForNote'];
|
||||
} | {
|
||||
type: 'setMandatoryCWForInstance';
|
||||
info: ModerationLogPayloads['setMandatoryCWForInstance'];
|
||||
} | {
|
||||
type: 'setRemoteInstanceNSFW';
|
||||
info: ModerationLogPayloads['setRemoteInstanceNSFW'];
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ userSaysSomethingInMutedNote: "{name} said something in a muted post"
|
|||
userSaysSomethingInMutedThread: "{name} said something in a muted thread"
|
||||
userIsFlaggedAs: "{name} is flagged: \"{cw}\""
|
||||
noteIsFlaggedAs: "Note is flagged: \"{cw}\""
|
||||
instanceIsFlaggedAs: "{name} is flagged: \"{cw}\""
|
||||
markAsNSFW: "Mark all media from user as NSFW"
|
||||
markInstanceAsNSFW: "Mark as NSFW"
|
||||
nsfwConfirm: "Are you sure that you want to mark all media from this account as NSFW?"
|
||||
|
|
@ -346,6 +347,7 @@ _moderationLogTypes:
|
|||
decline: "Declined"
|
||||
setMandatoryCW: "Set content warning for user"
|
||||
setMandatoryCWForNote: "Set content warning for note"
|
||||
setMandatoryCWForInstance: "Set content warning for instance"
|
||||
setRemoteInstanceNSFW: "Set remote instance as NSFW"
|
||||
unsetRemoteInstanceNSFW: "Unset remote instance as NSFW"
|
||||
rejectRemoteInstanceReports: "Rejected reports from remote instance"
|
||||
|
|
@ -507,6 +509,7 @@ _permissions:
|
|||
"write:admin:unnsfw-user": "Mark users as not NSFW"
|
||||
"write:admin:cw-user": "Apply mandatory CW on users"
|
||||
"write:admin:cw-note": "Apply mandatory CW on notes"
|
||||
"write:admin:cw-instance": "Apply mandatory CW on instances"
|
||||
"write:admin:silence-user": "Silence users"
|
||||
"write:admin:unsilence-user": "Un-silence users"
|
||||
"write:admin:reject-quotes": "Allow/Prohibit quote posts from a user"
|
||||
|
|
@ -548,6 +551,8 @@ mandatoryCW: "Force content warning"
|
|||
mandatoryCWDescription: "Applies a content warning to all posts created by this user. The forced warnings will appear like a word mute to distinguish them from the author's own content warnings."
|
||||
mandatoryCWForNote: "Force content warning"
|
||||
mandatoryCWForNoteDescription: "Applies an additional content warning to this post. The new warning will appear like a word mute to distinguish it from the author's own content warning."
|
||||
mandatoryCWForInstance: "Force content warning"
|
||||
mandatoryCWForInstanceDescription: "Applies a content warning to all posts originating from this instance. The forced warnings will appear like a word mute to distinguish them from the notes' own content warnings."
|
||||
fetchLinkedNote: "Fetch linked note"
|
||||
showTranslationButtonInNoteFooter: "Add \"Translate\" to note action menu"
|
||||
translationFailed: "Failed to translate note. Please try again later or contact an administrator for assistance."
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue