diff options
| author | おさむのひと <46447427+samunohito@users.noreply.github.com> | 2025-01-20 20:35:37 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-01-20 11:35:37 +0000 |
| commit | f9ad127aaf7875bad8fdf55f5ac98bff05997525 (patch) | |
| tree | cd8a4a3be870fee215e2940cb3c7571531c71385 /packages/backend/src/server/api/endpoints | |
| parent | fix(client): MkSubNoteContentに対するnoteの指定が誤っていたの... (diff) | |
| download | sharkey-f9ad127aaf7875bad8fdf55f5ac98bff05997525.tar.gz sharkey-f9ad127aaf7875bad8fdf55f5ac98bff05997525.tar.bz2 sharkey-f9ad127aaf7875bad8fdf55f5ac98bff05997525.zip | |
feat: 新カスタム絵文字管理画面(β)の追加 (#13473)
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* fix
* fix
* fix
* fix size
* fix register logs
* fix img autosize
* fix row selection
* support delete
* fix border rendering
* fix display:none
* tweak comments
* support choose pc file and drive file
* support directory drag-drop
* fix
* fix comment
* support context menu on data area
* fix autogen
* wip イベント整理
* イベントの整理
* refactor grid
* fix cell re-render bugs
* fix row remove
* fix comment
* fix validation
* fix utils
* list maximum
* add mimetype check
* fix
* fix number cell focus
* fix over 100 file drop
* remove log
* fix patchData
* fix performance
* fix
* support update and delete
* support remote import
* fix layout
* heightやめる
* fix performance
* add list v2 endpoint
* support pagination
* fix api call
* fix no clickable input text
* fix limit
* fix paging
* fix
* fix
* support search
* tweak logs
* tweak cell selection
* fix range select
* block delete
* add comment
* fix
* support import log
* fix dialog
* refactor
* add confirm dialog
* fix name
* fix autogen
* wip
* support image change and highlight row
* add columns
* wip
* support sort
* add role name
* add index to emoji
* refine context menu setting
* support role select
* remove unused buttons
* fix url
* fix MkRoleSelectDialog.vue
* add route
* refine remote page
* enter key search
* fix paste bugs
* fix copy/paste
* fix keyEvent
* fix copy/paste and delete
* fix comment
* fix MkRoleSelectDialog.vue and storybook scenario
* fix MkRoleSelectDialog.vue and storybook scenario
* add MkGrid.stories.impl.ts
* fix
* [wip] add custom-emojis-manager2.stories.impl.ts
* [wip] add custom-emojis-manager2.stories.impl.ts
* wip
* 課題はまだ残っているが、ひとまず完了
* fix validation and register roles
* fix upload
* optimize import
* patch from dev
* i18n
* revert excess fixes
* separate sort order component
* add SPDX
* revert excess fixes
* fix pre test
* fix bugs
* add type column
* fix types
* fix CHANGELOG.md
* fix lit
* lint
* tweak style
* refactor
* fix ci
* autogen
* Update types.ts
* CSS Module化
* fix log
* 縦スクロールを無効化
* MkStickyContainer化
* regenerate locales index.d.ts
* fix
* fix
* テスト
* ランダム値によるUI変更の抑制
* テスト
* tableタグやめる
* fix last-child css
* fix overflow css
* fix endpoint.ts
* tweak css
* 最新への追従とレイアウト微調整
* ソートキーの指定方法を他と合わせた
* fix focus
* fix layout
* v2エンドポイントのルールに対応
* 表示条件などを微調整
* fix MkDataCell.vue
* fix error code
* fix error
* add comment to MkModal.vue
* Update index.d.ts
* fix CHANGELOG.md
* fix color theme
* fix CHANGELOG.md
* fix CHANGELOG.md
* fix center
* fix: テーブルにフォーカスがあり、通常状態であるときはキーイベントの伝搬を止める
* fix: ロール選択用のダイアログにてコンディショナルロールを×ボタンで除外できなかったのを修正
* fix remote list folder
* sticky footers
* chore: fix ci error(just single line-break diff)
* fix loading
* fix like
* comma to space
* fix ci
* fix ci
* removed align-center
---------
Co-authored-by: osamu <46447427+sam-osamu@users.noreply.github.com>
Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
Co-authored-by: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com>
Diffstat (limited to 'packages/backend/src/server/api/endpoints')
4 files changed, 155 insertions, 12 deletions
diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/add.ts b/packages/backend/src/server/api/endpoints/admin/emoji/add.ts index 796f273330..53256565f6 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/add.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/add.ts @@ -9,6 +9,7 @@ import type { DriveFilesRepository } from '@/models/_.js'; import { DI } from '@/di-symbols.js'; import { CustomEmojiService } from '@/core/CustomEmojiService.js'; import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js'; +import { FILE_TYPE_IMAGE } from '@/const.js'; import { ApiError } from '../../../error.js'; export const meta = { @@ -24,6 +25,11 @@ export const meta = { code: 'NO_SUCH_FILE', id: 'fc46b5a4-6b92-4c33-ac66-b806659bb5cf', }, + unsupportedFileType: { + message: 'Unsupported file type.', + code: 'UNSUPPORTED_FILE_TYPE', + id: 'f7599d96-8750-af68-1633-9575d625c1a7', + }, duplicateName: { message: 'Duplicate name.', code: 'DUPLICATE_NAME', @@ -47,15 +53,21 @@ export const paramDef = { nullable: true, description: 'Use `null` to reset the category.', }, - aliases: { type: 'array', items: { - type: 'string', - } }, + aliases: { + type: 'array', + items: { + type: 'string', + }, + }, license: { type: 'string', nullable: true }, isSensitive: { type: 'boolean' }, localOnly: { type: 'boolean' }, - roleIdsThatCanBeUsedThisEmojiAsReaction: { type: 'array', items: { - type: 'string', - } }, + roleIdsThatCanBeUsedThisEmojiAsReaction: { + type: 'array', + items: { + type: 'string', + }, + }, }, required: ['name', 'fileId'], } as const; @@ -67,9 +79,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- constructor( @Inject(DI.driveFilesRepository) private driveFilesRepository: DriveFilesRepository, - private customEmojiService: CustomEmojiService, - private emojiEntityService: EmojiEntityService, ) { super(meta, paramDef, async (ps, me) => { @@ -77,9 +87,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- if (driveFile == null) throw new ApiError(meta.errors.noSuchFile); const isDuplicate = await this.customEmojiService.checkDuplicate(ps.name); if (isDuplicate) throw new ApiError(meta.errors.duplicateName); + if (!FILE_TYPE_IMAGE.includes(driveFile.type)) throw new ApiError(meta.errors.unsupportedFileType); const emoji = await this.customEmojiService.add({ - driveFile, + originalUrl: driveFile.url, + publicUrl: driveFile.webpublicUrl ?? driveFile.url, + fileType: driveFile.webpublicType ?? driveFile.type, name: ps.name, category: ps.category ?? null, aliases: ps.aliases ?? [], diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts b/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts index 975f892df9..87b58ff6f6 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts @@ -86,7 +86,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- if (isDuplicate) throw new ApiError(meta.errors.duplicateName); const addedEmoji = await this.customEmojiService.add({ - driveFile, + originalUrl: driveFile.url, + publicUrl: driveFile.webpublicUrl ?? driveFile.url, + fileType: driveFile.webpublicType ?? driveFile.type, name: emoji.name, category: emoji.category, aliases: emoji.aliases, diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/update.ts b/packages/backend/src/server/api/endpoints/admin/emoji/update.ts index 212cba5c5d..e3aaa051c1 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/update.ts @@ -79,13 +79,15 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- } // JSON schemeのanyOfの型変換がうまくいっていないらしい - const required = { id: ps.id, name: ps.name } as + const required = { id: ps.id, name: ps.name } as | { id: MiEmoji['id']; name?: string } | { id?: MiEmoji['id']; name: string }; const error = await this.customEmojiService.update({ ...required, - driveFile, + originalUrl: driveFile != null ? driveFile.url : undefined, + publicUrl: driveFile != null ? (driveFile.webpublicUrl ?? driveFile.url) : undefined, + fileType: driveFile != null ? (driveFile.webpublicType ?? driveFile.type) : undefined, category: ps.category, aliases: ps.aliases, license: ps.license, diff --git a/packages/backend/src/server/api/endpoints/v2/admin/emoji/list.ts b/packages/backend/src/server/api/endpoints/v2/admin/emoji/list.ts new file mode 100644 index 0000000000..9426318e34 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/v2/admin/emoji/list.ts @@ -0,0 +1,126 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js'; +import { CustomEmojiService, fetchEmojisHostTypes, fetchEmojisSortKeys } from '@/core/CustomEmojiService.js'; + +export const meta = { + tags: ['admin'], + + requireCredential: true, + requireRolePolicy: 'canManageCustomEmojis', + kind: 'read:admin:emoji', + + res: { + type: 'object', + properties: { + emojis: { + type: 'array', + items: { + type: 'object', + ref: 'EmojiDetailedAdmin', + }, + }, + count: { type: 'integer' }, + allCount: { type: 'integer' }, + allPages: { type: 'integer' }, + }, + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + query: { + type: 'object', + nullable: true, + properties: { + updatedAtFrom: { type: 'string' }, + updatedAtTo: { type: 'string' }, + name: { type: 'string' }, + host: { type: 'string' }, + uri: { type: 'string' }, + publicUrl: { type: 'string' }, + originalUrl: { type: 'string' }, + type: { type: 'string' }, + aliases: { type: 'string' }, + category: { type: 'string' }, + license: { type: 'string' }, + isSensitive: { type: 'boolean' }, + localOnly: { type: 'boolean' }, + hostType: { + type: 'string', + enum: fetchEmojisHostTypes, + default: 'all', + }, + roleIds: { + type: 'array', + items: { type: 'string', format: 'misskey:id' }, + }, + }, + }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + page: { type: 'integer' }, + sortKeys: { + type: 'array', + default: ['-id'], + items: { + type: 'string', + enum: fetchEmojisSortKeys, + }, + }, + }, + required: [], +} as const; + +@Injectable() +export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export + constructor( + private customEmojiService: CustomEmojiService, + private emojiEntityService: EmojiEntityService, + ) { + super(meta, paramDef, async (ps, me) => { + const q = ps.query; + const result = await this.customEmojiService.fetchEmojis( + { + query: { + updatedAtFrom: q?.updatedAtFrom, + updatedAtTo: q?.updatedAtTo, + name: q?.name, + host: q?.host, + uri: q?.uri, + publicUrl: q?.publicUrl, + type: q?.type, + aliases: q?.aliases, + category: q?.category, + license: q?.license, + isSensitive: q?.isSensitive, + localOnly: q?.localOnly, + hostType: q?.hostType, + roleIds: q?.roleIds, + }, + sinceId: ps.sinceId, + untilId: ps.untilId, + }, + { + limit: ps.limit, + page: ps.page, + sortKeys: ps.sortKeys, + }, + ); + + return { + emojis: await this.emojiEntityService.packDetailedAdminMany(result.emojis), + count: result.count, + allCount: result.allCount, + allPages: result.allPages, + }; + }); + } +} |