diff --git a/dictation_server/src/api/odms/openapi.json b/dictation_server/src/api/odms/openapi.json index ce07f3b..eb999e6 100644 --- a/dictation_server/src/api/odms/openapi.json +++ b/dictation_server/src/api/odms/openapi.json @@ -3368,6 +3368,59 @@ "security": [{ "bearer": [] }] } }, + "/templates/{templateFileId}/delete": { + "post": { + "operationId": "deleteTemplateFile", + "summary": "", + "description": "ログインしているユーザーのアカウント配下でIDで指定されたテンプレートファイルを削除します", + "parameters": [ + { + "name": "templateFileId", + "required": true, + "in": "path", + "schema": { "type": "number" } + } + ], + "responses": { + "200": { + "description": "成功時のレスポンス", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteTemplateResponse" + } + } + } + }, + "400": { + "description": "ルーティングルールに設定されている / 未完了タスクに紐づいている / 削除済み", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ErrorResponse" } + } + } + }, + "401": { + "description": "認証エラー", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ErrorResponse" } + } + } + }, + "500": { + "description": "想定外のサーバーエラー", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ErrorResponse" } + } + } + } + }, + "tags": ["templates"], + "security": [{ "bearer": [] }] + } + }, "/workflows": { "get": { "operationId": "getWorkflows", @@ -4918,6 +4971,7 @@ }, "required": ["templates"] }, + "DeleteTemplateResponse": { "type": "object", "properties": {} }, "WorkflowWorktype": { "type": "object", "properties": { diff --git a/dictation_server/src/features/templates/templates.controller.ts b/dictation_server/src/features/templates/templates.controller.ts index d07db64..f4dce06 100644 --- a/dictation_server/src/features/templates/templates.controller.ts +++ b/dictation_server/src/features/templates/templates.controller.ts @@ -4,6 +4,8 @@ import { HttpException, HttpStatus, Logger, + Param, + Post, Req, UseGuards, } from '@nestjs/common'; @@ -16,7 +18,7 @@ import { import jwt from 'jsonwebtoken'; import { AccessToken } from '../../common/token'; import { ErrorResponse } from '../../common/error/types/types'; -import { GetTemplatesResponse } from './types/types'; +import { DeleteTemplateRequestParam, DeleteTemplateResponse, GetTemplatesResponse } from './types/types'; import { AuthGuard } from '../../common/guards/auth/authguards'; import { RoleGuard } from '../../common/guards/role/roleguards'; import { ADMIN_ROLES } from '../../constants'; @@ -97,4 +99,83 @@ export class TemplatesController { return { templates }; } + + @ApiResponse({ + status: HttpStatus.OK, + type: DeleteTemplateResponse, + description: '成功時のレスポンス', + }) + @ApiResponse({ + status: HttpStatus.BAD_REQUEST, + description: + 'ルーティングルールに設定されている / 未完了タスクに紐づいている / 削除済み', + type: ErrorResponse, + }) + @ApiResponse({ + status: HttpStatus.UNAUTHORIZED, + description: '認証エラー', + type: ErrorResponse, + }) + @ApiResponse({ + status: HttpStatus.INTERNAL_SERVER_ERROR, + description: '想定外のサーバーエラー', + type: ErrorResponse, + }) + @ApiOperation({ + operationId: 'deleteTemplateFile', + description: + 'ログインしているユーザーのアカウント配下でIDで指定されたテンプレートファイルを削除します', + }) + @ApiBearerAuth() + @UseGuards(AuthGuard) + @UseGuards( + RoleGuard.requireds({ roles: [ADMIN_ROLES.ADMIN], delegation: true }), + ) + @Post(':templateFileId/delete') + async deleteTypistGroup( + @Req() req: Request, + @Param() param: DeleteTemplateRequestParam, + ): Promise { + const { templateFileId } = param; + + // アクセストークン取得 + const accessToken = retrieveAuthorizationToken(req); + if (!accessToken) { + throw new HttpException( + makeErrorResponse('E000107'), + HttpStatus.UNAUTHORIZED, + ); + } + + const ip = retrieveIp(req); + if (!ip) { + throw new HttpException( + makeErrorResponse('E000401'), + HttpStatus.UNAUTHORIZED, + ); + } + + const requestId = retrieveRequestId(req); + if (!requestId) { + throw new HttpException( + makeErrorResponse('E000501'), + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + const decodedAccessToken = jwt.decode(accessToken, { json: true }); + if (!decodedAccessToken) { + throw new HttpException( + makeErrorResponse('E000101'), + HttpStatus.UNAUTHORIZED, + ); + } + const { userId } = decodedAccessToken as AccessToken; + + const context = makeContext(userId, requestId); + this.logger.log(`[${context.getTrackingId()}] ip : ${ip}`); + + // TODO: service層呼び出し + + return {}; + } } diff --git a/dictation_server/src/features/templates/types/types.ts b/dictation_server/src/features/templates/types/types.ts index 243298d..a3ca106 100644 --- a/dictation_server/src/features/templates/types/types.ts +++ b/dictation_server/src/features/templates/types/types.ts @@ -1,4 +1,6 @@ import { ApiProperty } from '@nestjs/swagger'; +import { Type } from 'class-transformer'; +import { IsInt, Min } from 'class-validator'; export class TemplateFile { @ApiProperty({ description: 'テンプレートファイルのID' }) @@ -14,3 +16,14 @@ export class GetTemplatesResponse { }) templates: TemplateFile[]; } + + +export class DeleteTemplateRequestParam { + @ApiProperty() + @Type(() => Number) + @IsInt() + @Min(1) + templateFileId: number; +} + +export class DeleteTemplateResponse {}