diff --git a/packages/backend/src/server/api/EndpointsModule.ts b/packages/backend/src/server/api/EndpointsModule.ts index 95ce245d05ce..d5840647e1b1 100644 --- a/packages/backend/src/server/api/EndpointsModule.ts +++ b/packages/backend/src/server/api/EndpointsModule.ts @@ -49,6 +49,7 @@ import * as ep___admin_emoji_setCategoryBulk from './endpoints/admin/emoji/set-c import * as ep___admin_emoji_setLicenseBulk from './endpoints/admin/emoji/set-license-bulk.js'; import * as ep___admin_emoji_update from './endpoints/admin/emoji/update.js'; import * as ep___admin_emoji_getEmojiLog from './endpoints/admin/emoji/get-emoji-log.js'; +import * as ep___admin_emoji_getEmojiLogs from './endpoints/admin/emoji/get-emoji-logs.js'; import * as ep___admin_federation_deleteAllFiles from './endpoints/admin/federation/delete-all-files.js'; import * as ep___admin_federation_refreshRemoteInstanceMetadata from './endpoints/admin/federation/refresh-remote-instance-metadata.js'; import * as ep___admin_federation_removeAllFollowing from './endpoints/admin/federation/remove-all-following.js'; @@ -440,6 +441,7 @@ const $admin_emoji_setCategoryBulk: Provider = { provide: 'ep:admin/emoji/set-ca const $admin_emoji_setLicenseBulk: Provider = { provide: 'ep:admin/emoji/set-license-bulk', useClass: ep___admin_emoji_setLicenseBulk.default }; const $admin_emoji_update: Provider = { provide: 'ep:admin/emoji/update', useClass: ep___admin_emoji_update.default }; const $admin_emoji_getEmojiLog: Provider = { provide: 'ep:admin/emoji/get-emoji-log', useClass: ep___admin_emoji_getEmojiLog.default }; +const $admin_emoji_getEmojiLogs: Provider = { provide: 'ep:admin/emoji/get-emoji-logs', useClass: ep___admin_emoji_getEmojiLogs.default }; const $admin_federation_deleteAllFiles: Provider = { provide: 'ep:admin/federation/delete-all-files', useClass: ep___admin_federation_deleteAllFiles.default }; const $admin_federation_refreshRemoteInstanceMetadata: Provider = { provide: 'ep:admin/federation/refresh-remote-instance-metadata', useClass: ep___admin_federation_refreshRemoteInstanceMetadata.default }; const $admin_federation_removeAllFollowing: Provider = { provide: 'ep:admin/federation/remove-all-following', useClass: ep___admin_federation_removeAllFollowing.default }; @@ -835,6 +837,7 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__ $admin_emoji_setLicenseBulk, $admin_emoji_update, $admin_emoji_getEmojiLog, + $admin_emoji_getEmojiLogs, $admin_federation_deleteAllFiles, $admin_federation_refreshRemoteInstanceMetadata, $admin_federation_removeAllFollowing, @@ -1224,6 +1227,7 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__ $admin_emoji_setLicenseBulk, $admin_emoji_update, $admin_emoji_getEmojiLog, + $admin_emoji_getEmojiLogs, $admin_federation_deleteAllFiles, $admin_federation_refreshRemoteInstanceMetadata, $admin_federation_removeAllFollowing, diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts index dca1dccf018d..5cc960862de2 100644 --- a/packages/backend/src/server/api/endpoints.ts +++ b/packages/backend/src/server/api/endpoints.ts @@ -54,6 +54,7 @@ import * as ep___admin_emoji_setCategoryBulk from './endpoints/admin/emoji/set-c import * as ep___admin_emoji_setLicenseBulk from './endpoints/admin/emoji/set-license-bulk.js'; import * as ep___admin_emoji_update from './endpoints/admin/emoji/update.js'; import * as ep___admin_emoji_getEmojiLog from './endpoints/admin/emoji/get-emoji-log.js'; +import * as ep___admin_emoji_getEmojiLogs from './endpoints/admin/emoji/get-emoji-logs.js'; import * as ep___admin_federation_deleteAllFiles from './endpoints/admin/federation/delete-all-files.js'; import * as ep___admin_federation_refreshRemoteInstanceMetadata from './endpoints/admin/federation/refresh-remote-instance-metadata.js'; @@ -444,6 +445,7 @@ const eps = [ ['admin/emoji/set-license-bulk', ep___admin_emoji_setLicenseBulk], ['admin/emoji/update', ep___admin_emoji_update], ['admin/emoji/get-emoji-log', ep___admin_emoji_getEmojiLog], + ['admin/emoji/get-emoji-logs', ep___admin_emoji_getEmojiLogs], ['admin/federation/delete-all-files', ep___admin_federation_deleteAllFiles], ['admin/federation/refresh-remote-instance-metadata', ep___admin_federation_refreshRemoteInstanceMetadata], ['admin/federation/remove-all-following', ep___admin_federation_removeAllFollowing], diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/get-emoji-logs.ts b/packages/backend/src/server/api/endpoints/admin/emoji/get-emoji-logs.ts new file mode 100644 index 000000000000..f78126dcb29b --- /dev/null +++ b/packages/backend/src/server/api/endpoints/admin/emoji/get-emoji-logs.ts @@ -0,0 +1,111 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { In } from 'typeorm'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import type { EmojiModerationLog, EmojiModerationLogsRepository } from '@/models/_.js'; +import { DI } from '@/di-symbols.js'; +import { UserEntityService } from '@/core/entities/UserEntityService.js'; +import { ApiError } from '@/server/api/error.js'; + +export const meta = { + tags: ['admin'], + + requireCredential: true, + requireRolePolicy: 'canManageCustomEmojis', + kind: 'read:admin:emoji-log', + + cacheSec: 3600, + + errors: { + limitExceedEmojiIds: { + message: 'The number of elements in the id array passed exceeds the limit.', + code: 'LIMIT_EXCEED_EMOJI_IDS', + id: '1d39dbf5-774e-4886-8f1c-300985228386', + }, + }, + + res: { + type: 'array', + items: { + type: 'object', + properties: { + id: { + type: 'string', + format: 'misskey:id', + }, + logs: { + type: 'array', + optional: false, nullable: false, + ref: 'EmojiChangeLogs', + }, + }, + }, + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + ids: { + type: 'array', + items: { + type: 'string', + format: 'misskey:id', + }, + }, + }, + required: ['ids'], +} as const; + +const MAXIMUM_EMOJI_GET_COUNT = 100; + +// eslint-disable-next-line import/no-default-export +@Injectable() +export default class extends Endpoint { + constructor( + @Inject(DI.emojiModerationLogsRepository) + private emojiModerationLogsRepository: EmojiModerationLogsRepository, + + private userEntityService: UserEntityService, + ) { + super(meta, paramDef, async (ps, me) => { + if (ps.ids.length > MAXIMUM_EMOJI_GET_COUNT) { + throw new ApiError(meta.errors.limitExceedEmojiIds); + } + + const logs = await this.emojiModerationLogsRepository.find({ + where: { + emojiId: In(ps.ids), + }, + order: { + createdAt: 'ASC', + }, + }); + + // Object.groupByと同じようなもの + const dictedLogs = logs.reduce((obj, log) => { + const key = log.emojiId; + if (!(key in obj)) { + obj[key] = []; + } + obj[key].push(log); + return obj; + }, {} as Record); + + const promisedResponseList = Object.entries(dictedLogs).map(async (e) => ({ + id: e[0], + logs: await Promise.all( + e[1].map(async (v) => ({ + id: v.id, + createDate: v.createdAt.toISOString(), + userId: v.userId, + user: await this.userEntityService.pack(v.user ?? v.userId), + type: v.type, + changesProperties: v.info, + })), + ), + })); + + return await Promise.all(promisedResponseList); + }); + } +}