From 028e7c00ae91a76407029004eeba5145823edd46 Mon Sep 17 00:00:00 2001 From: tamaina Date: Fri, 16 Jun 2023 06:40:54 +0000 Subject: [PATCH] =?UTF-8?q?=E7=A7=BB=E8=A1=8C=E4=BD=9C=E6=A5=AD=E5=86=8D?= =?UTF-8?q?=E9=96=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/endpoints/drive/files/delete.ts | 41 +--- .../api/endpoints/drive/files/find-by-hash.ts | 33 +-- .../server/api/endpoints/drive/files/find.ts | 34 +-- .../server/api/endpoints/drive/files/show.ts | 51 +--- .../api/endpoints/drive/files/update.ts | 74 +----- .../endpoints/drive/files/upload-from-url.ts | 35 +-- packages/misskey-js/src/endpoints.ts | 219 ++++++++++++++++++ 7 files changed, 246 insertions(+), 241 deletions(-) diff --git a/packages/backend/src/server/api/endpoints/drive/files/delete.ts b/packages/backend/src/server/api/endpoints/drive/files/delete.ts index 2ced97ee02..5fada91b54 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/delete.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/delete.ts @@ -7,41 +7,10 @@ import { DI } from '@/di-symbols.js'; import { RoleService } from '@/core/RoleService.js'; import { ApiError } from '../../../error.js'; -export const meta = { - tags: ['drive'], - - requireCredential: true, - - kind: 'write:drive', - - description: 'Delete an existing drive file.', - - errors: { - noSuchFile: { - message: 'No such file.', - code: 'NO_SUCH_FILE', - id: '908939ec-e52b-4458-b395-1025195cea58', - }, - - accessDenied: { - message: 'Access denied.', - code: 'ACCESS_DENIED', - id: '5eb8d909-2540-4970-90b8-dd6f86088121', - }, - }, -} as const; - -export const paramDef = { - type: 'object', - properties: { - fileId: { type: 'string', format: 'misskey:id' }, - }, - required: ['fileId'], -} as const; - // eslint-disable-next-line import/no-default-export @Injectable() -export default class extends Endpoint { +export default class extends Endpoint<'drive/files/delete'> { + name = 'drive/files/delete' as const; constructor( @Inject(DI.driveFilesRepository) private driveFilesRepository: DriveFilesRepository, @@ -50,15 +19,15 @@ export default class extends Endpoint { private roleService: RoleService, private globalEventService: GlobalEventService, ) { - super(meta, paramDef, async (ps, me) => { + super(async (ps, me) => { const file = await this.driveFilesRepository.findOneBy({ id: ps.fileId }); if (file == null) { - throw new ApiError(meta.errors.noSuchFile); + throw new ApiError(this.meta.errors.noSuchFile); } if (!await this.roleService.isModerator(me) && (file.userId !== me.id)) { - throw new ApiError(meta.errors.accessDenied); + throw new ApiError(this.meta.errors.accessDenied); } // Delete diff --git a/packages/backend/src/server/api/endpoints/drive/files/find-by-hash.ts b/packages/backend/src/server/api/endpoints/drive/files/find-by-hash.ts index d6d85f4e77..fcc7394cf3 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/find-by-hash.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/find-by-hash.ts @@ -4,44 +4,17 @@ import { Endpoint } from '@/server/api/endpoint-base.js'; import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js'; import { DI } from '@/di-symbols.js'; -export const meta = { - tags: ['drive'], - - requireCredential: true, - - kind: 'read:drive', - - description: 'Search for a drive file by a hash of the contents.', - - res: { - type: 'array', - optional: false, nullable: false, - items: { - type: 'object', - optional: false, nullable: false, - ref: 'DriveFile', - }, - }, -} as const; - -export const paramDef = { - type: 'object', - properties: { - md5: { type: 'string' }, - }, - required: ['md5'], -} as const; - // eslint-disable-next-line import/no-default-export @Injectable() -export default class extends Endpoint { +export default class extends Endpoint<'drive/files/find-by-hash'> { + name = 'drive/files/find-by-hash' as const; constructor( @Inject(DI.driveFilesRepository) private driveFilesRepository: DriveFilesRepository, private driveFileEntityService: DriveFileEntityService, ) { - super(meta, paramDef, async (ps, me) => { + super(async (ps, me) => { const files = await this.driveFilesRepository.findBy({ md5: ps.md5, userId: me.id, diff --git a/packages/backend/src/server/api/endpoints/drive/files/find.ts b/packages/backend/src/server/api/endpoints/drive/files/find.ts index 858063eb4b..00629b92ad 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/find.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/find.ts @@ -5,45 +5,17 @@ import type { DriveFilesRepository } from '@/models/index.js'; import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js'; import { DI } from '@/di-symbols.js'; -export const meta = { - requireCredential: true, - - tags: ['drive'], - - kind: 'read:drive', - - description: 'Search for a drive file by the given parameters.', - - res: { - type: 'array', - optional: false, nullable: false, - items: { - type: 'object', - optional: false, nullable: false, - ref: 'DriveFile', - }, - }, -} as const; - -export const paramDef = { - type: 'object', - properties: { - name: { type: 'string' }, - folderId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, - }, - required: ['name'], -} as const; - // eslint-disable-next-line import/no-default-export @Injectable() -export default class extends Endpoint { +export default class extends Endpoint<'drive/files/find'> { + name = 'drive/files/find' as const; constructor( @Inject(DI.driveFilesRepository) private driveFilesRepository: DriveFilesRepository, private driveFileEntityService: DriveFileEntityService, ) { - super(meta, paramDef, async (ps, me) => { + super(async (ps, me) => { const files = await this.driveFilesRepository.findBy({ name: ps.name, userId: me.id, diff --git a/packages/backend/src/server/api/endpoints/drive/files/show.ts b/packages/backend/src/server/api/endpoints/drive/files/show.ts index 271b33ef4b..6abfcb8c7d 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/show.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/show.ts @@ -7,51 +7,10 @@ import { DI } from '@/di-symbols.js'; import { RoleService } from '@/core/RoleService.js'; import { ApiError } from '../../../error.js'; -export const meta = { - tags: ['drive'], - - requireCredential: true, - - kind: 'read:drive', - - description: 'Show the properties of a drive file.', - - res: { - type: 'object', - optional: false, nullable: false, - ref: 'DriveFile', - }, - - errors: { - noSuchFile: { - message: 'No such file.', - code: 'NO_SUCH_FILE', - id: '067bc436-2718-4795-b0fb-ecbe43949e31', - }, - - accessDenied: { - message: 'Access denied.', - code: 'ACCESS_DENIED', - id: '25b73c73-68b1-41d0-bad1-381cfdf6579f', - }, - }, -} as const; - -export const paramDef = { - type: 'object', - properties: { - fileId: { type: 'string', format: 'misskey:id' }, - url: { type: 'string' }, - }, - anyOf: [ - { required: ['fileId'] }, - { required: ['url'] }, - ], -} as const; - // eslint-disable-next-line import/no-default-export @Injectable() -export default class extends Endpoint { +export default class extends Endpoint<'drive/files/show'> { + name = 'drive/files/show' as const; constructor( @Inject(DI.driveFilesRepository) private driveFilesRepository: DriveFilesRepository, @@ -59,7 +18,7 @@ export default class extends Endpoint { private driveFileEntityService: DriveFileEntityService, private roleService: RoleService, ) { - super(meta, paramDef, async (ps, me) => { + super(async (ps, me) => { let file: DriveFile | null = null; if (ps.fileId) { @@ -77,11 +36,11 @@ export default class extends Endpoint { } if (file == null) { - throw new ApiError(meta.errors.noSuchFile); + throw new ApiError(this.meta.errors.noSuchFile); } if (!await this.roleService.isModerator(me) && (file.userId !== me.id)) { - throw new ApiError(meta.errors.accessDenied); + throw new ApiError(this.meta.errors.accessDenied); } return await this.driveFileEntityService.pack(file, { diff --git a/packages/backend/src/server/api/endpoints/drive/files/update.ts b/packages/backend/src/server/api/endpoints/drive/files/update.ts index 3ecbba22b5..4333e21848 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/update.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/update.ts @@ -7,68 +7,10 @@ import { DI } from '@/di-symbols.js'; import { RoleService } from '@/core/RoleService.js'; import { ApiError } from '../../../error.js'; -export const meta = { - tags: ['drive'], - - requireCredential: true, - - kind: 'write:drive', - - description: 'Update the properties of a drive file.', - - errors: { - invalidFileName: { - message: 'Invalid file name.', - code: 'INVALID_FILE_NAME', - id: '395e7156-f9f0-475e-af89-53c3c23080c2', - }, - - noSuchFile: { - message: 'No such file.', - code: 'NO_SUCH_FILE', - id: 'e7778c7e-3af9-49cd-9690-6dbc3e6c972d', - }, - - accessDenied: { - message: 'Access denied.', - code: 'ACCESS_DENIED', - id: '01a53b27-82fc-445b-a0c1-b558465a8ed2', - }, - - noSuchFolder: { - message: 'No such folder.', - code: 'NO_SUCH_FOLDER', - id: 'ea8fb7a5-af77-4a08-b608-c0218176cd73', - }, - - restrictedByRole: { - message: 'This feature is restricted by your role.', - code: 'RESTRICTED_BY_ROLE', - id: '7f59dccb-f465-75ab-5cf4-3ce44e3282f7', - }, - }, - res: { - type: 'object', - optional: false, nullable: false, - ref: 'DriveFile', - }, -} as const; - -export const paramDef = { - type: 'object', - properties: { - fileId: { type: 'string', format: 'misskey:id' }, - folderId: { type: 'string', format: 'misskey:id', nullable: true }, - name: { type: 'string' }, - isSensitive: { type: 'boolean' }, - comment: { type: 'string', nullable: true, maxLength: 512 }, - }, - required: ['fileId'], -} as const; - // eslint-disable-next-line import/no-default-export @Injectable() -export default class extends Endpoint { +export default class extends Endpoint<'drive/files/update'> { + name = 'drive/files/update' as const; constructor( @Inject(DI.driveFilesRepository) private driveFilesRepository: DriveFilesRepository, @@ -80,26 +22,26 @@ export default class extends Endpoint { private roleService: RoleService, private globalEventService: GlobalEventService, ) { - super(meta, paramDef, async (ps, me) => { + super(async (ps, me) => { const file = await this.driveFilesRepository.findOneBy({ id: ps.fileId }); const alwaysMarkNsfw = (await this.roleService.getUserPolicies(me.id)).alwaysMarkNsfw; if (file == null) { - throw new ApiError(meta.errors.noSuchFile); + throw new ApiError(this.meta.errors.noSuchFile); } if (!await this.roleService.isModerator(me) && (file.userId !== me.id)) { - throw new ApiError(meta.errors.accessDenied); + throw new ApiError(this.meta.errors.accessDenied); } if (ps.name) file.name = ps.name; if (!this.driveFileEntityService.validateFileName(file.name)) { - throw new ApiError(meta.errors.invalidFileName); + throw new ApiError(this.meta.errors.invalidFileName); } if (ps.comment !== undefined) file.comment = ps.comment; if (ps.isSensitive !== undefined && ps.isSensitive !== file.isSensitive && alwaysMarkNsfw && !ps.isSensitive) { - throw new ApiError(meta.errors.restrictedByRole); + throw new ApiError(this.meta.errors.restrictedByRole); } if (ps.isSensitive !== undefined) file.isSensitive = ps.isSensitive; @@ -114,7 +56,7 @@ export default class extends Endpoint { }); if (folder == null) { - throw new ApiError(meta.errors.noSuchFolder); + throw new ApiError(this.meta.errors.noSuchFolder); } file.folderId = folder.id; diff --git a/packages/backend/src/server/api/endpoints/drive/files/upload-from-url.ts b/packages/backend/src/server/api/endpoints/drive/files/upload-from-url.ts index c835587c4a..bf94c6a5f5 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/upload-from-url.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/upload-from-url.ts @@ -7,39 +7,10 @@ import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.j import { DriveService } from '@/core/DriveService.js'; import { DI } from '@/di-symbols.js'; -export const meta = { - tags: ['drive'], - - limit: { - duration: ms('1hour'), - max: 60, - }, - - description: 'Request the server to download a new drive file from the specified URL.', - - requireCredential: true, - - prohibitMoved: true, - - kind: 'write:drive', -} as const; - -export const paramDef = { - type: 'object', - properties: { - url: { type: 'string' }, - folderId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, - isSensitive: { type: 'boolean', default: false }, - comment: { type: 'string', nullable: true, maxLength: 512, default: null }, - marker: { type: 'string', nullable: true, default: null }, - force: { type: 'boolean', default: false }, - }, - required: ['url'], -} as const; - // eslint-disable-next-line import/no-default-export @Injectable() -export default class extends Endpoint { +export default class extends Endpoint<'drive/files/upload-from-url'> { + name = 'drive/files/upload-from-url' as const; constructor( @Inject(DI.driveFilesRepository) private driveFilesRepository: DriveFilesRepository, @@ -48,7 +19,7 @@ export default class extends Endpoint { private driveService: DriveService, private globalEventService: GlobalEventService, ) { - super(meta, paramDef, async (ps, user, _1, _2, _3, ip, headers) => { + super(async (ps, user, _1, _2, _3, ip, headers) => { this.driveService.uploadFromUrl({ url: ps.url, user, folderId: ps.folderId, sensitive: ps.isSensitive, force: ps.force, comment: ps.comment, requestIp: ip, requestHeaders: headers }).then(file => { this.driveFileEntityService.pack(file, { self: true }).then(packedFile => { this.globalEventService.publishMainStream(user.id, 'urlUploadFinished', { diff --git a/packages/misskey-js/src/endpoints.ts b/packages/misskey-js/src/endpoints.ts index 64c792748b..b694941459 100644 --- a/packages/misskey-js/src/endpoints.ts +++ b/packages/misskey-js/src/endpoints.ts @@ -3695,6 +3695,225 @@ export const endpoints = { }, }], }, + 'drive/files/delete': { + tags: ['drive'], + + requireCredential: true, + + kind: 'write:drive', + + description: 'Delete an existing drive file.', + + errors: { + noSuchFile: { + message: 'No such file.', + code: 'NO_SUCH_FILE', + id: '908939ec-e52b-4458-b395-1025195cea58', + }, + + accessDenied: { + message: 'Access denied.', + code: 'ACCESS_DENIED', + id: '5eb8d909-2540-4970-90b8-dd6f86088121', + }, + }, + + defines: [{ + req: { + type: 'object', + properties: { + fileId: { type: 'string', format: 'misskey:id' }, + }, + required: ['fileId'], + }, + res: undefined, + }], + }, + 'drive/files/find-by-hash': { + tags: ['drive'], + + requireCredential: true, + + kind: 'read:drive', + + description: 'Search for a drive file by a hash of the contents.', + + defines: [{ + req: { + type: 'object', + properties: { + md5: { type: 'string' }, + }, + required: ['md5'], + }, + res: { + type: 'array', + items: { + $ref: 'https://misskey-hub.net/api/schemas/DriveFile', + }, + }, + }], + }, + 'drive/files/find': { + requireCredential: true, + + tags: ['drive'], + + kind: 'read:drive', + + description: 'Search for a drive file by the given parameters.', + + defines: [{ + req: { + type: 'object', + properties: { + name: { type: 'string' }, + folderId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, + }, + required: ['name'], + }, + res: { + type: 'array', + items: { + $ref: 'https://misskey-hub.net/api/schemas/DriveFile', + }, + }, + }], + }, + 'drive/files/show': { + tags: ['drive'], + + requireCredential: true, + + kind: 'read:drive', + + description: 'Show the properties of a drive file.', + + errors: { + noSuchFile: { + message: 'No such file.', + code: 'NO_SUCH_FILE', + id: '067bc436-2718-4795-b0fb-ecbe43949e31', + }, + + accessDenied: { + message: 'Access denied.', + code: 'ACCESS_DENIED', + id: '25b73c73-68b1-41d0-bad1-381cfdf6579f', + }, + }, + + defines: [{ + req: { + type: 'object', + properties: { + fileId: { type: 'string', format: 'misskey:id' }, + url: { type: 'string' }, + }, + anyOf: [ + { required: ['fileId'] }, + { required: ['url'] }, + ], + }, + res: { + $ref: 'https://misskey-hub.net/api/schemas/DriveFile', + }, + }], + }, + 'drive/files/update': { + tags: ['drive'], + + requireCredential: true, + + kind: 'write:drive', + + description: 'Update the properties of a drive file.', + + errors: { + invalidFileName: { + message: 'Invalid file name.', + code: 'INVALID_FILE_NAME', + id: '395e7156-f9f0-475e-af89-53c3c23080c2', + }, + + noSuchFile: { + message: 'No such file.', + code: 'NO_SUCH_FILE', + id: 'e7778c7e-3af9-49cd-9690-6dbc3e6c972d', + }, + + accessDenied: { + message: 'Access denied.', + code: 'ACCESS_DENIED', + id: '01a53b27-82fc-445b-a0c1-b558465a8ed2', + }, + + noSuchFolder: { + message: 'No such folder.', + code: 'NO_SUCH_FOLDER', + id: 'ea8fb7a5-af77-4a08-b608-c0218176cd73', + }, + + restrictedByRole: { + message: 'This feature is restricted by your role.', + code: 'RESTRICTED_BY_ROLE', + id: '7f59dccb-f465-75ab-5cf4-3ce44e3282f7', + }, + }, + defines: [{ + req: { + type: 'object', + properties: { + fileId: { type: 'string', format: 'misskey:id' }, + folderId: { type: 'string', format: 'misskey:id', nullable: true }, + name: { type: 'string' }, + isSensitive: { type: 'boolean' }, + comment: { + oneOf: [ + { type: 'string', maxLength: 512 }, + { type: 'null' }, + ], + }, + }, + required: ['fileId'], + }, + res: { + $ref: 'https://misskey-hub.net/api/schemas/DriveFile', + }, + }], + }, + 'drive/files/upload-from-url': { + tags: ['drive'], + + limit: { + duration: ms('1hour'), + max: 60, + }, + + description: 'Request the server to download a new drive file from the specified URL.', + + requireCredential: true, + + prohibitMoved: true, + + kind: 'write:drive', + + defines: [{ + req: { + type: 'object', + properties: { + url: { type: 'string' }, + folderId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, + isSensitive: { type: 'boolean', default: false }, + comment: { type: 'string', nullable: true, maxLength: 512, default: null }, + marker: { type: 'string', nullable: true, default: null }, + force: { type: 'boolean', default: false }, + }, + required: ['url'], + }, + res: undefined, + }], + }, //#endregion } as const satisfies { [x: string]: IEndpointMeta; };