From 728bd6dfebe650a36a6a0fbbc10e6f4a9a74d1b3 Mon Sep 17 00:00:00 2001 From: "makabe.t" Date: Tue, 25 Apr 2023 01:56:40 +0000 Subject: [PATCH] =?UTF-8?q?Merged=20PR=2087:=20IF=E5=AE=9F=E8=A3=85?= =?UTF-8?q?=EF=BC=88=E3=83=86=E3=83=B3=E3=83=97=E3=83=AC=E3=83=BC=E3=83=88?= =?UTF-8?q?=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB=E3=83=80=E3=82=A6=E3=83=B3?= =?UTF-8?q?=E3=83=AD=E3=83=BC=E3=83=89=E5=85=88=E5=8F=96=E5=BE=97API/?= =?UTF-8?q?=E6=AC=A1=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB=E6=83=85=E5=A0=B1?= =?UTF-8?q?=E5=8F=96=E5=BE=97=E8=A6=81=E6=B1=82API=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 概要 [Task1646: IF実装(テンプレートファイルダウンロード先取得API/次ファイル情報取得要求API)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/1646) - 以下の外部連携APIのIFを実装しました。 - テンプレートファイルダウンロード先取得API - 次ファイル情報取得要求AP ## レビューポイント - 次ファイル情報取得要求APIについてFilesフォルダを掘って新規に追加したがフォルダ構成に問題はないか。 - IFの応答ステータスは適切か。 - リクエスト/レスポンスは想定通りか ## UIの変更 - なし ## 動作確認状況 - ローカルで確認Swaggerで確認 --- dictation_server/src/api/odms/openapi.json | 129 ++++++++++++++++++ dictation_server/src/app.module.ts | 6 + .../src/features/blob/blob.controller.ts | 31 +++++ .../src/features/blob/types/types.ts | 10 ++ .../features/files/files.controller.spec.ts | 23 ++++ .../src/features/files/files.controller.ts | 44 ++++++ .../src/features/files/files.module.ts | 9 ++ .../src/features/files/files.service.spec.ts | 18 +++ .../src/features/files/files.service.ts | 4 + .../src/features/files/types/types.ts | 11 ++ 10 files changed, 285 insertions(+) create mode 100644 dictation_server/src/features/files/files.controller.spec.ts create mode 100644 dictation_server/src/features/files/files.controller.ts create mode 100644 dictation_server/src/features/files/files.module.ts create mode 100644 dictation_server/src/features/files/files.service.spec.ts create mode 100644 dictation_server/src/features/files/files.service.ts create mode 100644 dictation_server/src/features/files/types/types.ts diff --git a/dictation_server/src/api/odms/openapi.json b/dictation_server/src/api/odms/openapi.json index 68ba4dd..08bd350 100644 --- a/dictation_server/src/api/odms/openapi.json +++ b/dictation_server/src/api/odms/openapi.json @@ -463,6 +463,61 @@ ] } }, + "/files/audio/next": { + "get": { + "operationId": "getNextAudioFile", + "summary": "", + "parameters": [ + { + "name": "endedFileId", + "required": true, + "in": "query", + "description": "文字起こし完了したタスクの音声ファイルID", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "成功時のレスポンス", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AudioNextResponse" + } + } + } + }, + "401": { + "description": "認証エラー", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "想定外のサーバーエラー", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "tags": ["files"], + "security": [ + { + "bearer": [] + } + ] + } + }, "/notification/register": { "post": { "operationId": "register", @@ -627,6 +682,61 @@ } ] } + }, + "/files/template/download-location": { + "get": { + "operationId": "downloadTemplateLocation", + "summary": "", + "parameters": [ + { + "name": "audioFileId", + "required": true, + "in": "query", + "description": "文字起こし対象の音声ファイルID", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "成功時のレスポンス", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TemplateDownloadLocationResponse" + } + } + } + }, + "401": { + "description": "認証エラー", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "想定外のサーバーエラー", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "tags": ["files"], + "security": [ + { + "bearer": [] + } + ] + } } }, "info": { @@ -1039,6 +1149,16 @@ "prompt" ] }, + "AudioNextResponse": { + "type": "object", + "properties": { + "nextFileId": { + "type": "string", + "description": "OMDS Cloud上の次の音声ファイルID" + } + }, + "required": ["nextFileId"] + }, "RegisterRequest": { "type": "object", "properties": { @@ -1074,6 +1194,15 @@ } }, "required": ["url"] + }, + "TemplateDownloadLocationResponse": { + "type": "object", + "properties": { + "url": { + "type": "string" + } + }, + "required": ["url"] } } } diff --git a/dictation_server/src/app.module.ts b/dictation_server/src/app.module.ts index 671893c..5e4be5c 100644 --- a/dictation_server/src/app.module.ts +++ b/dictation_server/src/app.module.ts @@ -23,6 +23,9 @@ import { NotificationhubModule } from './gateways/notificationhub/notificationhu import { NotificationhubService } from './gateways/notificationhub/notificationhub.service'; import { NotificationModule } from './features/notification/notification.module'; import { BlobModule } from './features/blob/blob.module'; +import { FilesModule } from './features/files/files.module'; +import { FilesController } from './features/files/files.controller'; +import { FilesService } from './features/files/files.service'; import { TaskController } from './features/task/task.controller'; import { TaskService } from './features/task/task.service'; import { TaskModule } from './features/task/task.module'; @@ -42,6 +45,7 @@ import { TaskModule } from './features/task/task.module'; AccountsModule, TaskModule, UsersModule, + FilesModule, SendGridModule, AccountsRepositoryModule, UsersRepositoryModule, @@ -69,6 +73,7 @@ import { TaskModule } from './features/task/task.module'; AccountsController, TaskController, UsersController, + FilesController, ], providers: [ AuthService, @@ -76,6 +81,7 @@ import { TaskModule } from './features/task/task.module'; TaskService, UsersService, NotificationhubService, + FilesService, ], }) export class AppModule { diff --git a/dictation_server/src/features/blob/blob.controller.ts b/dictation_server/src/features/blob/blob.controller.ts index e0b7b85..b33d64a 100644 --- a/dictation_server/src/features/blob/blob.controller.ts +++ b/dictation_server/src/features/blob/blob.controller.ts @@ -12,6 +12,8 @@ import { AudioUploadLocationRequest, AudioDownloadLocationResponse, AudioDownloadLocationRequest, + TemplateDownloadLocationResponse, + TemplateDownloadLocationRequest, } from './types/types'; @ApiTags('files') @@ -76,4 +78,33 @@ export class BlobController { return { url: '' }; } + + @Get('template/download-location') + @ApiResponse({ + status: HttpStatus.OK, + type: TemplateDownloadLocationResponse, + description: '成功時のレスポンス', + }) + @ApiResponse({ + status: HttpStatus.UNAUTHORIZED, + description: '認証エラー', + type: ErrorResponse, + }) + @ApiResponse({ + status: HttpStatus.INTERNAL_SERVER_ERROR, + description: '想定外のサーバーエラー', + type: ErrorResponse, + }) + @ApiOperation({ operationId: 'downloadTemplateLocation' }) + @ApiBearerAuth() + async downloadTemplateLocation( + @Headers() headers, + @Query() body: TemplateDownloadLocationRequest, + ): Promise { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { audioFileId } = body; + // コンテナ作成処理の前にアクセストークンの認証を行う + + return { url: '' }; + } } diff --git a/dictation_server/src/features/blob/types/types.ts b/dictation_server/src/features/blob/types/types.ts index aec5d42..6a6ca51 100644 --- a/dictation_server/src/features/blob/types/types.ts +++ b/dictation_server/src/features/blob/types/types.ts @@ -16,3 +16,13 @@ export class AudioDownloadLocationResponse { @ApiProperty() url: string; } + +export class TemplateDownloadLocationRequest { + @ApiProperty({ description: '文字起こし対象の音声ファイルID' }) + audioFileId: string; +} + +export class TemplateDownloadLocationResponse { + @ApiProperty() + url: string; +} diff --git a/dictation_server/src/features/files/files.controller.spec.ts b/dictation_server/src/features/files/files.controller.spec.ts new file mode 100644 index 0000000..4e79c99 --- /dev/null +++ b/dictation_server/src/features/files/files.controller.spec.ts @@ -0,0 +1,23 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { FilesController } from './files.controller'; +import { FilesService } from './files.service'; + +describe('FilesController', () => { + let controller: FilesController; + const mockFilesService = {}; + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [FilesController], + providers: [FilesService], + }) + .overrideProvider(FilesService) + .useValue(mockFilesService) + .compile(); + + controller = module.get(FilesController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/dictation_server/src/features/files/files.controller.ts b/dictation_server/src/features/files/files.controller.ts new file mode 100644 index 0000000..1d104f6 --- /dev/null +++ b/dictation_server/src/features/files/files.controller.ts @@ -0,0 +1,44 @@ +import { Controller, Get, Headers, HttpStatus, Query } from '@nestjs/common'; +import { + ApiResponse, + ApiOperation, + ApiBearerAuth, + ApiTags, +} from '@nestjs/swagger'; +import { ErrorResponse } from '../../common/error/types/types'; +import { FilesService } from './files.service'; +import { AudioNextRequest, AudioNextResponse } from './types/types'; + +@ApiTags('files') +@Controller('files') +export class FilesController { + constructor(private readonly filesService: FilesService) {} + + @Get('audio/next') + @ApiResponse({ + status: HttpStatus.OK, + type: AudioNextResponse, + description: '成功時のレスポンス', + }) + @ApiResponse({ + status: HttpStatus.UNAUTHORIZED, + description: '認証エラー', + type: ErrorResponse, + }) + @ApiResponse({ + status: HttpStatus.INTERNAL_SERVER_ERROR, + description: '想定外のサーバーエラー', + type: ErrorResponse, + }) + @ApiOperation({ operationId: 'getNextAudioFile' }) + @ApiBearerAuth() + async getNextAudioFile( + @Headers() headers, + @Query() body: AudioNextRequest, + ): Promise { + const { endedFileId } = body; + console.log(endedFileId); + + return { nextFileId: '1234' }; + } +} diff --git a/dictation_server/src/features/files/files.module.ts b/dictation_server/src/features/files/files.module.ts new file mode 100644 index 0000000..97b6f58 --- /dev/null +++ b/dictation_server/src/features/files/files.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { FilesService } from './files.service'; +import { FilesController } from './files.controller'; + +@Module({ + providers: [FilesService], + controllers: [FilesController], +}) +export class FilesModule {} diff --git a/dictation_server/src/features/files/files.service.spec.ts b/dictation_server/src/features/files/files.service.spec.ts new file mode 100644 index 0000000..c653b32 --- /dev/null +++ b/dictation_server/src/features/files/files.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { FilesService } from './files.service'; + +describe('FilesService', () => { + let service: FilesService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [FilesService], + }).compile(); + + service = module.get(FilesService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/dictation_server/src/features/files/files.service.ts b/dictation_server/src/features/files/files.service.ts new file mode 100644 index 0000000..ab8a4e6 --- /dev/null +++ b/dictation_server/src/features/files/files.service.ts @@ -0,0 +1,4 @@ +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class FilesService {} diff --git a/dictation_server/src/features/files/types/types.ts b/dictation_server/src/features/files/types/types.ts new file mode 100644 index 0000000..782f554 --- /dev/null +++ b/dictation_server/src/features/files/types/types.ts @@ -0,0 +1,11 @@ +import { ApiProperty } from '@nestjs/swagger'; + +export class AudioNextRequest { + @ApiProperty({ description: '文字起こし完了したタスクの音声ファイルID' }) + endedFileId: string; +} + +export class AudioNextResponse { + @ApiProperty({ description: 'OMDS Cloud上の次の音声ファイルID' }) + nextFileId: string; +}