feat(backend): 通報および通報解決時に送出されるSystemWebhookにユーザ情報を含めるようにする (#14698)
* feat(backend): 通報および通報解決時に送出されるSystemWebhookにユーザ情報を含めるようにする * テスト送信もペイロード形式を合わせる * add spaces * fix test
This commit is contained in:
parent
ae3c155490
commit
88698462a9
4 changed files with 46 additions and 6 deletions
|
@ -21,7 +21,7 @@
|
||||||
### Server
|
### Server
|
||||||
- Enhance: セキュリティ向上のため、ログイン時にメール通知を行うように
|
- Enhance: セキュリティ向上のため、ログイン時にメール通知を行うように
|
||||||
- Enhance: 自分とモデレーター以外のユーザーから二要素認証関連のデータが取得できないように
|
- Enhance: 自分とモデレーター以外のユーザーから二要素認証関連のデータが取得できないように
|
||||||
|
- Enhance: 通報および通報解決時に送出されるSystemWebhookにユーザ情報を含めるように ( #14697 )
|
||||||
|
|
||||||
## 2024.9.0
|
## 2024.9.0
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ import { RoleService } from '@/core/RoleService.js';
|
||||||
import { RecipientMethod } from '@/models/AbuseReportNotificationRecipient.js';
|
import { RecipientMethod } from '@/models/AbuseReportNotificationRecipient.js';
|
||||||
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
||||||
import { SystemWebhookService } from '@/core/SystemWebhookService.js';
|
import { SystemWebhookService } from '@/core/SystemWebhookService.js';
|
||||||
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import { IdService } from './IdService.js';
|
import { IdService } from './IdService.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -42,6 +43,7 @@ export class AbuseReportNotificationService implements OnApplicationShutdown {
|
||||||
private emailService: EmailService,
|
private emailService: EmailService,
|
||||||
private moderationLogService: ModerationLogService,
|
private moderationLogService: ModerationLogService,
|
||||||
private globalEventService: GlobalEventService,
|
private globalEventService: GlobalEventService,
|
||||||
|
private userEntityService: UserEntityService,
|
||||||
) {
|
) {
|
||||||
this.redisForSub.on('message', this.onMessage);
|
this.redisForSub.on('message', this.onMessage);
|
||||||
}
|
}
|
||||||
|
@ -135,6 +137,26 @@ export class AbuseReportNotificationService implements OnApplicationShutdown {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const usersMap = await this.userEntityService.packMany(
|
||||||
|
[
|
||||||
|
...new Set([
|
||||||
|
...abuseReports.map(it => it.reporter ?? it.reporterId),
|
||||||
|
...abuseReports.map(it => it.targetUser ?? it.targetUserId),
|
||||||
|
...abuseReports.map(it => it.assignee ?? it.assigneeId),
|
||||||
|
].filter(x => x != null)),
|
||||||
|
],
|
||||||
|
null,
|
||||||
|
{ schema: 'UserLite' },
|
||||||
|
).then(it => new Map(it.map(it => [it.id, it])));
|
||||||
|
const convertedReports = abuseReports.map(it => {
|
||||||
|
return {
|
||||||
|
...it,
|
||||||
|
reporter: usersMap.get(it.reporterId),
|
||||||
|
targetUser: usersMap.get(it.targetUserId),
|
||||||
|
assignee: it.assigneeId ? usersMap.get(it.assigneeId) : null,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
const recipientWebhookIds = await this.fetchWebhookRecipients()
|
const recipientWebhookIds = await this.fetchWebhookRecipients()
|
||||||
.then(it => it
|
.then(it => it
|
||||||
.filter(it => it.isActive && it.systemWebhookId && it.method === 'webhook')
|
.filter(it => it.isActive && it.systemWebhookId && it.method === 'webhook')
|
||||||
|
@ -142,7 +164,7 @@ export class AbuseReportNotificationService implements OnApplicationShutdown {
|
||||||
.filter(x => x != null));
|
.filter(x => x != null));
|
||||||
for (const webhookId of recipientWebhookIds) {
|
for (const webhookId of recipientWebhookIds) {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
abuseReports.map(it => {
|
convertedReports.map(it => {
|
||||||
return this.systemWebhookService.enqueueSystemWebhook(
|
return this.systemWebhookService.enqueueSystemWebhook(
|
||||||
webhookId,
|
webhookId,
|
||||||
type,
|
type,
|
||||||
|
|
|
@ -15,8 +15,14 @@ import { QueueService } from '@/core/QueueService.js';
|
||||||
|
|
||||||
const oneDayMillis = 24 * 60 * 60 * 1000;
|
const oneDayMillis = 24 * 60 * 60 * 1000;
|
||||||
|
|
||||||
function generateAbuseReport(override?: Partial<MiAbuseUserReport>): MiAbuseUserReport {
|
type AbuseUserReportDto = Omit<MiAbuseUserReport, 'targetUser' | 'reporter' | 'assignee'> & {
|
||||||
return {
|
targetUser: Packed<'UserLite'> | null,
|
||||||
|
reporter: Packed<'UserLite'> | null,
|
||||||
|
assignee: Packed<'UserLite'> | null,
|
||||||
|
};
|
||||||
|
|
||||||
|
function generateAbuseReport(override?: Partial<MiAbuseUserReport>): AbuseUserReportDto {
|
||||||
|
const result: MiAbuseUserReport = {
|
||||||
id: 'dummy-abuse-report1',
|
id: 'dummy-abuse-report1',
|
||||||
targetUserId: 'dummy-target-user',
|
targetUserId: 'dummy-target-user',
|
||||||
targetUser: null,
|
targetUser: null,
|
||||||
|
@ -31,6 +37,13 @@ function generateAbuseReport(override?: Partial<MiAbuseUserReport>): MiAbuseUser
|
||||||
reporterHost: null,
|
reporterHost: null,
|
||||||
...override,
|
...override,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...result,
|
||||||
|
targetUser: result.targetUser ? toPackedUserLite(result.targetUser) : null,
|
||||||
|
reporter: result.reporter ? toPackedUserLite(result.reporter) : null,
|
||||||
|
assignee: result.assignee ? toPackedUserLite(result.assignee) : null,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateDummyUser(override?: Partial<MiUser>): MiUser {
|
function generateDummyUser(override?: Partial<MiUser>): MiUser {
|
||||||
|
@ -268,7 +281,8 @@ const dummyUser3 = generateDummyUser({
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class WebhookTestService {
|
export class WebhookTestService {
|
||||||
public static NoSuchWebhookError = class extends Error {};
|
public static NoSuchWebhookError = class extends Error {
|
||||||
|
};
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private userWebhookService: UserWebhookService,
|
private userWebhookService: UserWebhookService,
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
import { jest } from '@jest/globals';
|
import { jest } from '@jest/globals';
|
||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { randomString } from '../utils.js';
|
||||||
import { AbuseReportNotificationService } from '@/core/AbuseReportNotificationService.js';
|
import { AbuseReportNotificationService } from '@/core/AbuseReportNotificationService.js';
|
||||||
import {
|
import {
|
||||||
AbuseReportNotificationRecipientRepository,
|
AbuseReportNotificationRecipientRepository,
|
||||||
|
@ -25,7 +26,7 @@ import { ModerationLogService } from '@/core/ModerationLogService.js';
|
||||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||||
import { RecipientMethod } from '@/models/AbuseReportNotificationRecipient.js';
|
import { RecipientMethod } from '@/models/AbuseReportNotificationRecipient.js';
|
||||||
import { SystemWebhookService } from '@/core/SystemWebhookService.js';
|
import { SystemWebhookService } from '@/core/SystemWebhookService.js';
|
||||||
import { randomString } from '../utils.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
|
|
||||||
process.env.NODE_ENV = 'test';
|
process.env.NODE_ENV = 'test';
|
||||||
|
|
||||||
|
@ -110,6 +111,9 @@ describe('AbuseReportNotificationService', () => {
|
||||||
{
|
{
|
||||||
provide: SystemWebhookService, useFactory: () => ({ enqueueSystemWebhook: jest.fn() }),
|
provide: SystemWebhookService, useFactory: () => ({ enqueueSystemWebhook: jest.fn() }),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
provide: UserEntityService, useFactory: () => ({ pack: (v: any) => v }),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
provide: EmailService, useFactory: () => ({ sendEmail: jest.fn() }),
|
provide: EmailService, useFactory: () => ({ sendEmail: jest.fn() }),
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue