feat(webhook): 通報の登録、解決、自動解決に対応 (#615)
This commit is contained in:
parent
432833747d
commit
470ce2e0f4
12
locales/index.d.ts
vendored
12
locales/index.d.ts
vendored
@ -9484,6 +9484,18 @@ export interface Locale extends ILocale {
|
|||||||
* メンションされたとき
|
* メンションされたとき
|
||||||
*/
|
*/
|
||||||
"mention": string;
|
"mention": string;
|
||||||
|
/**
|
||||||
|
* 通報が作成されたとき
|
||||||
|
*/
|
||||||
|
"reportCreated": string;
|
||||||
|
/**
|
||||||
|
* 通報が解決されたとき
|
||||||
|
*/
|
||||||
|
"reportResolved": string;
|
||||||
|
/**
|
||||||
|
* 通報が自動解決されたとき
|
||||||
|
*/
|
||||||
|
"reportAutoResolved": string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
"_abuse": {
|
"_abuse": {
|
||||||
|
@ -2513,6 +2513,9 @@ _webhookSettings:
|
|||||||
renote: "Renoteされたとき"
|
renote: "Renoteされたとき"
|
||||||
reaction: "リアクションがあったとき"
|
reaction: "リアクションがあったとき"
|
||||||
mention: "メンションされたとき"
|
mention: "メンションされたとき"
|
||||||
|
reportCreated: "通報が登録されたとき"
|
||||||
|
reportResolved: "通報が解決されたとき"
|
||||||
|
reportAutoResolved: "通報が自動解決されたとき"
|
||||||
|
|
||||||
_abuse:
|
_abuse:
|
||||||
_resolver:
|
_resolver:
|
||||||
|
@ -7,7 +7,7 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typ
|
|||||||
import { id } from './util/id.js';
|
import { id } from './util/id.js';
|
||||||
import { MiUser } from './User.js';
|
import { MiUser } from './User.js';
|
||||||
|
|
||||||
export const webhookEventTypes = ['mention', 'unfollow', 'follow', 'followed', 'note', 'reply', 'renote', 'reaction'] as const;
|
export const webhookEventTypes = ['mention', 'unfollow', 'follow', 'followed', 'note', 'reply', 'renote', 'reaction', 'reportCreated', 'reportResolved', 'reportAutoResolved'] as const;
|
||||||
|
|
||||||
@Entity('webhook')
|
@Entity('webhook')
|
||||||
export class MiWebhook {
|
export class MiWebhook {
|
||||||
|
@ -15,6 +15,7 @@ import type { AbuseReportResolversRepository, AbuseUserReportsRepository, UsersR
|
|||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
||||||
import { QueueService } from '@/core/QueueService.js';
|
import { QueueService } from '@/core/QueueService.js';
|
||||||
|
import { WebhookService } from '@/core/WebhookService.js';
|
||||||
import { QueueLoggerService } from '../QueueLoggerService.js';
|
import { QueueLoggerService } from '../QueueLoggerService.js';
|
||||||
import type { DbAbuseReportJobData } from '../types.js';
|
import type { DbAbuseReportJobData } from '../types.js';
|
||||||
import type * as Bull from 'bullmq';
|
import type * as Bull from 'bullmq';
|
||||||
@ -39,6 +40,7 @@ export class ReportAbuseProcessorService {
|
|||||||
private apRendererService: ApRendererService,
|
private apRendererService: ApRendererService,
|
||||||
private roleService: RoleService,
|
private roleService: RoleService,
|
||||||
private queueService: QueueService,
|
private queueService: QueueService,
|
||||||
|
private webhookService: WebhookService,
|
||||||
) {
|
) {
|
||||||
this.logger = this.queueLoggerService.logger.createSubLogger('report-abuse');
|
this.logger = this.queueLoggerService.logger.createSubLogger('report-abuse');
|
||||||
}
|
}
|
||||||
@ -86,6 +88,20 @@ export class ReportAbuseProcessorService {
|
|||||||
forwarded: resolver.forward && job.data.targetUserHost !== null && job.data.reporterHost === null,
|
forwarded: resolver.forward && job.data.targetUserHost !== null && job.data.reporterHost === null,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const activeWebhooks = await this.webhookService.getActiveWebhooks();
|
||||||
|
for (const webhook of activeWebhooks) {
|
||||||
|
const webhookUser = await this.usersRepository.findOneByOrFail({
|
||||||
|
id: webhook.userId,
|
||||||
|
});
|
||||||
|
const isAdmin = await this.roleService.isAdministrator(webhookUser);
|
||||||
|
if (webhook.on.includes('reportAutoResolved') && isAdmin) {
|
||||||
|
this.queueService.webhookDeliver(webhook, 'reportAutoResolved', {
|
||||||
|
resolver: resolver,
|
||||||
|
report: job.data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,8 @@ import { QueueService } from '@/core/QueueService.js';
|
|||||||
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
||||||
|
import { WebhookService } from '@/core/WebhookService.js';
|
||||||
|
import { RoleService } from '@/core/RoleService.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
@ -44,6 +46,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||||||
private instanceActorService: InstanceActorService,
|
private instanceActorService: InstanceActorService,
|
||||||
private apRendererService: ApRendererService,
|
private apRendererService: ApRendererService,
|
||||||
private moderationLogService: ModerationLogService,
|
private moderationLogService: ModerationLogService,
|
||||||
|
private webhookService: WebhookService,
|
||||||
|
private roleService: RoleService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const report = await this.abuseUserReportsRepository.findOneBy({ id: ps.reportId });
|
const report = await this.abuseUserReportsRepository.findOneBy({ id: ps.reportId });
|
||||||
@ -59,11 +63,24 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||||||
this.queueService.deliver(actor, this.apRendererService.addContext(this.apRendererService.renderFlag(actor, targetUser.uri!, report.comment)), targetUser.inbox, false);
|
this.queueService.deliver(actor, this.apRendererService.addContext(this.apRendererService.renderFlag(actor, targetUser.uri!, report.comment)), targetUser.inbox, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.abuseUserReportsRepository.update(report.id, {
|
const updatedReport = await this.abuseUserReportsRepository.update(report.id, {
|
||||||
resolved: true,
|
resolved: true,
|
||||||
assigneeId: me.id,
|
assigneeId: me.id,
|
||||||
forwarded: ps.forward && report.targetUserHost != null,
|
forwarded: ps.forward && report.targetUserHost != null,
|
||||||
|
}).then(() => this.abuseUserReportsRepository.findOneBy({ id: ps.reportId }));
|
||||||
|
|
||||||
|
const activeWebhooks = await this.webhookService.getActiveWebhooks();
|
||||||
|
for (const webhook of activeWebhooks) {
|
||||||
|
const webhookUser = await this.usersRepository.findOneByOrFail({
|
||||||
|
id: webhook.userId,
|
||||||
});
|
});
|
||||||
|
const isAdmin = await this.roleService.isAdministrator(webhookUser);
|
||||||
|
if (webhook.on.includes('reportResolved') && isAdmin) {
|
||||||
|
this.queueService.webhookDeliver(webhook, 'reportResolved', {
|
||||||
|
updatedReport,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.moderationLogService.log(me, 'resolveAbuseReport', {
|
this.moderationLogService.log(me, 'resolveAbuseReport', {
|
||||||
reportId: report.id,
|
reportId: report.id,
|
||||||
|
@ -27,6 +27,11 @@ export const meta = {
|
|||||||
code: 'TOO_MANY_WEBHOOKS',
|
code: 'TOO_MANY_WEBHOOKS',
|
||||||
id: '87a9bb19-111e-4e37-81d3-a3e7426453b0',
|
id: '87a9bb19-111e-4e37-81d3-a3e7426453b0',
|
||||||
},
|
},
|
||||||
|
youAreNotAdmin: {
|
||||||
|
message: 'You are not an administrator.',
|
||||||
|
code: 'YOU_ARE_NOT_ADMIN',
|
||||||
|
id: '26601bea-079b-4782-8dac-071febe2acf9',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
res: {
|
res: {
|
||||||
@ -90,6 +95,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||||||
throw new ApiError(meta.errors.tooManyWebhooks);
|
throw new ApiError(meta.errors.tooManyWebhooks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ps.on.includes('reportCreated') || ps.on.includes('reportResolved') || ps.on.includes('reportAutoResolved')) {
|
||||||
|
if (!await this.roleService.isAdministrator(me)) {
|
||||||
|
throw new ApiError(meta.errors.youAreNotAdmin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const webhook = await this.webhooksRepository.insert({
|
const webhook = await this.webhooksRepository.insert({
|
||||||
id: this.idService.gen(),
|
id: this.idService.gen(),
|
||||||
userId: me.id,
|
userId: me.id,
|
||||||
|
@ -9,6 +9,7 @@ import type { WebhooksRepository } from '@/models/_.js';
|
|||||||
import { webhookEventTypes } from '@/models/Webhook.js';
|
import { webhookEventTypes } from '@/models/Webhook.js';
|
||||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import { RoleService } from '@/core/RoleService.js';
|
||||||
import { ApiError } from '../../../error.js';
|
import { ApiError } from '../../../error.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
@ -25,6 +26,11 @@ export const meta = {
|
|||||||
code: 'NO_SUCH_WEBHOOK',
|
code: 'NO_SUCH_WEBHOOK',
|
||||||
id: 'fb0fea69-da18-45b1-828d-bd4fd1612518',
|
id: 'fb0fea69-da18-45b1-828d-bd4fd1612518',
|
||||||
},
|
},
|
||||||
|
youAreNotAdmin: {
|
||||||
|
message: 'You are not an administrator.',
|
||||||
|
code: 'YOU_ARE_NOT_ADMIN',
|
||||||
|
id: 'a70c7643-1db5-4ebf-becd-ff4b4223cf23',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
} as const;
|
} as const;
|
||||||
@ -53,6 +59,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||||||
private webhooksRepository: WebhooksRepository,
|
private webhooksRepository: WebhooksRepository,
|
||||||
|
|
||||||
private globalEventService: GlobalEventService,
|
private globalEventService: GlobalEventService,
|
||||||
|
private roleService: RoleService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const webhook = await this.webhooksRepository.findOneBy({
|
const webhook = await this.webhooksRepository.findOneBy({
|
||||||
@ -64,6 +71,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||||||
throw new ApiError(meta.errors.noSuchWebhook);
|
throw new ApiError(meta.errors.noSuchWebhook);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ps.on.includes('reportCreated') || ps.on.includes('reportResolved') || ps.on.includes('reportAutoResolved')) {
|
||||||
|
if (!await this.roleService.isAdministrator(me)) {
|
||||||
|
throw new ApiError(meta.errors.youAreNotAdmin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await this.webhooksRepository.update(webhook.id, {
|
await this.webhooksRepository.update(webhook.id, {
|
||||||
name: ps.name,
|
name: ps.name,
|
||||||
url: ps.url,
|
url: ps.url,
|
||||||
|
@ -5,13 +5,14 @@
|
|||||||
|
|
||||||
import sanitizeHtml from 'sanitize-html';
|
import sanitizeHtml from 'sanitize-html';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import type { AbuseUserReportsRepository } from '@/models/_.js';
|
import type { AbuseUserReportsRepository, UsersRepository } from '@/models/_.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { GetterService } from '@/server/api/GetterService.js';
|
import { GetterService } from '@/server/api/GetterService.js';
|
||||||
import { RoleService } from '@/core/RoleService.js';
|
import { RoleService } from '@/core/RoleService.js';
|
||||||
import { QueueService } from '@/core/QueueService.js';
|
import { QueueService } from '@/core/QueueService.js';
|
||||||
|
import { WebhookService } from '@/core/WebhookService.js';
|
||||||
import { ApiError } from '../../error.js';
|
import { ApiError } from '../../error.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
@ -69,10 +70,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||||||
@Inject(DI.abuseUserReportsRepository)
|
@Inject(DI.abuseUserReportsRepository)
|
||||||
private abuseUserReportsRepository: AbuseUserReportsRepository,
|
private abuseUserReportsRepository: AbuseUserReportsRepository,
|
||||||
|
|
||||||
|
@Inject(DI.usersRepository)
|
||||||
|
private usersRepository: UsersRepository,
|
||||||
|
|
||||||
private idService: IdService,
|
private idService: IdService,
|
||||||
private getterService: GetterService,
|
private getterService: GetterService,
|
||||||
private roleService: RoleService,
|
private roleService: RoleService,
|
||||||
private queueService: QueueService,
|
private queueService: QueueService,
|
||||||
|
private webhookService: WebhookService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
// Lookup user
|
// Lookup user
|
||||||
@ -95,6 +100,19 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||||||
category: ps.category,
|
category: ps.category,
|
||||||
}).then(x => this.abuseUserReportsRepository.findOneByOrFail(x.identifiers[0]));
|
}).then(x => this.abuseUserReportsRepository.findOneByOrFail(x.identifiers[0]));
|
||||||
|
|
||||||
|
const activeWebhooks = await this.webhookService.getActiveWebhooks();
|
||||||
|
for (const webhook of activeWebhooks) {
|
||||||
|
const webhookUser = await this.usersRepository.findOneByOrFail({
|
||||||
|
id: webhook.userId,
|
||||||
|
});
|
||||||
|
const isAdmin = await this.roleService.isAdministrator(webhookUser);
|
||||||
|
if (webhook.on.includes('reportCreated') && isAdmin) {
|
||||||
|
this.queueService.webhookDeliver(webhook, 'reportCreated', {
|
||||||
|
report,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.queueService.createReportAbuseJob(report);
|
this.queueService.createReportAbuseJob(report);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
<MkSwitch v-model="event_renote">{{ i18n.ts._webhookSettings._events.renote }}</MkSwitch>
|
<MkSwitch v-model="event_renote">{{ i18n.ts._webhookSettings._events.renote }}</MkSwitch>
|
||||||
<MkSwitch v-model="event_reaction">{{ i18n.ts._webhookSettings._events.reaction }}</MkSwitch>
|
<MkSwitch v-model="event_reaction">{{ i18n.ts._webhookSettings._events.reaction }}</MkSwitch>
|
||||||
<MkSwitch v-model="event_mention">{{ i18n.ts._webhookSettings._events.mention }}</MkSwitch>
|
<MkSwitch v-model="event_mention">{{ i18n.ts._webhookSettings._events.mention }}</MkSwitch>
|
||||||
|
<MkSwitch v-if="$i?.isAdmin" v-model="event_reportCreated">{{ i18n.ts._webhookSettings._events.reportCreated }}</MkSwitch>
|
||||||
|
<MkSwitch v-if="$i?.isAdmin" v-model="event_reportResolved">{{ i18n.ts._webhookSettings._events.reportResolved }}</MkSwitch>
|
||||||
|
<MkSwitch v-if="$i?.isAdmin" v-model="event_reportAutoResolved">{{ i18n.ts._webhookSettings._events.reportAutoResolved }}</MkSwitch>
|
||||||
</div>
|
</div>
|
||||||
</FormSection>
|
</FormSection>
|
||||||
|
|
||||||
@ -52,6 +55,7 @@ import { misskeyApi } from '@/scripts/misskey-api.js';
|
|||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router/supplier.js';
|
||||||
|
import { $i } from '@/account.js';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
@ -75,6 +79,9 @@ const event_reply = ref(webhook.on.includes('reply'));
|
|||||||
const event_renote = ref(webhook.on.includes('renote'));
|
const event_renote = ref(webhook.on.includes('renote'));
|
||||||
const event_reaction = ref(webhook.on.includes('reaction'));
|
const event_reaction = ref(webhook.on.includes('reaction'));
|
||||||
const event_mention = ref(webhook.on.includes('mention'));
|
const event_mention = ref(webhook.on.includes('mention'));
|
||||||
|
const event_reportCreated = ref(webhook.on.includes('reportCreated'));
|
||||||
|
const event_reportResolved = ref(webhook.on.includes('reportResolved'));
|
||||||
|
const event_reportAutoResolved = ref(webhook.on.includes('reportAutoResolved'));
|
||||||
|
|
||||||
async function save(): Promise<void> {
|
async function save(): Promise<void> {
|
||||||
const events = [];
|
const events = [];
|
||||||
@ -85,6 +92,9 @@ async function save(): Promise<void> {
|
|||||||
if (event_renote.value) events.push('renote');
|
if (event_renote.value) events.push('renote');
|
||||||
if (event_reaction.value) events.push('reaction');
|
if (event_reaction.value) events.push('reaction');
|
||||||
if (event_mention.value) events.push('mention');
|
if (event_mention.value) events.push('mention');
|
||||||
|
if (event_reportCreated.value) events.push('reportCreated');
|
||||||
|
if (event_reportResolved.value) events.push('reportResolved');
|
||||||
|
if (event_reportAutoResolved.value) events.push('reportAutoResolved');
|
||||||
|
|
||||||
os.apiWithDialog('i/webhooks/update', {
|
os.apiWithDialog('i/webhooks/update', {
|
||||||
name: name.value,
|
name: name.value,
|
||||||
|
@ -29,6 +29,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
<MkSwitch v-model="event_renote">{{ i18n.ts._webhookSettings._events.renote }}</MkSwitch>
|
<MkSwitch v-model="event_renote">{{ i18n.ts._webhookSettings._events.renote }}</MkSwitch>
|
||||||
<MkSwitch v-model="event_reaction">{{ i18n.ts._webhookSettings._events.reaction }}</MkSwitch>
|
<MkSwitch v-model="event_reaction">{{ i18n.ts._webhookSettings._events.reaction }}</MkSwitch>
|
||||||
<MkSwitch v-model="event_mention">{{ i18n.ts._webhookSettings._events.mention }}</MkSwitch>
|
<MkSwitch v-model="event_mention">{{ i18n.ts._webhookSettings._events.mention }}</MkSwitch>
|
||||||
|
<MkSwitch v-if="$i?.isAdmin" v-model="event_reportCreated">{{ i18n.ts._webhookSettings._events.reportCreated }}</MkSwitch>
|
||||||
|
<MkSwitch v-if="$i?.isAdmin" v-model="event_reportResolved">{{ i18n.ts._webhookSettings._events.reportResolved }}</MkSwitch>
|
||||||
|
<MkSwitch v-if="$i?.isAdmin" v-model="event_reportAutoResolved">{{ i18n.ts._webhookSettings._events.reportAutoResolved }}</MkSwitch>
|
||||||
</div>
|
</div>
|
||||||
</FormSection>
|
</FormSection>
|
||||||
|
|
||||||
@ -47,6 +50,7 @@ import MkButton from '@/components/MkButton.vue';
|
|||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
|
import { $i } from '@/account.js';
|
||||||
|
|
||||||
const name = ref('');
|
const name = ref('');
|
||||||
const url = ref('');
|
const url = ref('');
|
||||||
@ -59,6 +63,9 @@ const event_reply = ref(true);
|
|||||||
const event_renote = ref(true);
|
const event_renote = ref(true);
|
||||||
const event_reaction = ref(true);
|
const event_reaction = ref(true);
|
||||||
const event_mention = ref(true);
|
const event_mention = ref(true);
|
||||||
|
const event_reportCreated = ref(false);
|
||||||
|
const event_reportResolved = ref(false);
|
||||||
|
const event_reportAutoResolved = ref(false);
|
||||||
|
|
||||||
async function create(): Promise<void> {
|
async function create(): Promise<void> {
|
||||||
const events = [];
|
const events = [];
|
||||||
@ -69,6 +76,9 @@ async function create(): Promise<void> {
|
|||||||
if (event_renote.value) events.push('renote');
|
if (event_renote.value) events.push('renote');
|
||||||
if (event_reaction.value) events.push('reaction');
|
if (event_reaction.value) events.push('reaction');
|
||||||
if (event_mention.value) events.push('mention');
|
if (event_mention.value) events.push('mention');
|
||||||
|
if (event_reportCreated.value) events.push('reportCreated');
|
||||||
|
if (event_reportResolved.value) events.push('reportResolved');
|
||||||
|
if (event_reportAutoResolved.value) events.push('reportAutoResolved');
|
||||||
|
|
||||||
os.apiWithDialog('i/webhooks/create', {
|
os.apiWithDialog('i/webhooks/create', {
|
||||||
name: name.value,
|
name: name.value,
|
||||||
|
Loading…
Reference in New Issue
Block a user