refactor: api/*/update系の必須キーを最低限に (#13824)

* refactor: clips/updateの必須キーをclipIdのみに

* refactor: admin/roles/update の必須キーをroleIdのみに

* feat: pages/update の必須キーをpageIdのみに

* refactor: gallery/posts/update の必須キーをpostidのみに

* feat: misskey-jsの型を更新

* feat: i/webhooks/updateの必須キーをwebhookIdのみに

* feat: admin/ad/updateの必須キーをidのみに

* feat: misskey-jsの型を更新

* chore: update CHANGELOG.md

* docs: update CHANGELOG.md

* fix: secretが更新できなくなる場合がある

Co-authored-by: zyoshoka <107108195+zyoshoka@users.noreply.github.com>

* Update packages/backend/src/server/api/endpoints/gallery/posts/update.ts

---------

Co-authored-by: zyoshoka <107108195+zyoshoka@users.noreply.github.com>
Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
This commit is contained in:
yupix 2024-06-22 14:52:27 +09:00 committed by GitHub
parent ac12ab8629
commit b50eb511b0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 70 additions and 84 deletions

View file

@ -14,6 +14,12 @@
- Feat: レートリミット制限に引っかかったときに`Retry-After`ヘッダーを返すように (#13949) - Feat: レートリミット制限に引っかかったときに`Retry-After`ヘッダーを返すように (#13949)
- Fix: ユーザーのフィードページのMFMをHTMLに展開するように (#14006) - Fix: ユーザーのフィードページのMFMをHTMLに展開するように (#14006)
- Fix: アンテナ・クリップ・リスト・ウェブフックがロールポリシーの上限より一つ多く作れてしまうのを修正 (#14036) - Fix: アンテナ・クリップ・リスト・ウェブフックがロールポリシーの上限より一つ多く作れてしまうのを修正 (#14036)
- Enhance: エンドポイント`clips/update`の必須項目を`clipId`のみに
- Enhance: エンドポイント`admin/roles/update`の必須項目を`roleId`のみに
- Enhance: エンドポイント`pages/update`の必須項目を`pageId`のみに
- Enhance: エンドポイント`gallery/posts/update`の必須項目を`postId`のみに
- Enhance: エンドポイント`i/webhook/update`の必須項目を`webhookId`のみに
- Enhance: エンドポイント`admin/ad/update`の必須項目を`id`のみに
- Fix: notRespondingSinceが実装される前に不通になったインスタンスが自動的に配信停止にならない (#14059) - Fix: notRespondingSinceが実装される前に不通になったインスタンスが自動的に配信停止にならない (#14059)
- Fix: FTT有効時、タイムライン用エンドポイントで`sinceId`にキャッシュ内最古のものより古いものを指定した場合に正しく結果が返ってこない問題を修正 - Fix: FTT有効時、タイムライン用エンドポイントで`sinceId`にキャッシュ内最古のものより古いものを指定した場合に正しく結果が返ってこない問題を修正

View file

@ -40,7 +40,7 @@ export const paramDef = {
startsAt: { type: 'integer' }, startsAt: { type: 'integer' },
dayOfWeek: { type: 'integer' }, dayOfWeek: { type: 'integer' },
}, },
required: ['id', 'memo', 'url', 'imageUrl', 'place', 'priority', 'ratio', 'expiresAt', 'startsAt', 'dayOfWeek'], required: ['id'],
} as const; } as const;
@Injectable() @Injectable()
@ -63,8 +63,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
ratio: ps.ratio, ratio: ps.ratio,
memo: ps.memo, memo: ps.memo,
imageUrl: ps.imageUrl, imageUrl: ps.imageUrl,
expiresAt: new Date(ps.expiresAt), expiresAt: ps.expiresAt ? new Date(ps.expiresAt) : undefined,
startsAt: new Date(ps.startsAt), startsAt: ps.startsAt ? new Date(ps.startsAt) : undefined,
dayOfWeek: ps.dayOfWeek, dayOfWeek: ps.dayOfWeek,
}); });

View file

@ -6,7 +6,6 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js'; import { Endpoint } from '@/server/api/endpoint-base.js';
import type { RolesRepository } from '@/models/_.js'; import type { RolesRepository } from '@/models/_.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { ApiError } from '@/server/api/error.js'; import { ApiError } from '@/server/api/error.js';
import { RoleService } from '@/core/RoleService.js'; import { RoleService } from '@/core/RoleService.js';
@ -50,19 +49,6 @@ export const paramDef = {
}, },
required: [ required: [
'roleId', 'roleId',
'name',
'description',
'color',
'iconUrl',
'target',
'condFormula',
'isPublic',
'isModerator',
'isAdministrator',
'asBadge',
'canEditMembersByModerator',
'displayOrder',
'policies',
], ],
} as const; } as const;

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
import { Inject, Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js'; import { Endpoint } from '@/server/api/endpoint-base.js';
import { ClipEntityService } from '@/core/entities/ClipEntityService.js'; import { ClipEntityService } from '@/core/entities/ClipEntityService.js';
import { ClipService } from '@/core/ClipService.js'; import { ClipService } from '@/core/ClipService.js';
@ -41,7 +41,7 @@ export const paramDef = {
isPublic: { type: 'boolean' }, isPublic: { type: 'boolean' },
description: { type: 'string', nullable: true, minLength: 1, maxLength: 2048 }, description: { type: 'string', nullable: true, minLength: 1, maxLength: 2048 },
}, },
required: ['clipId', 'name'], required: ['clipId'],
} as const; } as const;
@Injectable() @Injectable()

View file

@ -47,7 +47,7 @@ export const paramDef = {
} }, } },
isSensitive: { type: 'boolean', default: false }, isSensitive: { type: 'boolean', default: false },
}, },
required: ['postId', 'title', 'fileIds'], required: ['postId'],
} as const; } as const;
@Injectable() @Injectable()
@ -62,15 +62,19 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private galleryPostEntityService: GalleryPostEntityService, private galleryPostEntityService: GalleryPostEntityService,
) { ) {
super(meta, paramDef, async (ps, me) => { super(meta, paramDef, async (ps, me) => {
const files = (await Promise.all(ps.fileIds.map(fileId => let files: Array<MiDriveFile> | undefined;
this.driveFilesRepository.findOneBy({
id: fileId,
userId: me.id,
}),
))).filter(x => x != null);
if (files.length === 0) { if (ps.fileIds) {
throw new Error(); files = (await Promise.all(ps.fileIds.map(fileId =>
this.driveFilesRepository.findOneBy({
id: fileId,
userId: me.id,
}),
))).filter(x => x != null);
if (files.length === 0) {
throw new Error();
}
} }
await this.galleryPostsRepository.update({ await this.galleryPostsRepository.update({
@ -81,7 +85,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
title: ps.title, title: ps.title,
description: ps.description, description: ps.description,
isSensitive: ps.isSensitive, isSensitive: ps.isSensitive,
fileIds: files.map(file => file.id), fileIds: files ? files.map(file => file.id) : undefined,
}); });
const post = await this.galleryPostsRepository.findOneByOrFail({ id: ps.postId }); const post = await this.galleryPostsRepository.findOneByOrFail({ id: ps.postId });

View file

@ -34,13 +34,13 @@ export const paramDef = {
webhookId: { type: 'string', format: 'misskey:id' }, webhookId: { type: 'string', format: 'misskey:id' },
name: { type: 'string', minLength: 1, maxLength: 100 }, name: { type: 'string', minLength: 1, maxLength: 100 },
url: { type: 'string', minLength: 1, maxLength: 1024 }, url: { type: 'string', minLength: 1, maxLength: 1024 },
secret: { type: 'string', maxLength: 1024, default: '' }, secret: { type: 'string', nullable: true, maxLength: 1024 },
on: { type: 'array', items: { on: { type: 'array', items: {
type: 'string', enum: webhookEventTypes, type: 'string', enum: webhookEventTypes,
} }, } },
active: { type: 'boolean' }, active: { type: 'boolean' },
}, },
required: ['webhookId', 'name', 'url', 'on', 'active'], required: ['webhookId'],
} as const; } as const;
// TODO: ロジックをサービスに切り出す // TODO: ロジックをサービスに切り出す
@ -66,7 +66,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
await this.webhooksRepository.update(webhook.id, { await this.webhooksRepository.update(webhook.id, {
name: ps.name, name: ps.name,
url: ps.url, url: ps.url,
secret: ps.secret, secret: ps.secret === null ? '' : ps.secret,
on: ps.on, on: ps.on,
active: ps.active, active: ps.active,
}); });

View file

@ -70,7 +70,7 @@ export const paramDef = {
alignCenter: { type: 'boolean' }, alignCenter: { type: 'boolean' },
hideTitleWhenPinned: { type: 'boolean' }, hideTitleWhenPinned: { type: 'boolean' },
}, },
required: ['pageId', 'title', 'name', 'content', 'variables', 'script'], required: ['pageId'],
} as const; } as const;
@Injectable() @Injectable()
@ -91,9 +91,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new ApiError(meta.errors.accessDenied); throw new ApiError(meta.errors.accessDenied);
} }
let eyeCatchingImage = null;
if (ps.eyeCatchingImageId != null) { if (ps.eyeCatchingImageId != null) {
eyeCatchingImage = await this.driveFilesRepository.findOneBy({ const eyeCatchingImage = await this.driveFilesRepository.findOneBy({
id: ps.eyeCatchingImageId, id: ps.eyeCatchingImageId,
userId: me.id, userId: me.id,
}); });
@ -116,23 +115,15 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
await this.pagesRepository.update(page.id, { await this.pagesRepository.update(page.id, {
updatedAt: new Date(), updatedAt: new Date(),
title: ps.title, title: ps.title,
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing name: ps.name,
name: ps.name === undefined ? page.name : ps.name,
summary: ps.summary === undefined ? page.summary : ps.summary, summary: ps.summary === undefined ? page.summary : ps.summary,
content: ps.content, content: ps.content,
variables: ps.variables, variables: ps.variables,
script: ps.script, script: ps.script,
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing alignCenter: ps.alignCenter,
alignCenter: ps.alignCenter === undefined ? page.alignCenter : ps.alignCenter, hideTitleWhenPinned: ps.hideTitleWhenPinned,
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing font: ps.font,
hideTitleWhenPinned: ps.hideTitleWhenPinned === undefined ? page.hideTitleWhenPinned : ps.hideTitleWhenPinned, eyeCatchingImageId: ps.eyeCatchingImageId,
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
font: ps.font === undefined ? page.font : ps.font,
eyeCatchingImageId: ps.eyeCatchingImageId === null
? null
: ps.eyeCatchingImageId === undefined
? page.eyeCatchingImageId
: eyeCatchingImage!.id,
}); });
}); });
} }

View file

@ -5881,15 +5881,15 @@ export type operations = {
'application/json': { 'application/json': {
/** Format: misskey:id */ /** Format: misskey:id */
id: string; id: string;
memo: string; memo?: string;
url: string; url?: string;
imageUrl: string; imageUrl?: string;
place: string; place?: string;
priority: string; priority?: string;
ratio: number; ratio?: number;
expiresAt: number; expiresAt?: number;
startsAt: number; startsAt?: number;
dayOfWeek: number; dayOfWeek?: number;
}; };
}; };
}; };
@ -9744,21 +9744,21 @@ export type operations = {
'application/json': { 'application/json': {
/** Format: misskey:id */ /** Format: misskey:id */
roleId: string; roleId: string;
name: string; name?: string;
description: string; description?: string;
color: string | null; color?: string | null;
iconUrl: string | null; iconUrl?: string | null;
/** @enum {string} */ /** @enum {string} */
target: 'manual' | 'conditional'; target?: 'manual' | 'conditional';
condFormula: Record<string, never>; condFormula?: Record<string, never>;
isPublic: boolean; isPublic?: boolean;
isModerator: boolean; isModerator?: boolean;
isAdministrator: boolean; isAdministrator?: boolean;
isExplorable?: boolean; isExplorable?: boolean;
asBadge: boolean; asBadge?: boolean;
canEditMembersByModerator: boolean; canEditMembersByModerator?: boolean;
displayOrder: number; displayOrder?: number;
policies: Record<string, never>; policies?: Record<string, never>;
}; };
}; };
}; };
@ -13400,7 +13400,7 @@ export type operations = {
'application/json': { 'application/json': {
/** Format: misskey:id */ /** Format: misskey:id */
clipId: string; clipId: string;
name: string; name?: string;
isPublic?: boolean; isPublic?: boolean;
description?: string | null; description?: string | null;
}; };
@ -16247,9 +16247,9 @@ export type operations = {
'application/json': { 'application/json': {
/** Format: misskey:id */ /** Format: misskey:id */
postId: string; postId: string;
title: string; title?: string;
description?: string | null; description?: string | null;
fileIds: string[]; fileIds?: string[];
/** @default false */ /** @default false */
isSensitive?: boolean; isSensitive?: boolean;
}; };
@ -20030,12 +20030,11 @@ export type operations = {
'application/json': { 'application/json': {
/** Format: misskey:id */ /** Format: misskey:id */
webhookId: string; webhookId: string;
name: string; name?: string;
url: string; url?: string;
/** @default */ secret?: string | null;
secret?: string; on?: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction')[];
on: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction')[]; active?: boolean;
active: boolean;
}; };
}; };
}; };
@ -23404,16 +23403,16 @@ export type operations = {
'application/json': { 'application/json': {
/** Format: misskey:id */ /** Format: misskey:id */
pageId: string; pageId: string;
title: string; title?: string;
name: string; name?: string;
summary?: string | null; summary?: string | null;
content: { content?: {
[key: string]: unknown; [key: string]: unknown;
}[]; }[];
variables: { variables?: {
[key: string]: unknown; [key: string]: unknown;
}[]; }[];
script: string; script?: string;
/** Format: misskey:id */ /** Format: misskey:id */
eyeCatchingImageId?: string | null; eyeCatchingImageId?: string | null;
/** @enum {string} */ /** @enum {string} */