feat: 通報を受けた際にメールまたはWebhookで通知を送出出来るようにする (#13758)
* feat: 通報を受けた際にメールまたはWebhookで通知を送出出来るようにする * モデログに対応&エンドポイントを単一オブジェクトでのサポートに変更(API経由で大量に作るシチュエーションもないと思うので) * fix spdx * fix migration * fix migration * fix models * add e2e webhook * tweak * fix modlog * fix bugs * add tests and fix bugs * add tests and fix bugs * add tests * fix path * regenerate locale * 混入除去 * 混入除去 * add abuseReportResolved * fix pnpm-lock.yaml * add abuseReportResolved test * fix bugs * fix ui * add tests * fix CHANGELOG.md * add tests * add RoleService.getModeratorIds tests * WebhookServiceをUserとSystemに分割 * fix CHANGELOG.md * fix test * insertOneを使う用に * fix * regenerate locales * revert version * separate webhook job queue * fix * 🎨 * Update QueueProcessorService.ts --------- Co-authored-by: osamu <46447427+sam-osamu@users.noreply.github.com> Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
<template>
|
||||
<MkStickyContainer>
|
||||
<template #header>
|
||||
<XHeader :actions="headerActions" :tabs="headerTabs"/>
|
||||
</template>
|
||||
|
||||
<MkSpacer :contentMax="900">
|
||||
<div :class="$style.root" class="_gaps_m">
|
||||
<div :class="$style.addButton">
|
||||
<MkButton primary @click="onAddButtonClicked">
|
||||
<span class="ti ti-plus"/> {{ i18n.ts._abuseReport._notificationRecipient.createRecipient }}
|
||||
</MkButton>
|
||||
</div>
|
||||
<div :class="$style.subMenus" class="_gaps_s">
|
||||
<MkSelect v-model="filterMethod" style="flex: 1">
|
||||
<template #label>{{ i18n.ts._abuseReport._notificationRecipient.recipientType }}</template>
|
||||
<option :value="null">-</option>
|
||||
<option :value="'email'">{{ i18n.ts._abuseReport._notificationRecipient._recipientType.mail }}</option>
|
||||
<option :value="'webhook'">{{ i18n.ts._abuseReport._notificationRecipient._recipientType.webhook }}</option>
|
||||
</MkSelect>
|
||||
<MkInput v-model="filterText" type="search" style="flex: 1">
|
||||
<template #label>{{ i18n.ts._abuseReport._notificationRecipient.keywords }}</template>
|
||||
</MkInput>
|
||||
</div>
|
||||
|
||||
<MkDivider/>
|
||||
|
||||
<div :class="$style.recipients" class="_gaps_s">
|
||||
<XRecipient
|
||||
v-for="r in filteredRecipients"
|
||||
:key="r.id"
|
||||
:entity="r"
|
||||
@edit="onEditButtonClicked"
|
||||
@delete="onDeleteButtonClicked"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</MkSpacer>
|
||||
</MkStickyContainer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { entities } from 'misskey-js';
|
||||
import { computed, defineAsyncComponent, onMounted, ref } from 'vue';
|
||||
import XRecipient from './notification-recipient.item.vue';
|
||||
import XHeader from '@/pages/admin/_header_.vue';
|
||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
import MkSelect from '@/components/MkSelect.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import * as os from '@/os.js';
|
||||
import MkDivider from '@/components/MkDivider.vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
|
||||
const recipients = ref<entities.AbuseReportNotificationRecipient[]>([]);
|
||||
|
||||
const filterMethod = ref<string | null>(null);
|
||||
const filterText = ref<string>('');
|
||||
|
||||
const filteredRecipients = computed(() => {
|
||||
const method = filterMethod.value;
|
||||
const text = filterText.value.trim().length === 0 ? null : filterText.value;
|
||||
|
||||
return recipients.value.filter(it => {
|
||||
if (method ?? text) {
|
||||
if (text) {
|
||||
const keywords = [it.name, it.systemWebhook?.name, it.user?.name, it.user?.username];
|
||||
if (keywords.filter(k => k?.includes(text)).length !== 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (method) {
|
||||
return it.method.includes(method);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
});
|
||||
const headerActions = computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
async function onAddButtonClicked() {
|
||||
await showEditor('create');
|
||||
}
|
||||
|
||||
async function onEditButtonClicked(id: string) {
|
||||
await showEditor('edit', id);
|
||||
}
|
||||
|
||||
async function onDeleteButtonClicked(id: string) {
|
||||
const res = await os.confirm({
|
||||
type: 'warning',
|
||||
title: i18n.ts._abuseReport._notificationRecipient.deleteConfirm,
|
||||
});
|
||||
if (!res.canceled) {
|
||||
await misskeyApi('admin/abuse-report/notification-recipient/delete', { id: id });
|
||||
await fetchRecipients();
|
||||
}
|
||||
}
|
||||
|
||||
async function showEditor(mode: 'create' | 'edit', id?: string) {
|
||||
const { dispose, needLoad } = await new Promise<{ dispose: () => void, needLoad: boolean }>(async resolve => {
|
||||
const res = await os.popup(
|
||||
defineAsyncComponent(() => import('./notification-recipient.editor.vue')),
|
||||
{
|
||||
mode,
|
||||
id,
|
||||
},
|
||||
{
|
||||
submitted: async () => {
|
||||
resolve({ dispose: res.dispose, needLoad: true });
|
||||
},
|
||||
closed: () => {
|
||||
resolve({ dispose: res.dispose, needLoad: false });
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
dispose();
|
||||
|
||||
if (needLoad) {
|
||||
await fetchRecipients();
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchRecipients() {
|
||||
const result = await misskeyApi('admin/abuse-report/notification-recipient/list', {
|
||||
method: ['email', 'webhook'],
|
||||
});
|
||||
|
||||
recipients.value = result.sort((a, b) => (a.method + a.id).localeCompare(b.method + b.id));
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await fetchRecipients();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style module lang="scss">
|
||||
.root {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.addButton {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.subMenus {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.recipients {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: stretch;
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user