hippofish/packages/backend/src/core/AbuseReportService.ts
dakkar c4e0bea931 don't return early -- should fix #626
I have no clue why I wrote that code 😭
2024-08-19 18:19:38 +01:00

138 lines
4.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Inject, Injectable } from '@nestjs/common';
import { In } from 'typeorm';
import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js';
import type { AbuseUserReportsRepository, MiAbuseUserReport, MiUser, UsersRepository } from '@/models/_.js';
import { AbuseReportNotificationService } from '@/core/AbuseReportNotificationService.js';
import { QueueService } from '@/core/QueueService.js';
import { InstanceActorService } from '@/core/InstanceActorService.js';
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
import { ModerationLogService } from '@/core/ModerationLogService.js';
import { IdService } from './IdService.js';
@Injectable()
export class AbuseReportService {
constructor(
@Inject(DI.abuseUserReportsRepository)
private abuseUserReportsRepository: AbuseUserReportsRepository,
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
private idService: IdService,
private abuseReportNotificationService: AbuseReportNotificationService,
private queueService: QueueService,
private instanceActorService: InstanceActorService,
private apRendererService: ApRendererService,
private moderationLogService: ModerationLogService,
) {
}
/**
* ユーザからの通報をDBに記録し、その内容を下記の手段で管理者各位に通知する.
* - 管理者用Redisイベント
* - EMailモデレータ権限所有者ユーザmetaテーブルに設定されているメールアドレス
* - SystemWebhook
*
* @param params 通報内容. もし複数件の通報に対応した時のために、あらかじめ複数件を処理できる前提で考える
* @see AbuseReportNotificationService.notify
*/
@bindThis
public async report(params: {
targetUserId: MiAbuseUserReport['targetUserId'],
targetUserHost: MiAbuseUserReport['targetUserHost'],
reporterId: MiAbuseUserReport['reporterId'],
reporterHost: MiAbuseUserReport['reporterHost'],
comment: string,
}[]) {
const entities = params.map(param => {
return {
id: this.idService.gen(),
targetUserId: param.targetUserId,
targetUserHost: param.targetUserHost,
reporterId: param.reporterId,
reporterHost: param.reporterHost,
comment: param.comment,
};
});
const reports = Array.of<MiAbuseUserReport>();
for (const entity of entities) {
const report = await this.abuseUserReportsRepository.insertOne(entity);
reports.push(report);
}
return Promise.all([
this.abuseReportNotificationService.notifyAdminStream(reports),
this.abuseReportNotificationService.notifySystemWebhook(reports, 'abuseReport'),
this.abuseReportNotificationService.notifyMail(reports),
]);
}
/**
* 通報を解決し、その内容を下記の手段で管理者各位に通知する.
* - SystemWebhook
*
* @param params 通報内容. もし複数件の通報に対応した時のために、あらかじめ複数件を処理できる前提で考える
* @param operator 通報を処理したユーザ
* @see AbuseReportNotificationService.notify
*/
@bindThis
public async resolve(
params: {
reportId: string;
forward: boolean;
}[],
operator: MiUser,
) {
const paramsMap = new Map(params.map(it => [it.reportId, it]));
const reports = await this.abuseUserReportsRepository.findBy({
id: In(params.map(it => it.reportId)),
});
const targetUserMap = new Map();
for (const report of reports) {
const shouldForward = paramsMap.get(report.id)!.forward;
if (shouldForward && report.targetUserHost != null) {
targetUserMap.set(report.id, await this.usersRepository.findOneByOrFail({ id: report.targetUserId }));
} else {
targetUserMap.set(report.id, null);
}
}
for (const report of reports) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const ps = paramsMap.get(report.id)!;
await this.abuseUserReportsRepository.update(report.id, {
resolved: true,
assigneeId: operator.id,
forwarded: ps.forward && report.targetUserHost !== null,
});
const targetUser = targetUserMap.get(report.id)!;
if (targetUser != null) {
const actor = await this.instanceActorService.getInstanceActor();
// eslint-disable-next-line
const flag = this.apRendererService.renderFlag(actor, targetUser.uri!, report.comment);
const contextAssignedFlag = this.apRendererService.addContext(flag);
this.queueService.deliver(actor, contextAssignedFlag, targetUser.inbox, false);
}
this.moderationLogService
.log(operator, 'resolveAbuseReport', {
reportId: report.id,
report: report,
forwarded: ps.forward && report.targetUserHost !== null,
});
}
return this.abuseUserReportsRepository.findBy({ id: In(reports.map(it => it.id)) })
.then(reports => this.abuseReportNotificationService.notifySystemWebhook(reports, 'abuseReportResolved'));
}
}