improve moderation log

This commit is contained in:
syuilo 2023-09-24 10:46:09 +09:00
parent 2ad3b1fd74
commit ed983a5baf
9 changed files with 177 additions and 14 deletions

4
locales/index.d.ts vendored
View File

@ -2262,6 +2262,10 @@ export interface Locale {
"deleteNote": string; "deleteNote": string;
"createGlobalAnnouncement": string; "createGlobalAnnouncement": string;
"createUserAnnouncement": string; "createUserAnnouncement": string;
"updateGlobalAnnouncement": string;
"updateUserAnnouncement": string;
"deleteGlobalAnnouncement": string;
"deleteUserAnnouncement": string;
"resetPassword": string; "resetPassword": string;
"suspendRemoteInstance": string; "suspendRemoteInstance": string;
"unsuspendRemoteInstance": string; "unsuspendRemoteInstance": string;

View File

@ -2175,6 +2175,10 @@ _moderationLogTypes:
deleteNote: "ノートを削除" deleteNote: "ノートを削除"
createGlobalAnnouncement: "全体のお知らせを作成" createGlobalAnnouncement: "全体のお知らせを作成"
createUserAnnouncement: "ユーザーへお知らせを作成" createUserAnnouncement: "ユーザーへお知らせを作成"
updateGlobalAnnouncement: "全体のお知らせを更新"
updateUserAnnouncement: "ユーザーのお知らせを更新"
deleteGlobalAnnouncement: "全体のお知らせを削除"
deleteUserAnnouncement: "ユーザーのお知らせを削除"
resetPassword: "パスワードをリセット" resetPassword: "パスワードをリセット"
suspendRemoteInstance: "リモートサーバーを停止" suspendRemoteInstance: "リモートサーバーを停止"
unsuspendRemoteInstance: "リモートサーバーを再開" unsuspendRemoteInstance: "リモートサーバーを再開"

View File

@ -60,7 +60,7 @@ export class AnnouncementService {
} }
@bindThis @bindThis
public async create(values: Partial<MiAnnouncement>, moderator: MiUser): Promise<{ raw: MiAnnouncement; packed: Packed<'Announcement'> }> { public async create(values: Partial<MiAnnouncement>, moderator?: MiUser): Promise<{ raw: MiAnnouncement; packed: Packed<'Announcement'> }> {
const announcement = await this.announcementsRepository.insert({ const announcement = await this.announcementsRepository.insert({
id: this.idService.genId(), id: this.idService.genId(),
createdAt: new Date(), createdAt: new Date(),
@ -82,20 +82,24 @@ export class AnnouncementService {
announcement: packed, announcement: packed,
}); });
this.moderationLogService.log(moderator, 'createUserAnnouncement', { if (moderator) {
announcementId: announcement.id, this.moderationLogService.log(moderator, 'createUserAnnouncement', {
announcement: announcement, announcementId: announcement.id,
userId: values.userId, announcement: announcement,
}); userId: values.userId,
});
}
} else { } else {
this.globalEventService.publishBroadcastStream('announcementCreated', { this.globalEventService.publishBroadcastStream('announcementCreated', {
announcement: packed, announcement: packed,
}); });
this.moderationLogService.log(moderator, 'createGlobalAnnouncement', { if (moderator) {
announcementId: announcement.id, this.moderationLogService.log(moderator, 'createGlobalAnnouncement', {
announcement: announcement, announcementId: announcement.id,
}); announcement: announcement,
});
}
} }
return { return {
@ -104,6 +108,59 @@ export class AnnouncementService {
}; };
} }
@bindThis
public async update(announcement: MiAnnouncement, values: Partial<MiAnnouncement>, moderator?: MiUser): Promise<void> {
await this.announcementsRepository.update(announcement.id, {
updatedAt: new Date(),
title: values.title,
text: values.text,
/* eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- 空の文字列の場合、nullを渡すようにするため */
imageUrl: values.imageUrl || null,
display: values.display,
icon: values.icon,
forExistingUsers: values.forExistingUsers,
needConfirmationToRead: values.needConfirmationToRead,
isActive: values.isActive,
});
const after = await this.announcementsRepository.findOneByOrFail({ id: announcement.id });
if (moderator) {
if (announcement.userId) {
this.moderationLogService.log(moderator, 'updateUserAnnouncement', {
announcementId: announcement.id,
before: announcement,
after: after,
});
} else {
this.moderationLogService.log(moderator, 'updateGlobalAnnouncement', {
announcementId: announcement.id,
before: announcement,
after: after,
});
}
}
}
@bindThis
public async delete(announcement: MiAnnouncement, moderator?: MiUser): Promise<void> {
await this.announcementsRepository.delete(announcement.id);
if (moderator) {
if (announcement.userId) {
this.moderationLogService.log(moderator, 'deleteUserAnnouncement', {
announcementId: announcement.id,
announcement: announcement,
});
} else {
this.moderationLogService.log(moderator, 'deleteGlobalAnnouncement', {
announcementId: announcement.id,
announcement: announcement,
});
}
}
}
@bindThis @bindThis
public async read(user: MiUser, announcementId: MiAnnouncement['id']): Promise<void> { public async read(user: MiUser, announcementId: MiAnnouncement['id']): Promise<void> {
try { try {

View File

@ -7,6 +7,7 @@ import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js'; import { Endpoint } from '@/server/api/endpoint-base.js';
import type { AnnouncementsRepository } from '@/models/_.js'; import type { AnnouncementsRepository } from '@/models/_.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { AnnouncementService } from '@/core/AnnouncementService.js';
import { ApiError } from '../../../error.js'; import { ApiError } from '../../../error.js';
export const meta = { export const meta = {
@ -37,13 +38,15 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
constructor( constructor(
@Inject(DI.announcementsRepository) @Inject(DI.announcementsRepository)
private announcementsRepository: AnnouncementsRepository, private announcementsRepository: AnnouncementsRepository,
private announcementService: AnnouncementService,
) { ) {
super(meta, paramDef, async (ps, me) => { super(meta, paramDef, async (ps, me) => {
const announcement = await this.announcementsRepository.findOneBy({ id: ps.id }); const announcement = await this.announcementsRepository.findOneBy({ id: ps.id });
if (announcement == null) throw new ApiError(meta.errors.noSuchAnnouncement); if (announcement == null) throw new ApiError(meta.errors.noSuchAnnouncement);
await this.announcementsRepository.delete(announcement.id); await this.announcementService.delete(announcement, me);
}); });
} }
} }

View File

@ -7,6 +7,7 @@ import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js'; import { Endpoint } from '@/server/api/endpoint-base.js';
import type { AnnouncementsRepository } from '@/models/_.js'; import type { AnnouncementsRepository } from '@/models/_.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { AnnouncementService } from '@/core/AnnouncementService.js';
import { ApiError } from '../../../error.js'; import { ApiError } from '../../../error.js';
export const meta = { export const meta = {
@ -45,13 +46,15 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
constructor( constructor(
@Inject(DI.announcementsRepository) @Inject(DI.announcementsRepository)
private announcementsRepository: AnnouncementsRepository, private announcementsRepository: AnnouncementsRepository,
private announcementService: AnnouncementService,
) { ) {
super(meta, paramDef, async (ps, me) => { super(meta, paramDef, async (ps, me) => {
const announcement = await this.announcementsRepository.findOneBy({ id: ps.id }); const announcement = await this.announcementsRepository.findOneBy({ id: ps.id });
if (announcement == null) throw new ApiError(meta.errors.noSuchAnnouncement); if (announcement == null) throw new ApiError(meta.errors.noSuchAnnouncement);
await this.announcementsRepository.update(announcement.id, { await this.announcementService.update(announcement, {
updatedAt: new Date(), updatedAt: new Date(),
title: ps.title, title: ps.title,
text: ps.text, text: ps.text,
@ -62,7 +65,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
forExistingUsers: ps.forExistingUsers, forExistingUsers: ps.forExistingUsers,
needConfirmationToRead: ps.needConfirmationToRead, needConfirmationToRead: ps.needConfirmationToRead,
isActive: ps.isActive, isActive: ps.isActive,
}); }, me);
}); });
} }
} }

View File

@ -43,6 +43,10 @@ export const moderationLogTypes = [
'deleteNote', 'deleteNote',
'createGlobalAnnouncement', 'createGlobalAnnouncement',
'createUserAnnouncement', 'createUserAnnouncement',
'updateGlobalAnnouncement',
'updateUserAnnouncement',
'deleteGlobalAnnouncement',
'deleteUserAnnouncement',
'resetPassword', 'resetPassword',
'suspendRemoteInstance', 'suspendRemoteInstance',
'unsuspendRemoteInstance', 'unsuspendRemoteInstance',
@ -107,6 +111,24 @@ export type ModerationLogPayloads = {
announcement: any; announcement: any;
userId: string; userId: string;
}; };
updateGlobalAnnouncement: {
announcementId: string;
before: any;
after: any;
};
updateUserAnnouncement: {
announcementId: string;
before: any;
after: any;
};
deleteGlobalAnnouncement: {
announcementId: string;
announcement: any;
};
deleteUserAnnouncement: {
announcementId: string;
announcement: any;
};
resetPassword: { resetPassword: {
targetId: string; targetId: string;
}; };

View File

@ -2556,6 +2556,30 @@ type ModerationLog = {
} | { } | {
type: 'promoteQueue'; type: 'promoteQueue';
info: ModerationLogPayloads['promoteQueue']; info: ModerationLogPayloads['promoteQueue'];
} | {
type: 'deleteDriveFile';
info: ModerationLogPayloads['deleteDriveFile'];
} | {
type: 'deleteNote';
info: ModerationLogPayloads['deleteNote'];
} | {
type: 'createGlobalAnnouncement';
info: ModerationLogPayloads['createGlobalAnnouncement'];
} | {
type: 'createUserAnnouncement';
info: ModerationLogPayloads['createUserAnnouncement'];
} | {
type: 'updateGlobalAnnouncement';
info: ModerationLogPayloads['updateGlobalAnnouncement'];
} | {
type: 'updateUserAnnouncement';
info: ModerationLogPayloads['updateUserAnnouncement'];
} | {
type: 'deleteGlobalAnnouncement';
info: ModerationLogPayloads['deleteGlobalAnnouncement'];
} | {
type: 'deleteUserAnnouncement';
info: ModerationLogPayloads['deleteUserAnnouncement'];
} | { } | {
type: 'resetPassword'; type: 'resetPassword';
info: ModerationLogPayloads['resetPassword']; info: ModerationLogPayloads['resetPassword'];
@ -2568,7 +2592,7 @@ type ModerationLog = {
}); });
// @public (undocumented) // @public (undocumented)
export const moderationLogTypes: readonly ["updateServerSettings", "suspend", "unsuspend", "updateUserNote", "addCustomEmoji", "assignRole", "unassignRole", "updateRole", "deleteRole", "clearQueue", "promoteQueue", "deleteDriveFile", "deleteNote", "createGlobalAnnouncement", "createUserAnnouncement", "resetPassword", "suspendRemoteInstance", "unsuspendRemoteInstance"]; export const moderationLogTypes: readonly ["updateServerSettings", "suspend", "unsuspend", "updateUserNote", "addCustomEmoji", "assignRole", "unassignRole", "updateRole", "deleteRole", "clearQueue", "promoteQueue", "deleteDriveFile", "deleteNote", "createGlobalAnnouncement", "createUserAnnouncement", "updateGlobalAnnouncement", "updateUserAnnouncement", "deleteGlobalAnnouncement", "deleteUserAnnouncement", "resetPassword", "suspendRemoteInstance", "unsuspendRemoteInstance"];
// @public (undocumented) // @public (undocumented)
export const mutedNoteReasons: readonly ["word", "manual", "spam", "other"]; export const mutedNoteReasons: readonly ["word", "manual", "spam", "other"];

View File

@ -61,6 +61,10 @@ export const moderationLogTypes = [
'deleteNote', 'deleteNote',
'createGlobalAnnouncement', 'createGlobalAnnouncement',
'createUserAnnouncement', 'createUserAnnouncement',
'updateGlobalAnnouncement',
'updateUserAnnouncement',
'deleteGlobalAnnouncement',
'deleteUserAnnouncement',
'resetPassword', 'resetPassword',
'suspendRemoteInstance', 'suspendRemoteInstance',
'unsuspendRemoteInstance', 'unsuspendRemoteInstance',
@ -125,6 +129,24 @@ export type ModerationLogPayloads = {
announcement: any; announcement: any;
userId: string; userId: string;
}; };
updateGlobalAnnouncement: {
announcementId: string;
before: any;
after: any;
};
updateUserAnnouncement: {
announcementId: string;
before: any;
after: any;
};
deleteGlobalAnnouncement: {
announcementId: string;
announcement: any;
};
deleteUserAnnouncement: {
announcementId: string;
announcement: any;
};
resetPassword: { resetPassword: {
targetId: string; targetId: string;
}; };

View File

@ -607,6 +607,30 @@ export type ModerationLog = {
} | { } | {
type: 'promoteQueue'; type: 'promoteQueue';
info: ModerationLogPayloads['promoteQueue']; info: ModerationLogPayloads['promoteQueue'];
} | {
type: 'deleteDriveFile';
info: ModerationLogPayloads['deleteDriveFile'];
} | {
type: 'deleteNote';
info: ModerationLogPayloads['deleteNote'];
} | {
type: 'createGlobalAnnouncement';
info: ModerationLogPayloads['createGlobalAnnouncement'];
} | {
type: 'createUserAnnouncement';
info: ModerationLogPayloads['createUserAnnouncement'];
} | {
type: 'updateGlobalAnnouncement';
info: ModerationLogPayloads['updateGlobalAnnouncement'];
} | {
type: 'updateUserAnnouncement';
info: ModerationLogPayloads['updateUserAnnouncement'];
} | {
type: 'deleteGlobalAnnouncement';
info: ModerationLogPayloads['deleteGlobalAnnouncement'];
} | {
type: 'deleteUserAnnouncement';
info: ModerationLogPayloads['deleteUserAnnouncement'];
} | { } | {
type: 'resetPassword'; type: 'resetPassword';
info: ModerationLogPayloads['resetPassword']; info: ModerationLogPayloads['resetPassword'];