This commit is contained in:
おさむのひと 2024-11-23 14:22:50 +09:00
parent ef61f24c33
commit 198cdc2f24
4 changed files with 78 additions and 3 deletions

View file

@ -160,11 +160,19 @@ export class AbuseReportNotificationService implements OnApplicationShutdown {
}; };
}); });
const inactiveRecipients = await this.fetchWebhookRecipients()
.then(it => it.filter(it => !it.isActive));
const withoutWebhookIds = inactiveRecipients
.map(it => it.systemWebhookId)
.filter(x => x != null);
return Promise.all( return Promise.all(
convertedReports.map(it => { convertedReports.map(it => {
return this.systemWebhookService.enqueueSystemWebhook( return this.systemWebhookService.enqueueSystemWebhook(
type, type,
it, it,
{
excludes: withoutWebhookIds,
},
); );
}), }),
); );

View file

@ -195,9 +195,14 @@ export class SystemWebhookService implements OnApplicationShutdown {
public async enqueueSystemWebhook<T extends SystemWebhookEventType>( public async enqueueSystemWebhook<T extends SystemWebhookEventType>(
type: T, type: T,
content: SystemWebhookPayload<T>, content: SystemWebhookPayload<T>,
opts?: {
excludes?: MiSystemWebhook['id'][];
},
) { ) {
const webhooks = await this.fetchActiveSystemWebhooks() const webhooks = await this.fetchActiveSystemWebhooks()
.then(webhooks => webhooks.filter(webhook => webhook.on.includes(type))); .then(webhooks => {
return webhooks.filter(webhook => !opts?.excludes?.includes(webhook.id) && webhook.on.includes(type));
});
return Promise.all( return Promise.all(
webhooks.map(webhook => { webhooks.map(webhook => {
return this.queueService.systemWebhookDeliver(webhook, type, content); return this.queueService.systemWebhookDeliver(webhook, type, content);

View file

@ -3,13 +3,14 @@
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
import { jest } from '@jest/globals'; import { describe, jest } from '@jest/globals';
import { Test, TestingModule } from '@nestjs/testing'; import { Test, TestingModule } from '@nestjs/testing';
import { randomString } from '../utils.js'; import { randomString } from '../utils.js';
import { AbuseReportNotificationService } from '@/core/AbuseReportNotificationService.js'; import { AbuseReportNotificationService } from '@/core/AbuseReportNotificationService.js';
import { import {
AbuseReportNotificationRecipientRepository, AbuseReportNotificationRecipientRepository,
MiAbuseReportNotificationRecipient, MiAbuseReportNotificationRecipient,
MiAbuseUserReport,
MiSystemWebhook, MiSystemWebhook,
MiUser, MiUser,
SystemWebhooksRepository, SystemWebhooksRepository,
@ -112,7 +113,10 @@ describe('AbuseReportNotificationService', () => {
provide: SystemWebhookService, useFactory: () => ({ enqueueSystemWebhook: jest.fn() }), provide: SystemWebhookService, useFactory: () => ({ enqueueSystemWebhook: jest.fn() }),
}, },
{ {
provide: UserEntityService, useFactory: () => ({ pack: (v: any) => v }), provide: UserEntityService, useFactory: () => ({
pack: (v: any) => Promise.resolve(v),
packMany: (v: any) => Promise.resolve(v),
}),
}, },
{ {
provide: EmailService, useFactory: () => ({ sendEmail: jest.fn() }), provide: EmailService, useFactory: () => ({ sendEmail: jest.fn() }),
@ -344,4 +348,46 @@ describe('AbuseReportNotificationService', () => {
expect(recipients).toEqual([recipient3]); expect(recipients).toEqual([recipient3]);
}); });
}); });
describe('notifySystemWebhook', () => {
test('非アクティブな通報通知はWebhook送信から除外される', async () => {
const recipient1 = await createRecipient({
method: 'webhook',
systemWebhookId: systemWebhook1.id,
isActive: true,
});
const recipient2 = await createRecipient({
method: 'webhook',
systemWebhookId: systemWebhook2.id,
isActive: false,
});
const reports: MiAbuseUserReport[] = [
{
id: idService.gen(),
targetUserId: alice.id,
targetUser: alice,
reporterId: bob.id,
reporter: bob,
assigneeId: null,
assignee: null,
resolved: false,
forwarded: false,
comment: 'test',
moderationNote: '',
resolvedAs: null,
targetUserHost: null,
reporterHost: null,
},
];
await service.notifySystemWebhook(reports, 'abuseReport');
// 実際に除外されるかはSystemWebhookService側で確認する.
// ここでは非アクティブな通報通知を除外設定できているかを確認する
expect(webhookService.enqueueSystemWebhook).toHaveBeenCalledTimes(1);
expect(webhookService.enqueueSystemWebhook.mock.calls[0][0]).toBe('abuseReport');
expect(webhookService.enqueueSystemWebhook.mock.calls[0][2]).toEqual({ excludes: [systemWebhook2.id] });
});
});
}); });

View file

@ -366,6 +366,22 @@ describe('SystemWebhookService', () => {
expect(queueService.systemWebhookDeliver).toHaveBeenCalledTimes(1); expect(queueService.systemWebhookDeliver).toHaveBeenCalledTimes(1);
expect(queueService.systemWebhookDeliver.mock.calls[0][0] as MiSystemWebhook).toEqual(webhook1); expect(queueService.systemWebhookDeliver.mock.calls[0][0] as MiSystemWebhook).toEqual(webhook1);
}); });
test('除外指定した場合は送信されない', async () => {
const webhook1 = await createWebhook({
isActive: true,
on: ['abuseReport'],
});
const webhook2 = await createWebhook({
isActive: true,
on: ['abuseReport'],
});
await service.enqueueSystemWebhook('abuseReport', { foo: 'bar' } as any, { excludes: [webhook2.id] });
expect(queueService.systemWebhookDeliver).toHaveBeenCalledTimes(1);
expect(queueService.systemWebhookDeliver.mock.calls[0][0] as MiSystemWebhook).toEqual(webhook1);
});
}); });
describe('fetchActiveSystemWebhooks', () => { describe('fetchActiveSystemWebhooks', () => {