wip
This commit is contained in:
parent
7352387045
commit
a4701edb41
|
|
@ -2171,3 +2171,7 @@ _moderationLogTypes:
|
||||||
addCustomEmoji: "カスタム絵文字追加"
|
addCustomEmoji: "カスタム絵文字追加"
|
||||||
updateServerSettings: "サーバー設定更新"
|
updateServerSettings: "サーバー設定更新"
|
||||||
updateUserNote: "モデレーションノート更新"
|
updateUserNote: "モデレーションノート更新"
|
||||||
|
deleteDriveFile: "ファイルを削除"
|
||||||
|
deleteNote: "ノートを削除"
|
||||||
|
createGlobalAnnouncement: "全体のお知らせを作成"
|
||||||
|
createUserAnnouncement: "ユーザーへお知らせを作成"
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import { bindThis } from '@/decorators.js';
|
||||||
import { Packed } from '@/misc/json-schema.js';
|
import { Packed } from '@/misc/json-schema.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||||
|
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AnnouncementService {
|
export class AnnouncementService {
|
||||||
|
|
@ -24,6 +25,7 @@ export class AnnouncementService {
|
||||||
|
|
||||||
private idService: IdService,
|
private idService: IdService,
|
||||||
private globalEventService: GlobalEventService,
|
private globalEventService: GlobalEventService,
|
||||||
|
private moderationLogService: ModerationLogService,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -58,7 +60,7 @@ export class AnnouncementService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async create(values: Partial<MiAnnouncement>): 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(),
|
||||||
|
|
@ -79,10 +81,21 @@ export class AnnouncementService {
|
||||||
this.globalEventService.publishMainStream(values.userId, 'announcementCreated', {
|
this.globalEventService.publishMainStream(values.userId, 'announcementCreated', {
|
||||||
announcement: packed,
|
announcement: packed,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.moderationLogService.log(moderator, 'createUserAnnouncement', {
|
||||||
|
announcementId: announcement.id,
|
||||||
|
announcement: announcement,
|
||||||
|
userId: values.userId,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
this.globalEventService.publishBroadcastStream('announcementCreated', {
|
this.globalEventService.publishBroadcastStream('announcementCreated', {
|
||||||
announcement: packed,
|
announcement: packed,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.moderationLogService.log(moderator, 'createGlobalAnnouncement', {
|
||||||
|
announcementId: announcement.id,
|
||||||
|
announcement: announcement,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
forExistingUsers: ps.forExistingUsers,
|
forExistingUsers: ps.forExistingUsers,
|
||||||
needConfirmationToRead: ps.needConfirmationToRead,
|
needConfirmationToRead: ps.needConfirmationToRead,
|
||||||
userId: ps.userId,
|
userId: ps.userId,
|
||||||
});
|
}, me);
|
||||||
|
|
||||||
return packed;
|
return packed;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,8 @@ export const moderationLogTypes = [
|
||||||
'promoteQueue',
|
'promoteQueue',
|
||||||
'deleteDriveFile',
|
'deleteDriveFile',
|
||||||
'deleteNote',
|
'deleteNote',
|
||||||
|
'createGlobalAnnouncement',
|
||||||
|
'createUserAnnouncement',
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export type ModerationLogPayloads = {
|
export type ModerationLogPayloads = {
|
||||||
|
|
@ -92,5 +94,14 @@ export type ModerationLogPayloads = {
|
||||||
noteId: string;
|
noteId: string;
|
||||||
noteUserId: string;
|
noteUserId: string;
|
||||||
note: any;
|
note: any;
|
||||||
}
|
};
|
||||||
|
createGlobalAnnouncement: {
|
||||||
|
announcementId: string;
|
||||||
|
announcement: any;
|
||||||
|
};
|
||||||
|
createUserAnnouncement: {
|
||||||
|
announcementId: string;
|
||||||
|
announcement: any;
|
||||||
|
userId: string;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import { genAidx } from '@/misc/id/aidx.js';
|
||||||
import { CacheService } from '@/core/CacheService.js';
|
import { CacheService } from '@/core/CacheService.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||||
|
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
||||||
import { secureRndstr } from '@/misc/secure-rndstr.js';
|
import { secureRndstr } from '@/misc/secure-rndstr.js';
|
||||||
import type { TestingModule } from '@nestjs/testing';
|
import type { TestingModule } from '@nestjs/testing';
|
||||||
import type { MockFunctionMetadata } from 'jest-mock';
|
import type { MockFunctionMetadata } from 'jest-mock';
|
||||||
|
|
@ -29,6 +30,7 @@ describe('AnnouncementService', () => {
|
||||||
let announcementsRepository: AnnouncementsRepository;
|
let announcementsRepository: AnnouncementsRepository;
|
||||||
let announcementReadsRepository: AnnouncementReadsRepository;
|
let announcementReadsRepository: AnnouncementReadsRepository;
|
||||||
let globalEventService: jest.Mocked<GlobalEventService>;
|
let globalEventService: jest.Mocked<GlobalEventService>;
|
||||||
|
let moderationLogService: jest.Mocked<ModerationLogService>;
|
||||||
|
|
||||||
function createUser(data: Partial<MiUser> = {}) {
|
function createUser(data: Partial<MiUser> = {}) {
|
||||||
const un = secureRndstr(16);
|
const un = secureRndstr(16);
|
||||||
|
|
@ -71,8 +73,11 @@ describe('AnnouncementService', () => {
|
||||||
publishMainStream: jest.fn(),
|
publishMainStream: jest.fn(),
|
||||||
publishBroadcastStream: jest.fn(),
|
publishBroadcastStream: jest.fn(),
|
||||||
};
|
};
|
||||||
}
|
} else if (token === ModerationLogService) {
|
||||||
if (typeof token === 'function') {
|
return {
|
||||||
|
log: jest.fn(),
|
||||||
|
};
|
||||||
|
} else if (typeof token === 'function') {
|
||||||
const mockMetadata = moduleMocker.getMetadata(token) as MockFunctionMetadata<any, any>;
|
const mockMetadata = moduleMocker.getMetadata(token) as MockFunctionMetadata<any, any>;
|
||||||
const Mock = moduleMocker.generateFromMetadata(mockMetadata);
|
const Mock = moduleMocker.generateFromMetadata(mockMetadata);
|
||||||
return new Mock();
|
return new Mock();
|
||||||
|
|
@ -87,6 +92,7 @@ describe('AnnouncementService', () => {
|
||||||
announcementsRepository = app.get<AnnouncementsRepository>(DI.announcementsRepository);
|
announcementsRepository = app.get<AnnouncementsRepository>(DI.announcementsRepository);
|
||||||
announcementReadsRepository = app.get<AnnouncementReadsRepository>(DI.announcementReadsRepository);
|
announcementReadsRepository = app.get<AnnouncementReadsRepository>(DI.announcementReadsRepository);
|
||||||
globalEventService = app.get<GlobalEventService>(GlobalEventService) as jest.Mocked<GlobalEventService>;
|
globalEventService = app.get<GlobalEventService>(GlobalEventService) as jest.Mocked<GlobalEventService>;
|
||||||
|
moderationLogService = app.get<ModerationLogService>(ModerationLogService) as jest.Mocked<ModerationLogService>;
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
|
|
@ -155,10 +161,11 @@ describe('AnnouncementService', () => {
|
||||||
|
|
||||||
describe('create', () => {
|
describe('create', () => {
|
||||||
test('通常', async () => {
|
test('通常', async () => {
|
||||||
|
const me = await createUser();
|
||||||
const result = await announcementService.create({
|
const result = await announcementService.create({
|
||||||
title: 'Title',
|
title: 'Title',
|
||||||
text: 'Text',
|
text: 'Text',
|
||||||
});
|
}, me);
|
||||||
|
|
||||||
expect(result.raw.title).toBe('Title');
|
expect(result.raw.title).toBe('Title');
|
||||||
expect(result.packed.title).toBe('Title');
|
expect(result.packed.title).toBe('Title');
|
||||||
|
|
@ -166,15 +173,17 @@ describe('AnnouncementService', () => {
|
||||||
expect(globalEventService.publishBroadcastStream).toHaveBeenCalled();
|
expect(globalEventService.publishBroadcastStream).toHaveBeenCalled();
|
||||||
expect(globalEventService.publishBroadcastStream.mock.lastCall![0]).toBe('announcementCreated');
|
expect(globalEventService.publishBroadcastStream.mock.lastCall![0]).toBe('announcementCreated');
|
||||||
expect((globalEventService.publishBroadcastStream.mock.lastCall![1] as any).announcement).toBe(result.packed);
|
expect((globalEventService.publishBroadcastStream.mock.lastCall![1] as any).announcement).toBe(result.packed);
|
||||||
|
expect(moderationLogService.log).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('ユーザー指定', async () => {
|
test('ユーザー指定', async () => {
|
||||||
|
const me = await createUser();
|
||||||
const user = await createUser();
|
const user = await createUser();
|
||||||
const result = await announcementService.create({
|
const result = await announcementService.create({
|
||||||
title: 'Title',
|
title: 'Title',
|
||||||
text: 'Text',
|
text: 'Text',
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
});
|
}, me);
|
||||||
|
|
||||||
expect(result.raw.title).toBe('Title');
|
expect(result.raw.title).toBe('Title');
|
||||||
expect(result.packed.title).toBe('Title');
|
expect(result.packed.title).toBe('Title');
|
||||||
|
|
@ -184,6 +193,7 @@ describe('AnnouncementService', () => {
|
||||||
expect(globalEventService.publishMainStream.mock.lastCall![0]).toBe(user.id);
|
expect(globalEventService.publishMainStream.mock.lastCall![0]).toBe(user.id);
|
||||||
expect(globalEventService.publishMainStream.mock.lastCall![1]).toBe('announcementCreated');
|
expect(globalEventService.publishMainStream.mock.lastCall![1]).toBe('announcementCreated');
|
||||||
expect((globalEventService.publishMainStream.mock.lastCall![2] as any).announcement).toBe(result.packed);
|
expect((globalEventService.publishMainStream.mock.lastCall![2] as any).announcement).toBe(result.packed);
|
||||||
|
expect(moderationLogService.log).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,8 @@ export const moderationLogTypes = [
|
||||||
'promoteQueue',
|
'promoteQueue',
|
||||||
'deleteDriveFile',
|
'deleteDriveFile',
|
||||||
'deleteNote',
|
'deleteNote',
|
||||||
|
'createGlobalAnnouncement',
|
||||||
|
'createUserAnnouncement',
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export type ModerationLogPayloads = {
|
export type ModerationLogPayloads = {
|
||||||
|
|
@ -110,5 +112,14 @@ export type ModerationLogPayloads = {
|
||||||
noteId: string;
|
noteId: string;
|
||||||
noteUserId: string;
|
noteUserId: string;
|
||||||
note: any;
|
note: any;
|
||||||
}
|
};
|
||||||
|
createGlobalAnnouncement: {
|
||||||
|
announcementId: string;
|
||||||
|
announcement: any;
|
||||||
|
};
|
||||||
|
createUserAnnouncement: {
|
||||||
|
announcementId: string;
|
||||||
|
announcement: any;
|
||||||
|
userId: string;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue