Merge remote-tracking branch 'misskey-dev/develop' into io
This commit is contained in:
		
						commit
						d18e3e9b93
					
				|  | @ -28,6 +28,10 @@ | |||
| - Fix: nodeinfoにenableMcaptchaとenableTurnstileが無いのを修正 | ||||
| - エンドポイント`flash/update`の`flashId`以外のパラメータは必須ではなくなりました | ||||
| - Fix: 禁止キーワードを含むノートがDelayed Queueに追加されて再処理される問題を修正 | ||||
| - エンドポイント`admin/emoji/update`の各種修正 | ||||
|   - 必須パラメータを`id`または`name`のいずれかのみに | ||||
|   - `id`の代わりに`name`で絵文字を指定可能に(`id`・`name`両指定時は従来通り`name`を変更する挙動) | ||||
|   - `category`および`licence`が指定なしの時勝手にnullに上書きされる挙動を修正 | ||||
| 
 | ||||
| ## 2024.2.0 | ||||
| 
 | ||||
|  |  | |||
|  | @ -405,6 +405,11 @@ export class CustomEmojiService implements OnApplicationShutdown { | |||
| 		return this.emojisRepository.findOneBy({ id }); | ||||
| 	} | ||||
| 
 | ||||
| 	@bindThis | ||||
| 	public getEmojiByName(name: string): Promise<MiEmoji | null> { | ||||
| 		return this.emojisRepository.findOneBy({ name, host: IsNull() }); | ||||
| 	} | ||||
| 
 | ||||
| 	@bindThis | ||||
| 	public dispose(): void { | ||||
| 		this.cache.dispose(); | ||||
|  |  | |||
|  | @ -148,6 +148,9 @@ export const packedUserLiteSchema = { | |||
| 		emojis: { | ||||
| 			type: 'object', | ||||
| 			nullable: false, optional: false, | ||||
| 			additionalProperties: { | ||||
| 				type: 'string', | ||||
| 			}, | ||||
| 		}, | ||||
| 		onlineStatus: { | ||||
| 			type: 'string', | ||||
|  |  | |||
|  | @ -31,7 +31,10 @@ export const meta = { | |||
| 		}, | ||||
| 	}, | ||||
| 
 | ||||
| 	ref: 'EmojiDetailed', | ||||
| 	res: { | ||||
| 		type: 'object', | ||||
| 		ref: 'EmojiDetailed', | ||||
| 	}, | ||||
| } as const; | ||||
| 
 | ||||
| export const paramDef = { | ||||
|  |  | |||
|  | @ -64,7 +64,10 @@ export const paramDef = { | |||
| 			format: 'misskey:id', | ||||
| 		} }, | ||||
| 	}, | ||||
| 	required: ['id', 'name', 'aliases'], | ||||
| 	anyOf: [ | ||||
| 		{ required: ['id'] }, | ||||
| 		{ required: ['name'] }, | ||||
| 	], | ||||
| } as const; | ||||
| 
 | ||||
| @Injectable() | ||||
|  | @ -77,27 +80,33 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 	) { | ||||
| 		super(meta, paramDef, async (ps, me) => { | ||||
| 			let driveFile; | ||||
| 
 | ||||
| 			if (ps.fileId) { | ||||
| 				driveFile = await this.driveFilesRepository.findOneBy({ id: ps.fileId }); | ||||
| 				if (driveFile == null) throw new ApiError(meta.errors.noSuchFile); | ||||
| 			} | ||||
| 			const emoji = await this.customEmojiService.getEmojiById(ps.id); | ||||
| 			if (emoji != null) { | ||||
| 				if (ps.name !== emoji.name) { | ||||
| 
 | ||||
| 			let emojiId; | ||||
| 			if (ps.id) { | ||||
| 				emojiId = ps.id; | ||||
| 				const emoji = await this.customEmojiService.getEmojiById(ps.id); | ||||
| 				if (!emoji) throw new ApiError(meta.errors.noSuchEmoji); | ||||
| 				if (ps.name && (ps.name !== emoji.name)) { | ||||
| 					const isDuplicate = await this.customEmojiService.checkDuplicate(ps.name); | ||||
| 					if (isDuplicate) throw new ApiError(meta.errors.sameNameEmojiExists); | ||||
| 				} | ||||
| 			} else { | ||||
| 				throw new ApiError(meta.errors.noSuchEmoji); | ||||
| 				if (!ps.name) throw new Error('Invalid Params unexpectedly passed. This is a BUG. Please report it to the development team.'); | ||||
| 				const emoji = await this.customEmojiService.getEmojiByName(ps.name); | ||||
| 				if (!emoji) throw new ApiError(meta.errors.noSuchEmoji); | ||||
| 				emojiId = emoji.id; | ||||
| 			} | ||||
| 
 | ||||
| 			await this.customEmojiService.update(ps.id, { | ||||
| 			await this.customEmojiService.update(emojiId, { | ||||
| 				driveFile, | ||||
| 				name: ps.name, | ||||
| 				category: ps.category ?? null, | ||||
| 				category: ps.category, | ||||
| 				aliases: ps.aliases, | ||||
| 				license: ps.license ?? null, | ||||
| 				license: ps.license, | ||||
| 				isSensitive: ps.isSensitive, | ||||
| 				localOnly: ps.localOnly, | ||||
| 				requestedBy: ps.requestedBy ?? null, | ||||
|  |  | |||
|  | @ -401,7 +401,8 @@ function toStories(component: string): Promise<string> { | |||
| // glob('src/{components,pages,ui,widgets}/**/*.vue')
 | ||||
| (async () => { | ||||
| 	const globs = await Promise.all([ | ||||
| 		glob('src/components/global/*.vue'), | ||||
| 		glob('src/components/global/Mk*.vue'), | ||||
| 		glob('src/components/global/RouterView.vue'), | ||||
| 		glob('src/components/Mk{A,B}*.vue'), | ||||
| 		glob('src/components/MkDigitalClock.vue'), | ||||
| 		glob('src/components/MkGalleryPostPreview.vue'), | ||||
|  |  | |||
|  | @ -32,7 +32,8 @@ export const Default = { | |||
| 	async play({ canvasElement }) { | ||||
| 		const canvas = within(canvasElement); | ||||
| 		const a = canvas.getByRole<HTMLAnchorElement>('link'); | ||||
| 		await expect(a.href).toMatch(/^https?:\/\/.*#test$/); | ||||
| 		// FIXME: 通るけどその後落ちるのでコメントアウト
 | ||||
| 		// await expect(a.href).toMatch(/^https?:\/\/.*#test$/);
 | ||||
| 		await userEvent.pointer({ keys: '[MouseRight]', target: a }); | ||||
| 		await tick(); | ||||
| 		const menu = canvas.getByRole('menu'); | ||||
|  | @ -44,6 +45,7 @@ export const Default = { | |||
| 	}, | ||||
| 	args: { | ||||
| 		to: '#test', | ||||
| 		behavior: 'browser', | ||||
| 	}, | ||||
| 	parameters: { | ||||
| 		layout: 'centered', | ||||
|  |  | |||
|  | @ -10,7 +10,7 @@ import MkTime from './MkTime.vue'; | |||
| import { i18n } from '@/i18n.js'; | ||||
| import { dateTimeFormat } from '@/scripts/intl-const.js'; | ||||
| const now = new Date('2023-04-01T00:00:00.000Z'); | ||||
| const future = new Date('3000-04-01T00:00:00.000Z'); | ||||
| const future = new Date('2024-04-01T00:00:00.000Z'); | ||||
| const oneHourAgo = new Date(now.getTime() - 3600000); | ||||
| const oneDayAgo = new Date(now.getTime() - 86400000); | ||||
| const oneWeekAgo = new Date(now.getTime() - 604800000); | ||||
|  | @ -49,7 +49,7 @@ export const Empty = { | |||
| export const RelativeFuture = { | ||||
| 	...Empty, | ||||
| 	async play({ canvasElement }) { | ||||
| 		await expect(canvasElement).toHaveTextContent(i18n.tsx._timeIn.years({ n: 977 })); | ||||
| 		await expect(canvasElement).toHaveTextContent(i18n.tsx._timeIn.years({ n: 1 })); // n (1) = future (2024) - now (2023)
 | ||||
| 	}, | ||||
| 	args: { | ||||
| 		...Empty.args, | ||||
|  |  | |||
|  | @ -145,6 +145,9 @@ type AdminEmojiAddAliasesBulkRequest = operations['admin/emoji/add-aliases-bulk' | |||
| // @public (undocumented) | ||||
| type AdminEmojiAddRequest = operations['admin/emoji/add']['requestBody']['content']['application/json']; | ||||
| 
 | ||||
| // @public (undocumented) | ||||
| type AdminEmojiAddResponse = operations['admin/emoji/add']['responses']['200']['content']['application/json']; | ||||
| 
 | ||||
| // @public (undocumented) | ||||
| type AdminEmojiCopyRequest = operations['admin/emoji/copy']['requestBody']['content']['application/json']; | ||||
| 
 | ||||
|  | @ -1202,6 +1205,7 @@ declare namespace entities { | |||
|         AdminDriveShowFileResponse, | ||||
|         AdminEmojiAddAliasesBulkRequest, | ||||
|         AdminEmojiAddRequest, | ||||
|         AdminEmojiAddResponse, | ||||
|         AdminEmojiCopyRequest, | ||||
|         AdminEmojiCopyResponse, | ||||
|         AdminEmojiDeleteBulkRequest, | ||||
|  |  | |||
|  | @ -41,6 +41,7 @@ import type { | |||
| 	AdminDriveShowFileResponse, | ||||
| 	AdminEmojiAddAliasesBulkRequest, | ||||
| 	AdminEmojiAddRequest, | ||||
| 	AdminEmojiAddResponse, | ||||
| 	AdminEmojiCopyRequest, | ||||
| 	AdminEmojiCopyResponse, | ||||
| 	AdminEmojiDeleteBulkRequest, | ||||
|  | @ -597,7 +598,7 @@ export type Endpoints = { | |||
| 	'admin/drive/files': { req: AdminDriveFilesRequest; res: AdminDriveFilesResponse }; | ||||
| 	'admin/drive/show-file': { req: AdminDriveShowFileRequest; res: AdminDriveShowFileResponse }; | ||||
| 	'admin/emoji/add-aliases-bulk': { req: AdminEmojiAddAliasesBulkRequest; res: EmptyResponse }; | ||||
| 	'admin/emoji/add': { req: AdminEmojiAddRequest; res: EmptyResponse }; | ||||
| 	'admin/emoji/add': { req: AdminEmojiAddRequest; res: AdminEmojiAddResponse }; | ||||
| 	'admin/emoji/copy': { req: AdminEmojiCopyRequest; res: AdminEmojiCopyResponse }; | ||||
| 	'admin/emoji/delete-bulk': { req: AdminEmojiDeleteBulkRequest; res: EmptyResponse }; | ||||
| 	'admin/emoji/delete': { req: AdminEmojiDeleteRequest; res: EmptyResponse }; | ||||
|  |  | |||
|  | @ -43,6 +43,7 @@ export type AdminDriveShowFileRequest = operations['admin/drive/show-file']['req | |||
| export type AdminDriveShowFileResponse = operations['admin/drive/show-file']['responses']['200']['content']['application/json']; | ||||
| export type AdminEmojiAddAliasesBulkRequest = operations['admin/emoji/add-aliases-bulk']['requestBody']['content']['application/json']; | ||||
| export type AdminEmojiAddRequest = operations['admin/emoji/add']['requestBody']['content']['application/json']; | ||||
| export type AdminEmojiAddResponse = operations['admin/emoji/add']['responses']['200']['content']['application/json']; | ||||
| export type AdminEmojiCopyRequest = operations['admin/emoji/copy']['requestBody']['content']['application/json']; | ||||
| export type AdminEmojiCopyResponse = operations['admin/emoji/copy']['responses']['200']['content']['application/json']; | ||||
| export type AdminEmojiDeleteBulkRequest = operations['admin/emoji/delete-bulk']['requestBody']['content']['application/json']; | ||||
|  |  | |||
|  | @ -3678,7 +3678,9 @@ export type components = { | |||
|         faviconUrl: string | null; | ||||
|         themeColor: string | null; | ||||
|       }; | ||||
|       emojis: Record<string, never>; | ||||
|       emojis: { | ||||
|         [key: string]: string; | ||||
|       }; | ||||
|       /** @enum {string} */ | ||||
|       onlineStatus: 'unknown' | 'online' | 'active' | 'offline'; | ||||
|       badgeRoles?: ({ | ||||
|  | @ -6947,9 +6949,11 @@ export type operations = { | |||
|       }; | ||||
|     }; | ||||
|     responses: { | ||||
|       /** @description OK (without any results) */ | ||||
|       204: { | ||||
|         content: never; | ||||
|       /** @description OK (with results) */ | ||||
|       200: { | ||||
|         content: { | ||||
|           'application/json': components['schemas']['EmojiDetailed']; | ||||
|         }; | ||||
|       }; | ||||
|       /** @description Client error */ | ||||
|       400: { | ||||
|  | @ -7560,13 +7564,13 @@ export type operations = { | |||
|       content: { | ||||
|         'application/json': { | ||||
|           /** Format: misskey:id */ | ||||
|           id: string; | ||||
|           name: string; | ||||
|           id?: string; | ||||
|           name?: string; | ||||
|           /** Format: misskey:id */ | ||||
|           fileId?: string; | ||||
|           /** @description Use `null` to reset the category. */ | ||||
|           category?: string | null; | ||||
|           aliases: string[]; | ||||
|           aliases?: string[]; | ||||
|           license?: string | null; | ||||
|           isSensitive?: boolean; | ||||
|           localOnly?: boolean; | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue