From 71127a6db952877d780b123edd7b3198f0bd4c67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B9=AF=E6=9C=AC=20=E9=96=8B?= Date: Wed, 28 Feb 2024 05:30:09 +0000 Subject: [PATCH] =?UTF-8?q?Merged=20PR=20787:=20API=20I/F=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 概要 [Task3793: API I/F修正](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/3793) - OMDS様とのメール文面調整の結果、csvファイル名もAPIで受け渡す必要が出てきたためAPI I/Fを修正する - 一括登録依頼API、一括登録完了APIの両方に「ファイル名」を追加 - 増えたプロパティのバリデーションをするテストを追加 ## レビューポイント - プロパティ名は妥当か - テストの内容は十分か ## 動作確認状況 - npm run testを通過 --- .../src/features/users/types/types.ts | 23 +++- .../features/users/users.controller.spec.ts | 109 +++++++++++++----- 2 files changed, 97 insertions(+), 35 deletions(-) diff --git a/dictation_server/src/features/users/types/types.ts b/dictation_server/src/features/users/types/types.ts index 822a45b..2b5e8a4 100644 --- a/dictation_server/src/features/users/types/types.ts +++ b/dictation_server/src/features/users/types/types.ts @@ -331,6 +331,11 @@ export class MultipleImportUser { } export class PostMultipleImportsRequest { + @ApiProperty({ description: 'CSVファイル名' }) + @IsString() + @IsNotEmpty() + filename: string; + @ApiProperty({ type: [MultipleImportUser] }) @IsArray() @ValidateNested({ each: true }) @@ -345,10 +350,11 @@ export class MultipleImportErrors { @IsNotEmpty() name: string; - @ApiProperty({ description: 'メールアドレス' }) - @IsEmail({ blacklisted_chars: '*' }) + @ApiProperty({ description: 'エラー発生行数' }) + @IsInt() @IsNotEmpty() - email: string; + @Type(() => Number) + line: number; @ApiProperty({ description: 'エラーコード' }) @IsString() @@ -362,6 +368,17 @@ export class PostMultipleImportsCompleteRequest { @IsInt() accountId: number; + @ApiProperty({ description: 'CSVファイル名' }) + @IsString() + @IsNotEmpty() + filename: string; + + @ApiProperty({ description: '一括登録受付時刻(UNIXTIME/ミリ秒)' }) + @IsInt() + @IsNotEmpty() + @Type(() => Number) + requestTime: number; + @ApiProperty({ type: [MultipleImportErrors] }) @IsArray() @ValidateNested({ each: true }) diff --git a/dictation_server/src/features/users/users.controller.spec.ts b/dictation_server/src/features/users/users.controller.spec.ts index 2f93755..123c403 100644 --- a/dictation_server/src/features/users/users.controller.spec.ts +++ b/dictation_server/src/features/users/users.controller.spec.ts @@ -42,6 +42,7 @@ describe('UsersController', () => { describe('valdation PostMultipleImportsRequest', () => { it('role:noneの最低限の有効なリクエストが成功する', async () => { const request = new PostMultipleImportsRequest(); + request.filename = 'test.csv'; request.users = [ { name: 'namae', @@ -60,6 +61,7 @@ describe('UsersController', () => { it('role:authorの最低限の有効なリクエストが成功する', async () => { const request = new PostMultipleImportsRequest(); + request.filename = 'test.csv'; request.users = [ { name: 'namae', @@ -81,6 +83,7 @@ describe('UsersController', () => { it('emailがメールアドレスではない場合、バリデーションエラーが発生する', async () => { const request = new PostMultipleImportsRequest(); + request.filename = 'test.csv'; request.users = [ { name: 'namae', @@ -94,10 +97,11 @@ describe('UsersController', () => { const valdationObject = plainToClass(PostMultipleImportsRequest, request); const errors = await validate(valdationObject); - expect(errors.length).toBeGreaterThan(0); + expect(errors.length).toBe(1); }); it('AuthorなのにAuthorIDがない場合、バリデーションエラーが発生する', async () => { const request = new PostMultipleImportsRequest(); + request.filename = 'test.csv'; request.users = [ { name: 'namae', @@ -113,13 +117,14 @@ describe('UsersController', () => { const valdationObject = plainToClass(PostMultipleImportsRequest, request); const errors = await validate(valdationObject); - expect(errors.length).toBeGreaterThan(0); + expect(errors.length).toBe(1); }); it('AuthorIDがルールに違反していた場合、バリデーションエラーが発生する', async () => { // ルールに合致したAuthorIDではエラーが発生しない const validAuthorIDs = ['A', '_', 'AB', 'A1', '1A', '_1', 'A_B']; for await (const authorId of validAuthorIDs) { const request = new PostMultipleImportsRequest(); + request.filename = 'test.csv'; request.users = [ { name: 'namae', @@ -146,6 +151,7 @@ describe('UsersController', () => { const invalidAuthorIDs = ['a', '+', 'AB.', 'Ab', '1a', '_.', 'A/B', '']; for await (const authorId of invalidAuthorIDs) { const request = new PostMultipleImportsRequest(); + request.filename = 'test.csv'; request.users = [ { name: 'namae', @@ -165,11 +171,12 @@ describe('UsersController', () => { ); const errors = await validate(valdationObject); - expect(errors.length).toBeGreaterThan(0); + expect(errors.length).toBe(1); } }); it('Authorなのにencryptionがない場合、バリデーションエラーが発生する', async () => { const request = new PostMultipleImportsRequest(); + request.filename = 'test.csv'; request.users = [ { name: 'namae', @@ -185,10 +192,11 @@ describe('UsersController', () => { const valdationObject = plainToClass(PostMultipleImportsRequest, request); const errors = await validate(valdationObject); - expect(errors.length).toBeGreaterThan(0); + expect(errors.length).toBe(1); }); it('Authorなのにpromptがない場合、バリデーションエラーが発生する', async () => { const request = new PostMultipleImportsRequest(); + request.filename = 'test.csv'; request.users = [ { name: 'namae', @@ -204,10 +212,11 @@ describe('UsersController', () => { const valdationObject = plainToClass(PostMultipleImportsRequest, request); const errors = await validate(valdationObject); - expect(errors.length).toBeGreaterThan(0); + expect(errors.length).toBe(1); }); it('Authorでencryption:trueなのに、encryptionPasswordがない場合、バリデーションエラーが発生する', async () => { const request = new PostMultipleImportsRequest(); + request.filename = 'test.csv'; request.users = [ { name: 'namae', @@ -224,11 +233,12 @@ describe('UsersController', () => { const valdationObject = plainToClass(PostMultipleImportsRequest, request); const errors = await validate(valdationObject); - expect(errors.length).toBeGreaterThan(0); + expect(errors.length).toBe(1); }); it('Authorでencryption:trueでencryptionPasswordが正常であれば成功する', async () => { const request = new PostMultipleImportsRequest(); + request.filename = 'test.csv'; request.users = [ { name: 'namae', @@ -251,6 +261,7 @@ describe('UsersController', () => { it('encryptionPasswordが要件外(短い)の場合、バリデーションエラーが発生する', async () => { const request = new PostMultipleImportsRequest(); + request.filename = 'test.csv'; request.users = [ { name: 'namae', @@ -268,10 +279,11 @@ describe('UsersController', () => { const valdationObject = plainToClass(PostMultipleImportsRequest, request); const errors = await validate(valdationObject); - expect(errors.length).toBeGreaterThan(0); + expect(errors.length).toBe(1); }); it('encryptionPasswordが要件外(長い)の場合、バリデーションエラーが発生する', async () => { const request = new PostMultipleImportsRequest(); + request.filename = 'test.csv'; request.users = [ { name: 'namae', @@ -289,10 +301,11 @@ describe('UsersController', () => { const valdationObject = plainToClass(PostMultipleImportsRequest, request); const errors = await validate(valdationObject); - expect(errors.length).toBeGreaterThan(0); + expect(errors.length).toBe(1); }); it('encryptionPasswordが要件外(全角が含まれる)の場合、バリデーションエラーが発生する', async () => { const request = new PostMultipleImportsRequest(); + request.filename = 'test.csv'; request.users = [ { name: 'namae', @@ -310,11 +323,12 @@ describe('UsersController', () => { const valdationObject = plainToClass(PostMultipleImportsRequest, request); const errors = await validate(valdationObject); - expect(errors.length).toBeGreaterThan(0); + expect(errors.length).toBe(1); }); it('AuthorIDが要件外(小文字)の場合、バリデーションエラーが発生する', async () => { const request = new PostMultipleImportsRequest(); + request.filename = 'test.csv'; request.users = [ { name: 'namae', @@ -332,7 +346,7 @@ describe('UsersController', () => { const valdationObject = plainToClass(PostMultipleImportsRequest, request); const errors = await validate(valdationObject); - expect(errors.length).toBeGreaterThan(0); + expect(errors.length).toBe(1); }); }); @@ -340,6 +354,8 @@ describe('UsersController', () => { it('最低限の有効なリクエストが成功する', async () => { const request = new PostMultipleImportsCompleteRequest(); request.accountId = 1; + request.requestTime = new Date().getTime(); + request.filename = 'test.csv'; request.errors = []; const valdationObject = plainToClass( @@ -351,18 +367,36 @@ describe('UsersController', () => { expect(errors.length).toBe(0); }); + it('ファイル名が存在しなかった場合、バリデーションエラーが発生する', async () => { + const request = { + accountId: 1, + requestTime: new Date().getTime(), + errors: [], + }; + + const valdationObject = plainToClass( + PostMultipleImportsCompleteRequest, + request, + ); + + const errors = await validate(valdationObject); + expect(errors.length).toBe(1); + }); + it('エラーが存在するリクエストが成功する', async () => { const request = new PostMultipleImportsCompleteRequest(); request.accountId = 1; + request.requestTime = new Date().getTime(); + request.filename = 'test.csv'; request.errors = [ { name: 'namae', - email: 'hogehoge@example.com', + line: 1, errorCode: 'E1101', }, { name: 'namae', - email: 'hogehoge@example.com', + line: 1, errorCode: 'E1101', }, ]; @@ -379,14 +413,16 @@ describe('UsersController', () => { it('名前が足りないエラーがある場合、バリデーションエラーが発生する', async () => { const request = { accountId: 1, + filename: 'test.csv', + requestTime: new Date().getTime(), errors: [ { - email: 'hogehoge@example.com', + line: 1, errorCode: 'E1101', }, { name: 'namae', - email: 'hogehoge@example.com', + line: 1, errorCode: 'E1101', }, ], @@ -398,12 +434,14 @@ describe('UsersController', () => { ); const errors = await validate(valdationObject); - expect(errors.length).toBeGreaterThan(0); + expect(errors.length).toBe(1); }); - it('emailが足りないエラーがある場合、バリデーションエラーが発生する', async () => { + it('行指定が足りないエラーがある場合、バリデーションエラーが発生する', async () => { const request = { accountId: 1, + filename: 'test.csv', + requestTime: new Date().getTime(), errors: [ { name: 'namae', @@ -411,7 +449,7 @@ describe('UsersController', () => { }, { name: 'namae', - email: 'hogehoge@example.com', + line: 1, errorCode: 'E1101', }, ], @@ -423,20 +461,22 @@ describe('UsersController', () => { ); const errors = await validate(valdationObject); - expect(errors.length).toBeGreaterThan(0); + expect(errors.length).toBe(1); }); it('errorCodeが足りないエラーがある場合、バリデーションエラーが発生する', async () => { const request = { accountId: 1, + filename: 'test.csv', + requestTime: new Date().getTime(), errors: [ { name: 'namae', - email: 'hogehoge@example.com', + line: 1, }, { name: 'namae', - email: 'hogehoge@example.com', + line: 1, errorCode: 'E1101', }, ], @@ -448,21 +488,23 @@ describe('UsersController', () => { ); const errors = await validate(valdationObject); - expect(errors.length).toBeGreaterThan(0); + expect(errors.length).toBe(1); }); it('名前が空のエラーがある場合、バリデーションエラーが発生する', async () => { const request = { accountId: 1, + filename: 'test.csv', + requestTime: new Date().getTime(), errors: [ { name: '', - email: 'hogehoge@example.com', + line: 1, errorCode: 'E1101', }, { name: 'namae', - email: 'hogehoge@example.com', + line: 1, errorCode: 'E1101', }, ], @@ -474,20 +516,21 @@ describe('UsersController', () => { ); const errors = await validate(valdationObject); - expect(errors.length).toBeGreaterThan(0); + expect(errors.length).toBe(1); }); - it('emailが空のエラーがある場合、バリデーションエラーが発生する', async () => { + it('行数が空のエラーがある場合、バリデーションエラーが発生する', async () => { const request = { accountId: 1, + filename: 'test.csv', + requestTime: new Date().getTime(), errors: [ { name: 'namae', - email: '', errorCode: 'E1101', }, { name: 'namae', - email: 'hogehoge@example.com', + line: 1, errorCode: 'E1101', }, ], @@ -499,20 +542,22 @@ describe('UsersController', () => { ); const errors = await validate(valdationObject); - expect(errors.length).toBeGreaterThan(0); + expect(errors.length).toBe(1); }); - it('emailが空のエラーがある場合、バリデーションエラーが発生する', async () => { + it('エラーコードが空のエラーがある場合、バリデーションエラーが発生する', async () => { const request = { accountId: 1, + filename: 'test.csv', + requestTime: new Date().getTime(), errors: [ { name: 'namae', - email: 'hogehoge@example.com', + line: 1, errorCode: '', }, { name: 'namae', - email: 'hogehoge@example.com', + line: 1, errorCode: 'E1101', }, ], @@ -524,7 +569,7 @@ describe('UsersController', () => { ); const errors = await validate(valdationObject); - expect(errors.length).toBeGreaterThan(0); + expect(errors.length).toBe(1); }); }); });