Merge remote-tracking branch 'misskey-dev/develop' into io

This commit is contained in:
まっちゃとーにゅ 2024-02-27 04:08:00 +09:00
commit d18e3e9b93
No known key found for this signature in database
GPG key ID: 6AFBBF529601C1DB
12 changed files with 59 additions and 22 deletions

View file

@ -28,6 +28,10 @@
- Fix: nodeinfoにenableMcaptchaとenableTurnstileが無いのを修正 - Fix: nodeinfoにenableMcaptchaとenableTurnstileが無いのを修正
- エンドポイント`flash/update`の`flashId`以外のパラメータは必須ではなくなりました - エンドポイント`flash/update`の`flashId`以外のパラメータは必須ではなくなりました
- Fix: 禁止キーワードを含むートがDelayed Queueに追加されて再処理される問題を修正 - Fix: 禁止キーワードを含むートがDelayed Queueに追加されて再処理される問題を修正
- エンドポイント`admin/emoji/update`の各種修正
- 必須パラメータを`id`または`name`のいずれかのみに
- `id`の代わりに`name`で絵文字を指定可能に(`id`・`name`両指定時は従来通り`name`を変更する挙動)
- `category`および`licence`が指定なしの時勝手にnullに上書きされる挙動を修正
## 2024.2.0 ## 2024.2.0

View file

@ -405,6 +405,11 @@ export class CustomEmojiService implements OnApplicationShutdown {
return this.emojisRepository.findOneBy({ id }); return this.emojisRepository.findOneBy({ id });
} }
@bindThis
public getEmojiByName(name: string): Promise<MiEmoji | null> {
return this.emojisRepository.findOneBy({ name, host: IsNull() });
}
@bindThis @bindThis
public dispose(): void { public dispose(): void {
this.cache.dispose(); this.cache.dispose();

View file

@ -148,6 +148,9 @@ export const packedUserLiteSchema = {
emojis: { emojis: {
type: 'object', type: 'object',
nullable: false, optional: false, nullable: false, optional: false,
additionalProperties: {
type: 'string',
},
}, },
onlineStatus: { onlineStatus: {
type: 'string', type: 'string',

View file

@ -31,7 +31,10 @@ export const meta = {
}, },
}, },
ref: 'EmojiDetailed', res: {
type: 'object',
ref: 'EmojiDetailed',
},
} as const; } as const;
export const paramDef = { export const paramDef = {

View file

@ -64,7 +64,10 @@ export const paramDef = {
format: 'misskey:id', format: 'misskey:id',
} }, } },
}, },
required: ['id', 'name', 'aliases'], anyOf: [
{ required: ['id'] },
{ required: ['name'] },
],
} as const; } as const;
@Injectable() @Injectable()
@ -77,27 +80,33 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
) { ) {
super(meta, paramDef, async (ps, me) => { super(meta, paramDef, async (ps, me) => {
let driveFile; let driveFile;
if (ps.fileId) { if (ps.fileId) {
driveFile = await this.driveFilesRepository.findOneBy({ id: ps.fileId }); driveFile = await this.driveFilesRepository.findOneBy({ id: ps.fileId });
if (driveFile == null) throw new ApiError(meta.errors.noSuchFile); if (driveFile == null) throw new ApiError(meta.errors.noSuchFile);
} }
const emoji = await this.customEmojiService.getEmojiById(ps.id);
if (emoji != null) { let emojiId;
if (ps.name !== emoji.name) { 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); const isDuplicate = await this.customEmojiService.checkDuplicate(ps.name);
if (isDuplicate) throw new ApiError(meta.errors.sameNameEmojiExists); if (isDuplicate) throw new ApiError(meta.errors.sameNameEmojiExists);
} }
} else { } 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, driveFile,
name: ps.name, name: ps.name,
category: ps.category ?? null, category: ps.category,
aliases: ps.aliases, aliases: ps.aliases,
license: ps.license ?? null, license: ps.license,
isSensitive: ps.isSensitive, isSensitive: ps.isSensitive,
localOnly: ps.localOnly, localOnly: ps.localOnly,
requestedBy: ps.requestedBy ?? null, requestedBy: ps.requestedBy ?? null,

View file

@ -401,7 +401,8 @@ function toStories(component: string): Promise<string> {
// glob('src/{components,pages,ui,widgets}/**/*.vue') // glob('src/{components,pages,ui,widgets}/**/*.vue')
(async () => { (async () => {
const globs = await Promise.all([ 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/Mk{A,B}*.vue'),
glob('src/components/MkDigitalClock.vue'), glob('src/components/MkDigitalClock.vue'),
glob('src/components/MkGalleryPostPreview.vue'), glob('src/components/MkGalleryPostPreview.vue'),

View file

@ -32,7 +32,8 @@ export const Default = {
async play({ canvasElement }) { async play({ canvasElement }) {
const canvas = within(canvasElement); const canvas = within(canvasElement);
const a = canvas.getByRole<HTMLAnchorElement>('link'); 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 userEvent.pointer({ keys: '[MouseRight]', target: a });
await tick(); await tick();
const menu = canvas.getByRole('menu'); const menu = canvas.getByRole('menu');
@ -44,6 +45,7 @@ export const Default = {
}, },
args: { args: {
to: '#test', to: '#test',
behavior: 'browser',
}, },
parameters: { parameters: {
layout: 'centered', layout: 'centered',

View file

@ -10,7 +10,7 @@ import MkTime from './MkTime.vue';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { dateTimeFormat } from '@/scripts/intl-const.js'; import { dateTimeFormat } from '@/scripts/intl-const.js';
const now = new Date('2023-04-01T00:00:00.000Z'); 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 oneHourAgo = new Date(now.getTime() - 3600000);
const oneDayAgo = new Date(now.getTime() - 86400000); const oneDayAgo = new Date(now.getTime() - 86400000);
const oneWeekAgo = new Date(now.getTime() - 604800000); const oneWeekAgo = new Date(now.getTime() - 604800000);
@ -49,7 +49,7 @@ export const Empty = {
export const RelativeFuture = { export const RelativeFuture = {
...Empty, ...Empty,
async play({ canvasElement }) { 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: { args: {
...Empty.args, ...Empty.args,

View file

@ -145,6 +145,9 @@ type AdminEmojiAddAliasesBulkRequest = operations['admin/emoji/add-aliases-bulk'
// @public (undocumented) // @public (undocumented)
type AdminEmojiAddRequest = operations['admin/emoji/add']['requestBody']['content']['application/json']; 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) // @public (undocumented)
type AdminEmojiCopyRequest = operations['admin/emoji/copy']['requestBody']['content']['application/json']; type AdminEmojiCopyRequest = operations['admin/emoji/copy']['requestBody']['content']['application/json'];
@ -1202,6 +1205,7 @@ declare namespace entities {
AdminDriveShowFileResponse, AdminDriveShowFileResponse,
AdminEmojiAddAliasesBulkRequest, AdminEmojiAddAliasesBulkRequest,
AdminEmojiAddRequest, AdminEmojiAddRequest,
AdminEmojiAddResponse,
AdminEmojiCopyRequest, AdminEmojiCopyRequest,
AdminEmojiCopyResponse, AdminEmojiCopyResponse,
AdminEmojiDeleteBulkRequest, AdminEmojiDeleteBulkRequest,

View file

@ -41,6 +41,7 @@ import type {
AdminDriveShowFileResponse, AdminDriveShowFileResponse,
AdminEmojiAddAliasesBulkRequest, AdminEmojiAddAliasesBulkRequest,
AdminEmojiAddRequest, AdminEmojiAddRequest,
AdminEmojiAddResponse,
AdminEmojiCopyRequest, AdminEmojiCopyRequest,
AdminEmojiCopyResponse, AdminEmojiCopyResponse,
AdminEmojiDeleteBulkRequest, AdminEmojiDeleteBulkRequest,
@ -597,7 +598,7 @@ export type Endpoints = {
'admin/drive/files': { req: AdminDriveFilesRequest; res: AdminDriveFilesResponse }; 'admin/drive/files': { req: AdminDriveFilesRequest; res: AdminDriveFilesResponse };
'admin/drive/show-file': { req: AdminDriveShowFileRequest; res: AdminDriveShowFileResponse }; 'admin/drive/show-file': { req: AdminDriveShowFileRequest; res: AdminDriveShowFileResponse };
'admin/emoji/add-aliases-bulk': { req: AdminEmojiAddAliasesBulkRequest; res: EmptyResponse }; '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/copy': { req: AdminEmojiCopyRequest; res: AdminEmojiCopyResponse };
'admin/emoji/delete-bulk': { req: AdminEmojiDeleteBulkRequest; res: EmptyResponse }; 'admin/emoji/delete-bulk': { req: AdminEmojiDeleteBulkRequest; res: EmptyResponse };
'admin/emoji/delete': { req: AdminEmojiDeleteRequest; res: EmptyResponse }; 'admin/emoji/delete': { req: AdminEmojiDeleteRequest; res: EmptyResponse };

View file

@ -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 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 AdminEmojiAddAliasesBulkRequest = operations['admin/emoji/add-aliases-bulk']['requestBody']['content']['application/json'];
export type AdminEmojiAddRequest = operations['admin/emoji/add']['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 AdminEmojiCopyRequest = operations['admin/emoji/copy']['requestBody']['content']['application/json'];
export type AdminEmojiCopyResponse = operations['admin/emoji/copy']['responses']['200']['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']; export type AdminEmojiDeleteBulkRequest = operations['admin/emoji/delete-bulk']['requestBody']['content']['application/json'];

View file

@ -3678,7 +3678,9 @@ export type components = {
faviconUrl: string | null; faviconUrl: string | null;
themeColor: string | null; themeColor: string | null;
}; };
emojis: Record<string, never>; emojis: {
[key: string]: string;
};
/** @enum {string} */ /** @enum {string} */
onlineStatus: 'unknown' | 'online' | 'active' | 'offline'; onlineStatus: 'unknown' | 'online' | 'active' | 'offline';
badgeRoles?: ({ badgeRoles?: ({
@ -6947,9 +6949,11 @@ export type operations = {
}; };
}; };
responses: { responses: {
/** @description OK (without any results) */ /** @description OK (with results) */
204: { 200: {
content: never; content: {
'application/json': components['schemas']['EmojiDetailed'];
};
}; };
/** @description Client error */ /** @description Client error */
400: { 400: {
@ -7560,13 +7564,13 @@ export type operations = {
content: { content: {
'application/json': { 'application/json': {
/** Format: misskey:id */ /** Format: misskey:id */
id: string; id?: string;
name: string; name?: string;
/** Format: misskey:id */ /** Format: misskey:id */
fileId?: string; fileId?: string;
/** @description Use `null` to reset the category. */ /** @description Use `null` to reset the category. */
category?: string | null; category?: string | null;
aliases: string[]; aliases?: string[];
license?: string | null; license?: string | null;
isSensitive?: boolean; isSensitive?: boolean;
localOnly?: boolean; localOnly?: boolean;