mirror of
https://activitypub.software/TransFem-org/Sharkey.git
synced 2024-12-28 21:28:19 +01:00
refactor(backend): SystemWebhookで送信されるペイロードの型を追加 (#14980)
This commit is contained in:
parent
c271534aba
commit
7b9c884a5d
5 changed files with 63 additions and 29 deletions
|
@ -154,9 +154,9 @@ export class AbuseReportNotificationService implements OnApplicationShutdown {
|
||||||
const convertedReports = abuseReports.map(it => {
|
const convertedReports = abuseReports.map(it => {
|
||||||
return {
|
return {
|
||||||
...it,
|
...it,
|
||||||
reporter: usersMap.get(it.reporterId),
|
reporter: usersMap.get(it.reporterId) ?? null,
|
||||||
targetUser: usersMap.get(it.targetUserId),
|
targetUser: usersMap.get(it.targetUserId) ?? null,
|
||||||
assignee: it.assigneeId ? usersMap.get(it.assigneeId) : null,
|
assignee: it.assigneeId ? (usersMap.get(it.assigneeId) ?? null) : null,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -7,13 +7,15 @@ import { randomUUID } from 'node:crypto';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import type { IActivity } from '@/core/activitypub/type.js';
|
import type { IActivity } from '@/core/activitypub/type.js';
|
||||||
import type { MiDriveFile } from '@/models/DriveFile.js';
|
import type { MiDriveFile } from '@/models/DriveFile.js';
|
||||||
import type { MiWebhook, WebhookEventTypes, webhookEventTypes } from '@/models/Webhook.js';
|
import type { MiWebhook, WebhookEventTypes } from '@/models/Webhook.js';
|
||||||
import type { MiSystemWebhook, SystemWebhookEventType } from '@/models/SystemWebhook.js';
|
import type { MiSystemWebhook, SystemWebhookEventType } from '@/models/SystemWebhook.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import type { Antenna } from '@/server/api/endpoints/i/import-antennas.js';
|
import type { Antenna } from '@/server/api/endpoints/i/import-antennas.js';
|
||||||
import { ApRequestCreator } from '@/core/activitypub/ApRequestService.js';
|
import { ApRequestCreator } from '@/core/activitypub/ApRequestService.js';
|
||||||
|
import { type SystemWebhookPayload } from '@/core/SystemWebhookService.js';
|
||||||
|
import { type UserWebhookPayload } from './UserWebhookService.js';
|
||||||
import type {
|
import type {
|
||||||
DbJobData,
|
DbJobData,
|
||||||
DeliverJobData,
|
DeliverJobData,
|
||||||
|
@ -30,12 +32,11 @@ import type {
|
||||||
ObjectStorageQueue,
|
ObjectStorageQueue,
|
||||||
RelationshipQueue,
|
RelationshipQueue,
|
||||||
SystemQueue,
|
SystemQueue,
|
||||||
UserWebhookDeliverQueue,
|
|
||||||
SystemWebhookDeliverQueue,
|
SystemWebhookDeliverQueue,
|
||||||
|
UserWebhookDeliverQueue,
|
||||||
} from './QueueModule.js';
|
} from './QueueModule.js';
|
||||||
import type httpSignature from '@peertube/http-signature';
|
import type httpSignature from '@peertube/http-signature';
|
||||||
import type * as Bull from 'bullmq';
|
import type * as Bull from 'bullmq';
|
||||||
import { type UserWebhookPayload } from './UserWebhookService.js';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class QueueService {
|
export class QueueService {
|
||||||
|
@ -501,10 +502,10 @@ export class QueueService {
|
||||||
* @see SystemWebhookDeliverProcessorService
|
* @see SystemWebhookDeliverProcessorService
|
||||||
*/
|
*/
|
||||||
@bindThis
|
@bindThis
|
||||||
public systemWebhookDeliver(
|
public systemWebhookDeliver<T extends SystemWebhookEventType>(
|
||||||
webhook: MiSystemWebhook,
|
webhook: MiSystemWebhook,
|
||||||
type: SystemWebhookEventType,
|
type: T,
|
||||||
content: unknown,
|
content: SystemWebhookPayload<T>,
|
||||||
opts?: { attempts?: number },
|
opts?: { attempts?: number },
|
||||||
) {
|
) {
|
||||||
const data: SystemWebhookDeliverJobData = {
|
const data: SystemWebhookDeliverJobData = {
|
||||||
|
|
|
@ -15,8 +15,39 @@ import { QueueService } from '@/core/QueueService.js';
|
||||||
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
||||||
import { LoggerService } from '@/core/LoggerService.js';
|
import { LoggerService } from '@/core/LoggerService.js';
|
||||||
import Logger from '@/logger.js';
|
import Logger from '@/logger.js';
|
||||||
|
import { Packed } from '@/misc/json-schema.js';
|
||||||
|
import { AbuseReportResolveType } from '@/models/AbuseUserReport.js';
|
||||||
|
import { ModeratorInactivityRemainingTime } from '@/queue/processors/CheckModeratorsActivityProcessorService.js';
|
||||||
import type { OnApplicationShutdown } from '@nestjs/common';
|
import type { OnApplicationShutdown } from '@nestjs/common';
|
||||||
|
|
||||||
|
export type AbuseReportPayload = {
|
||||||
|
id: string;
|
||||||
|
targetUserId: string;
|
||||||
|
targetUser: Packed<'UserLite'> | null;
|
||||||
|
targetUserHost: string | null;
|
||||||
|
reporterId: string;
|
||||||
|
reporter: Packed<'UserLite'> | null;
|
||||||
|
reporterHost: string | null;
|
||||||
|
assigneeId: string | null;
|
||||||
|
assignee: Packed<'UserLite'> | null;
|
||||||
|
resolved: boolean;
|
||||||
|
forwarded: boolean;
|
||||||
|
comment: string;
|
||||||
|
moderationNote: string;
|
||||||
|
resolvedAs: AbuseReportResolveType | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type InactiveModeratorsWarningPayload = {
|
||||||
|
remainingTime: ModeratorInactivityRemainingTime;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SystemWebhookPayload<T extends SystemWebhookEventType> =
|
||||||
|
T extends 'abuseReport' | 'abuseReportResolved' ? AbuseReportPayload :
|
||||||
|
T extends 'userCreated' ? Packed<'UserLite'> :
|
||||||
|
T extends 'inactiveModeratorsWarning' ? InactiveModeratorsWarningPayload :
|
||||||
|
T extends 'inactiveModeratorsInvitationOnlyChanged' ? Record<string, never> :
|
||||||
|
never;
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SystemWebhookService implements OnApplicationShutdown {
|
export class SystemWebhookService implements OnApplicationShutdown {
|
||||||
private logger: Logger;
|
private logger: Logger;
|
||||||
|
@ -168,7 +199,7 @@ export class SystemWebhookService implements OnApplicationShutdown {
|
||||||
public async enqueueSystemWebhook<T extends SystemWebhookEventType>(
|
public async enqueueSystemWebhook<T extends SystemWebhookEventType>(
|
||||||
webhook: MiSystemWebhook | MiSystemWebhook['id'],
|
webhook: MiSystemWebhook | MiSystemWebhook['id'],
|
||||||
type: T,
|
type: T,
|
||||||
content: unknown,
|
content: SystemWebhookPayload<T>,
|
||||||
) {
|
) {
|
||||||
const webhookEntity = typeof webhook === 'string'
|
const webhookEntity = typeof webhook === 'string'
|
||||||
? (await this.fetchActiveSystemWebhooks()).find(a => a.id === webhook)
|
? (await this.fetchActiveSystemWebhooks()).find(a => a.id === webhook)
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { Injectable } from '@nestjs/common';
|
||||||
import { MiAbuseUserReport, MiNote, MiUser, MiWebhook } from '@/models/_.js';
|
import { MiAbuseUserReport, MiNote, MiUser, MiWebhook } from '@/models/_.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { MiSystemWebhook, type SystemWebhookEventType } from '@/models/SystemWebhook.js';
|
import { MiSystemWebhook, type SystemWebhookEventType } from '@/models/SystemWebhook.js';
|
||||||
import { SystemWebhookService } from '@/core/SystemWebhookService.js';
|
import { AbuseReportPayload, SystemWebhookPayload, SystemWebhookService } from '@/core/SystemWebhookService.js';
|
||||||
import { Packed } from '@/misc/json-schema.js';
|
import { Packed } from '@/misc/json-schema.js';
|
||||||
import { type WebhookEventTypes } from '@/models/Webhook.js';
|
import { type WebhookEventTypes } from '@/models/Webhook.js';
|
||||||
import { type UserWebhookPayload, UserWebhookService } from '@/core/UserWebhookService.js';
|
import { type UserWebhookPayload, UserWebhookService } from '@/core/UserWebhookService.js';
|
||||||
|
@ -16,13 +16,7 @@ import { ModeratorInactivityRemainingTime } from '@/queue/processors/CheckModera
|
||||||
|
|
||||||
const oneDayMillis = 24 * 60 * 60 * 1000;
|
const oneDayMillis = 24 * 60 * 60 * 1000;
|
||||||
|
|
||||||
type AbuseUserReportDto = Omit<MiAbuseUserReport, 'targetUser' | 'reporter' | 'assignee'> & {
|
function generateAbuseReport(override?: Partial<MiAbuseUserReport>): AbuseReportPayload {
|
||||||
targetUser: Packed<'UserLite'> | null,
|
|
||||||
reporter: Packed<'UserLite'> | null,
|
|
||||||
assignee: Packed<'UserLite'> | null,
|
|
||||||
};
|
|
||||||
|
|
||||||
function generateAbuseReport(override?: Partial<MiAbuseUserReport>): AbuseUserReportDto {
|
|
||||||
const result: MiAbuseUserReport = {
|
const result: MiAbuseUserReport = {
|
||||||
id: 'dummy-abuse-report1',
|
id: 'dummy-abuse-report1',
|
||||||
targetUserId: 'dummy-target-user',
|
targetUserId: 'dummy-target-user',
|
||||||
|
@ -389,7 +383,8 @@ export class WebhookTestService {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// まだ実装されていない (#9485)
|
// まだ実装されていない (#9485)
|
||||||
case 'reaction': return;
|
case 'reaction':
|
||||||
|
return;
|
||||||
default: {
|
default: {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const _exhaustiveAssertion: never = params.type;
|
const _exhaustiveAssertion: never = params.type;
|
||||||
|
@ -407,10 +402,10 @@ export class WebhookTestService {
|
||||||
* - 送信対象イベント(on)に関する設定
|
* - 送信対象イベント(on)に関する設定
|
||||||
*/
|
*/
|
||||||
@bindThis
|
@bindThis
|
||||||
public async testSystemWebhook(
|
public async testSystemWebhook<T extends SystemWebhookEventType>(
|
||||||
params: {
|
params: {
|
||||||
webhookId: MiSystemWebhook['id'],
|
webhookId: MiSystemWebhook['id'],
|
||||||
type: SystemWebhookEventType,
|
type: T,
|
||||||
override?: Partial<Omit<MiSystemWebhook, 'id'>>,
|
override?: Partial<Omit<MiSystemWebhook, 'id'>>,
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
|
@ -420,7 +415,7 @@ export class WebhookTestService {
|
||||||
}
|
}
|
||||||
|
|
||||||
const webhook = webhooks[0];
|
const webhook = webhooks[0];
|
||||||
const send = (contents: unknown) => {
|
const send = <U extends SystemWebhookEventType>(type: U, contents: SystemWebhookPayload<U>) => {
|
||||||
const merged = {
|
const merged = {
|
||||||
...webhook,
|
...webhook,
|
||||||
...params.override,
|
...params.override,
|
||||||
|
@ -428,12 +423,12 @@ export class WebhookTestService {
|
||||||
|
|
||||||
// テスト目的なのでSystemWebhookServiceの機能を経由せず直接キューに追加する(チェック処理などをスキップする意図).
|
// テスト目的なのでSystemWebhookServiceの機能を経由せず直接キューに追加する(チェック処理などをスキップする意図).
|
||||||
// また、Jobの試行回数も1回だけ.
|
// また、Jobの試行回数も1回だけ.
|
||||||
this.queueService.systemWebhookDeliver(merged, params.type, contents, { attempts: 1 });
|
this.queueService.systemWebhookDeliver(merged, type, contents, { attempts: 1 });
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (params.type) {
|
switch (params.type) {
|
||||||
case 'abuseReport': {
|
case 'abuseReport': {
|
||||||
send(generateAbuseReport({
|
send('abuseReport', generateAbuseReport({
|
||||||
targetUserId: dummyUser1.id,
|
targetUserId: dummyUser1.id,
|
||||||
targetUser: dummyUser1,
|
targetUser: dummyUser1,
|
||||||
reporterId: dummyUser2.id,
|
reporterId: dummyUser2.id,
|
||||||
|
@ -442,7 +437,7 @@ export class WebhookTestService {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'abuseReportResolved': {
|
case 'abuseReportResolved': {
|
||||||
send(generateAbuseReport({
|
send('abuseReportResolved', generateAbuseReport({
|
||||||
targetUserId: dummyUser1.id,
|
targetUserId: dummyUser1.id,
|
||||||
targetUser: dummyUser1,
|
targetUser: dummyUser1,
|
||||||
reporterId: dummyUser2.id,
|
reporterId: dummyUser2.id,
|
||||||
|
@ -454,7 +449,7 @@ export class WebhookTestService {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'userCreated': {
|
case 'userCreated': {
|
||||||
send(toPackedUserLite(dummyUser1));
|
send('userCreated', toPackedUserLite(dummyUser1));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'inactiveModeratorsWarning': {
|
case 'inactiveModeratorsWarning': {
|
||||||
|
@ -464,15 +459,20 @@ export class WebhookTestService {
|
||||||
asHours: 24,
|
asHours: 24,
|
||||||
};
|
};
|
||||||
|
|
||||||
send({
|
send('inactiveModeratorsWarning', {
|
||||||
remainingTime: dummyTime,
|
remainingTime: dummyTime,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'inactiveModeratorsInvitationOnlyChanged': {
|
case 'inactiveModeratorsInvitationOnlyChanged': {
|
||||||
send({});
|
send('inactiveModeratorsInvitationOnlyChanged', {});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
default: {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
const _exhaustiveAssertion: never = params.type;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@ 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 type AbuseReportResolveType = 'accept' | 'reject';
|
||||||
|
|
||||||
@Entity('abuse_user_report')
|
@Entity('abuse_user_report')
|
||||||
export class MiAbuseUserReport {
|
export class MiAbuseUserReport {
|
||||||
@PrimaryColumn(id())
|
@PrimaryColumn(id())
|
||||||
|
@ -76,7 +78,7 @@ export class MiAbuseUserReport {
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 128, nullable: true,
|
length: 128, nullable: true,
|
||||||
})
|
})
|
||||||
public resolvedAs: 'accept' | 'reject' | null;
|
public resolvedAs: AbuseReportResolveType | null;
|
||||||
|
|
||||||
//#region Denormalized fields
|
//#region Denormalized fields
|
||||||
@Index()
|
@Index()
|
||||||
|
|
Loading…
Reference in a new issue