diff --git a/dictation_server/package.json b/dictation_server/package.json index 0bab16e..e6f383f 100644 --- a/dictation_server/package.json +++ b/dictation_server/package.json @@ -8,8 +8,8 @@ "scripts": { "prebuild": "rimraf dist", "build": "nest build", - "apigen": "ts-node src/api/generate.ts", - "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", + "apigen": "ts-node src/api/generate.ts && prettier --write \"src/api/odms/*.json\"", + "format": "prettier --write \"src/**/*.ts\" \"src/api/odms/*.json\"", "start": "nest start", "start:dev": "nest start --watch", "start:debug": "nest start --debug --watch", diff --git a/dictation_server/src/api/generate.ts b/dictation_server/src/api/generate.ts index 80add8e..a2010e5 100644 --- a/dictation_server/src/api/generate.ts +++ b/dictation_server/src/api/generate.ts @@ -1,24 +1,12 @@ -// XXX 現状うまく動作しないため運用できない import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; -import { Test } from '@nestjs/testing'; import { AppModule } from '../app.module'; import { promises as fs } from 'fs'; +import { NestFactory } from '@nestjs/core'; async function bootstrap(): Promise { - const controllers = Reflect.getMetadata('controllers', AppModule); - const providers = Reflect.getMetadata('providers', AppModule); - const mockedProviders = providers.map((provider) => { - return { - provide: provider.name, - useValue: {}, - }; + const app = await NestFactory.create(AppModule, { + preview: true, }); - const testingModule = await Test.createTestingModule({ - controllers: controllers, - providers: mockedProviders, - }).compile(); - const app = testingModule.createNestApplication(); - const options = new DocumentBuilder() .setTitle('ODMSOpenAPI') .setVersion('1.0.0') @@ -32,7 +20,7 @@ async function bootstrap(): Promise { const document = SwaggerModule.createDocument(app, options); await fs.writeFile( 'src/api/odms/openapi.json', - JSON.stringify(document, null, 2), + JSON.stringify(document, null, 0), ); } bootstrap(); diff --git a/dictation_server/src/api/odms/openapi.json b/dictation_server/src/api/odms/openapi.json index 60460a3..a5a1a42 100644 --- a/dictation_server/src/api/odms/openapi.json +++ b/dictation_server/src/api/odms/openapi.json @@ -350,6 +350,88 @@ "tags": ["notification"], "security": [{ "bearer": [] }] } + }, + "/files/audio/upload-location": { + "get": { + "operationId": "uploadLocation", + "summary": "", + "parameters": [], + "responses": { + "200": { + "description": "成功時のレスポンス", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AudioUploadLocationResponse" + } + } + } + }, + "401": { + "description": "認証エラー", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ErrorResponse" } + } + } + }, + "500": { + "description": "想定外のサーバーエラー", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ErrorResponse" } + } + } + } + }, + "tags": ["files"], + "security": [{ "bearer": [] }] + } + }, + "/files/audio/download-location": { + "get": { + "operationId": "downloadLocation", + "summary": "", + "parameters": [ + { + "name": "id", + "required": true, + "in": "query", + "description": "音声ファイル情報をDBから取得するためのID", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "成功時のレスポンス", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AudioDownloadLocationResponse" + } + } + } + }, + "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": { @@ -508,7 +590,17 @@ }, "required": ["pns", "handler"] }, - "RegisterResponse": { "type": "object", "properties": {} } + "RegisterResponse": { "type": "object", "properties": {} }, + "AudioUploadLocationResponse": { + "type": "object", + "properties": { "url": { "type": "string" } }, + "required": ["url"] + }, + "AudioDownloadLocationResponse": { + "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 ab015fc..d01af52 100644 --- a/dictation_server/src/app.module.ts +++ b/dictation_server/src/app.module.ts @@ -22,6 +22,7 @@ import { UsersRepositoryModule } from './repositories/users/users.repository.mod import { NotificationhubModule } from './gateways/notificationhub/notificationhub.module'; import { NotificationhubService } from './gateways/notificationhub/notificationhub.service'; import { NotificationModule } from './features/notification/notification.module'; +import { BlobModule } from './features/blob/blob.module'; @Module({ imports: [ @@ -56,6 +57,7 @@ import { NotificationModule } from './features/notification/notification.module' }), NotificationModule, NotificationhubModule, + BlobModule, ], controllers: [ HealthController, diff --git a/dictation_server/src/features/blob/blob.controller.spec.ts b/dictation_server/src/features/blob/blob.controller.spec.ts new file mode 100644 index 0000000..d68d2c4 --- /dev/null +++ b/dictation_server/src/features/blob/blob.controller.spec.ts @@ -0,0 +1,23 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { BlobController } from './blob.controller'; +import { BlobService } from './blob.service'; + +describe('BlobController', () => { + let controller: BlobController; + const mockBlobService = {}; + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [BlobController], + providers: [BlobService], + }) + .overrideProvider(BlobService) + .useValue(mockBlobService) + .compile(); + + controller = module.get(BlobController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/dictation_server/src/features/blob/blob.controller.ts b/dictation_server/src/features/blob/blob.controller.ts new file mode 100644 index 0000000..e0b7b85 --- /dev/null +++ b/dictation_server/src/features/blob/blob.controller.ts @@ -0,0 +1,79 @@ +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 { BlobService } from './blob.service'; +import { + AudioUploadLocationResponse, + AudioUploadLocationRequest, + AudioDownloadLocationResponse, + AudioDownloadLocationRequest, +} from './types/types'; + +@ApiTags('files') +@Controller('files') +export class BlobController { + constructor(private readonly blobService: BlobService) {} + @Get('audio/upload-location') + @ApiResponse({ + status: HttpStatus.OK, + type: AudioUploadLocationResponse, + description: '成功時のレスポンス', + }) + @ApiResponse({ + status: HttpStatus.UNAUTHORIZED, + description: '認証エラー', + type: ErrorResponse, + }) + @ApiResponse({ + status: HttpStatus.INTERNAL_SERVER_ERROR, + description: '想定外のサーバーエラー', + type: ErrorResponse, + }) + @ApiOperation({ operationId: 'uploadLocation' }) + @ApiBearerAuth() + async uploadLocation( + @Headers() headers, + @Query() query: AudioUploadLocationRequest, + ): Promise { + const {} = query; + // コンテナ作成処理の前にアクセストークンの認証を行う + // アップロード先を決定する国情報はトークンから取得する想定 + + return { url: '' }; + } + + @Get('audio/download-location') + @ApiResponse({ + status: HttpStatus.OK, + type: AudioDownloadLocationResponse, + description: '成功時のレスポンス', + }) + @ApiResponse({ + status: HttpStatus.UNAUTHORIZED, + description: '認証エラー', + type: ErrorResponse, + }) + @ApiResponse({ + status: HttpStatus.INTERNAL_SERVER_ERROR, + description: '想定外のサーバーエラー', + type: ErrorResponse, + }) + @ApiOperation({ operationId: 'downloadLocation' }) + @ApiBearerAuth() + async downloadLocation( + @Headers() headers, + @Query() body: AudioDownloadLocationRequest, + ): Promise { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { id } = body; + // コンテナ作成処理の前にアクセストークンの認証を行う + // + + return { url: '' }; + } +} diff --git a/dictation_server/src/features/blob/blob.module.ts b/dictation_server/src/features/blob/blob.module.ts new file mode 100644 index 0000000..712a287 --- /dev/null +++ b/dictation_server/src/features/blob/blob.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { BlobService } from './blob.service'; +import { BlobController } from './blob.controller'; + +@Module({ + providers: [BlobService], + controllers: [BlobController], +}) +export class BlobModule {} diff --git a/dictation_server/src/features/blob/blob.service.spec.ts b/dictation_server/src/features/blob/blob.service.spec.ts new file mode 100644 index 0000000..8bd3902 --- /dev/null +++ b/dictation_server/src/features/blob/blob.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { BlobService } from './blob.service'; + +describe('BlobService', () => { + let service: BlobService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [BlobService], + }).compile(); + + service = module.get(BlobService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/dictation_server/src/features/blob/blob.service.ts b/dictation_server/src/features/blob/blob.service.ts new file mode 100644 index 0000000..4e17e41 --- /dev/null +++ b/dictation_server/src/features/blob/blob.service.ts @@ -0,0 +1,4 @@ +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BlobService {} diff --git a/dictation_server/src/features/blob/types/types.ts b/dictation_server/src/features/blob/types/types.ts new file mode 100644 index 0000000..aec5d42 --- /dev/null +++ b/dictation_server/src/features/blob/types/types.ts @@ -0,0 +1,18 @@ +import { ApiProperty } from '@nestjs/swagger'; + +export class AudioUploadLocationRequest {} + +export class AudioUploadLocationResponse { + @ApiProperty() + url: string; +} + +export class AudioDownloadLocationRequest { + @ApiProperty({ description: '音声ファイル情報をDBから取得するためのID' }) + id: string; +} + +export class AudioDownloadLocationResponse { + @ApiProperty() + url: string; +} diff --git a/dictation_server/src/features/notification/notification.module.ts b/dictation_server/src/features/notification/notification.module.ts index aba2de8..a59a046 100644 --- a/dictation_server/src/features/notification/notification.module.ts +++ b/dictation_server/src/features/notification/notification.module.ts @@ -4,8 +4,8 @@ import { NotificationController } from './notification.controller'; import { NotificationhubModule } from '../../gateways/notificationhub/notificationhub.module'; @Module({ - imports:[NotificationhubModule], + imports: [NotificationhubModule], providers: [NotificationService], - controllers: [NotificationController] + controllers: [NotificationController], }) export class NotificationModule {} diff --git a/dictation_server/src/features/notification/notification.service.ts b/dictation_server/src/features/notification/notification.service.ts index 09eeaec..3c4f1bf 100644 --- a/dictation_server/src/features/notification/notification.service.ts +++ b/dictation_server/src/features/notification/notification.service.ts @@ -14,7 +14,7 @@ export class NotificationService { * @param pnsHandler * @returns register */ - async register(pns: string, pnsHandler: string): Promise<{}> { + async register(pns: string, pnsHandler: string): Promise { this.logger.log(`[IN] ${this.register.name}`); try { await this.notificationhubService.register(pns, pnsHandler); @@ -27,6 +27,5 @@ export class NotificationService { } finally { this.logger.log(`[OUT] ${this.register.name}`); } - return {}; } } diff --git a/dictation_server/src/gateways/notificationhub/notificationhub.module.ts b/dictation_server/src/gateways/notificationhub/notificationhub.module.ts index 4d3b237..8f8b5e7 100644 --- a/dictation_server/src/gateways/notificationhub/notificationhub.module.ts +++ b/dictation_server/src/gateways/notificationhub/notificationhub.module.ts @@ -3,7 +3,7 @@ import { NotificationhubService } from './notificationhub.service'; import { ConfigModule } from '@nestjs/config'; @Module({ - imports:[ConfigModule], + imports: [ConfigModule], exports: [NotificationhubService], providers: [NotificationhubService], }) diff --git a/dictation_server/src/gateways/notificationhub/notificationhub.service.ts b/dictation_server/src/gateways/notificationhub/notificationhub.service.ts index 5b25674..76f251e 100644 --- a/dictation_server/src/gateways/notificationhub/notificationhub.service.ts +++ b/dictation_server/src/gateways/notificationhub/notificationhub.service.ts @@ -23,7 +23,7 @@ export class NotificationhubService { * @param pnsHandler * @returns register */ - async register(pns: string, pnsHandler: string): Promise<{}> { + async register(pns: string, pnsHandler: string): Promise { this.logger.log(`[IN] ${this.register.name}`); let reg: RegistrationDescription; //登録情報作成 @@ -59,7 +59,5 @@ export class NotificationhubService { } finally { this.logger.log(`[OUT] ${this.register.name}`); } - - return {}; } }