From 81d17fb57e5d924b9e02e650a06e7846a9704247 Mon Sep 17 00:00:00 2001 From: "makabe.t" Date: Thu, 14 Sep 2023 09:20:04 +0000 Subject: [PATCH] =?UTF-8?q?Merged=20PR=20408:=20API=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=EF=BC=88WorktypeID=E4=B8=80=E8=A6=A7API=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 概要 [Task2621: API修正(WorktypeID一覧API)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2621) - Worktype一覧APIでActiveWorkTypeも取得するよう修正しました。 - API IFでプロパティがnullableになっているところをrequiredに修正しました。 ## レビューポイント - ActiveWorktypeの取得に問題はないか - テストケースは適切か - IFの修正は問題ないか ## UIの変更 - なし ## 動作確認状況 - ローカルで確認 --- dictation_server/src/api/odms/openapi.json | 6 ++-- .../accounts/accounts.service.spec.ts | 8 ++++- .../src/features/accounts/accounts.service.ts | 22 +++++++++++-- .../src/features/accounts/test/utility.ts | 12 +++++++ .../src/features/accounts/types/types.ts | 2 +- .../features/tasks/test/tasks.service.mock.ts | 8 ++--- .../src/features/users/types/types.ts | 2 +- .../accounts/entity/account.entity.ts | 3 ++ .../worktypes/worktypes.repository.service.ts | 33 +++++++++++++++---- 9 files changed, 75 insertions(+), 21 deletions(-) diff --git a/dictation_server/src/api/odms/openapi.json b/dictation_server/src/api/odms/openapi.json index c5612fa..bf171db 100644 --- a/dictation_server/src/api/odms/openapi.json +++ b/dictation_server/src/api/odms/openapi.json @@ -3094,7 +3094,7 @@ "type": "array", "items": { "$ref": "#/components/schemas/Worktype" } }, - "acrive": { + "active": { "type": "number", "description": "Active WorktypeIDに設定されているWorkTypeの内部ID" } @@ -3390,8 +3390,7 @@ }, "encryptionPassword": { "type": "string", - "description": "ユーザーが暗号化を掛ける場合のパスワード", - "nullable": true + "description": "ユーザーが暗号化を掛ける場合のパスワード" }, "activeWorktype": { "type": "string", @@ -3411,7 +3410,6 @@ "authorIdList", "workTypeList", "isEncrypted", - "encryptionPassword", "activeWorktype", "audioFormat", "prompt" diff --git a/dictation_server/src/features/accounts/accounts.service.spec.ts b/dictation_server/src/features/accounts/accounts.service.spec.ts index e240d75..f83453c 100644 --- a/dictation_server/src/features/accounts/accounts.service.spec.ts +++ b/dictation_server/src/features/accounts/accounts.service.spec.ts @@ -3372,17 +3372,21 @@ describe('getWorktypes', () => { const service = module.get(AccountsService); const context = makeContext(admin.external_id); - await createWorktype(source, account.id, 'worktype1', 'description1'); + await createWorktype(source, account.id, 'worktype1', 'description1', true); await createWorktype(source, account.id, 'worktype2'); //作成したデータを確認 const worktypes = await getWorktypes(source, account.id); + const accounts = await getAccounts(source); { expect(worktypes.length).toBe(2); expect(worktypes[0].custom_worktype_id).toBe('worktype1'); expect(worktypes[1].custom_worktype_id).toBe('worktype2'); expect(worktypes[0].description).toBe('description1'); expect(worktypes[1].description).toBeNull(); + + expect(accounts.length).toBe(1); + expect(accounts[0].active_worktype_id).toBe(worktypes[0].id); } const resWorktypes = await service.getWorktypes(context, admin.external_id); @@ -3394,6 +3398,8 @@ describe('getWorktypes', () => { expect(resWorktypes.worktypes[1].worktypeId).toBe('worktype2'); expect(resWorktypes.worktypes[0].description).toBe('description1'); expect(resWorktypes.worktypes[1].description).toBe(undefined); + + expect(resWorktypes.active).toBe(worktypes[0].id); } }); diff --git a/dictation_server/src/features/accounts/accounts.service.ts b/dictation_server/src/features/accounts/accounts.service.ts index 93f3293..acb6308 100644 --- a/dictation_server/src/features/accounts/accounts.service.ts +++ b/dictation_server/src/features/accounts/accounts.service.ts @@ -1169,8 +1169,9 @@ export class AccountsService { const { account_id: accountId } = await this.usersRepository.findUserByExternalId(externalId); - // ワークタイプ一覧を取得する - const worktypes = await this.worktypesRepository.getWorktypes(accountId); + // ワークタイプ一覧とActiveWorktypeIDを取得する + const { worktypes, active_worktype_id } = + await this.worktypesRepository.getWorktypes(accountId); return { worktypes: worktypes.map((x) => ({ @@ -1178,9 +1179,24 @@ export class AccountsService { worktypeId: x.custom_worktype_id, description: x.description ?? undefined, })), + active: active_worktype_id, }; } catch (e) { - this.logger.error(e); + this.logger.error(`error=${e}`); + if (e instanceof Error) { + switch (e.constructor) { + case AccountNotFoundError: + throw new HttpException( + makeErrorResponse('E010501'), + HttpStatus.BAD_REQUEST, + ); + default: + throw new HttpException( + makeErrorResponse('E009999'), + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + } throw new HttpException( makeErrorResponse('E009999'), HttpStatus.INTERNAL_SERVER_ERROR, diff --git a/dictation_server/src/features/accounts/test/utility.ts b/dictation_server/src/features/accounts/test/utility.ts index 32a2586..a91a8d4 100644 --- a/dictation_server/src/features/accounts/test/utility.ts +++ b/dictation_server/src/features/accounts/test/utility.ts @@ -9,6 +9,7 @@ import { UserGroupMember } from '../../../repositories/user_groups/entity/user_g import { Worktype } from '../../../repositories/worktypes/entity/worktype.entity'; import { OptionItem } from '../../../repositories/worktypes/entity/option_item.entity'; import { OPTION_ITEM_VALUE_TYPE } from '../../../constants'; +import { Account } from '../../../repositories/accounts/entity/account.entity'; /** * テスト ユーティリティ: すべてのソート条件を取得する @@ -127,6 +128,7 @@ export const createWorktype = async ( accountId: number, worktypeId: string, description?: string, + isActive?: boolean, ): Promise => { const { identifiers } = await datasource.getRepository(Worktype).insert({ account_id: accountId, @@ -139,6 +141,16 @@ export const createWorktype = async ( updated_at: new Date(), }); const worktype = identifiers.pop() as Worktype; + + if (isActive) { + await datasource.getRepository(Account).update( + { id: accountId }, + { + active_worktype_id: worktype.id, + }, + ); + } + return worktype; }; diff --git a/dictation_server/src/features/accounts/types/types.ts b/dictation_server/src/features/accounts/types/types.ts index a258533..e67cb65 100644 --- a/dictation_server/src/features/accounts/types/types.ts +++ b/dictation_server/src/features/accounts/types/types.ts @@ -358,7 +358,7 @@ export class GetWorktypesResponse { required: false, description: 'Active WorktypeIDに設定されているWorkTypeの内部ID', }) - acrive?: number | undefined; + active?: number | undefined; } export class CreateWorktypesRequest { diff --git a/dictation_server/src/features/tasks/test/tasks.service.mock.ts b/dictation_server/src/features/tasks/test/tasks.service.mock.ts index 38a9aba..8c9ba89 100644 --- a/dictation_server/src/features/tasks/test/tasks.service.mock.ts +++ b/dictation_server/src/features/tasks/test/tasks.service.mock.ts @@ -330,7 +330,7 @@ const defaultTasksRepositoryMockValue: { audio_file_id: 1, status: 'Uploaded', priority: '00', - created_at: new Date('2023-01-01T01:01:01.000'), + created_at: new Date('2023-01-01T01:01:01.000Z'), option_items: [ { id: 1, @@ -401,10 +401,10 @@ const defaultTasksRepositoryMockValue: { file_name: 'test.zip', author_id: 'AUTHOR', work_type_id: 'WorkType', - started_at: new Date('2023-01-01T01:01:01.000'), + started_at: new Date('2023-01-01T01:01:01.000Z'), duration: '123000', - finished_at: new Date('2023-01-01T01:01:01.000'), - uploaded_at: new Date('2023-01-01T01:01:01.000'), + finished_at: new Date('2023-01-01T01:01:01.000Z'), + uploaded_at: new Date('2023-01-01T01:01:01.000Z'), file_size: 123000, priority: '00', audio_format: 'DS', diff --git a/dictation_server/src/features/users/types/types.ts b/dictation_server/src/features/users/types/types.ts index 54fd6b0..c3df59c 100644 --- a/dictation_server/src/features/users/types/types.ts +++ b/dictation_server/src/features/users/types/types.ts @@ -159,7 +159,7 @@ export class GetRelationsResponse { isEncrypted: boolean; @ApiProperty({ description: 'ユーザーが暗号化を掛ける場合のパスワード', - nullable: true, + required: false, }) encryptionPassword?: string | undefined; @ApiProperty({ diff --git a/dictation_server/src/repositories/accounts/entity/account.entity.ts b/dictation_server/src/repositories/accounts/entity/account.entity.ts index ad65437..f6787d9 100644 --- a/dictation_server/src/repositories/accounts/entity/account.entity.ts +++ b/dictation_server/src/repositories/accounts/entity/account.entity.ts @@ -40,6 +40,9 @@ export class Account { @Column({ nullable: true }) secondary_admin_user_id?: number; + @Column({ nullable: true }) + active_worktype_id?: number; + @Column({ nullable: true }) deleted_at?: Date; diff --git a/dictation_server/src/repositories/worktypes/worktypes.repository.service.ts b/dictation_server/src/repositories/worktypes/worktypes.repository.service.ts index bd856e6..7ce50da 100644 --- a/dictation_server/src/repositories/worktypes/worktypes.repository.service.ts +++ b/dictation_server/src/repositories/worktypes/worktypes.repository.service.ts @@ -13,22 +13,41 @@ import { } from './errors/types'; import { OptionItem } from './entity/option_item.entity'; import { PostWorktypeOptionItem } from '../../features/accounts/types/types'; +import { AccountNotFoundError } from '../accounts/errors/types'; +import { Account } from '../accounts/entity/account.entity'; @Injectable() export class WorktypesRepositoryService { constructor(private dataSource: DataSource) {} /** - * ワークタイプ一覧を取得する - * @param accountId - * @returns worktypes + * ワークタイプ一覧とActiveWorktypeIDを取得する + * @param externalId + * @returns worktypes and active worktype id */ - async getWorktypes(accountId: number): Promise { + async getWorktypes(accountId: number): Promise<{ + worktypes: Worktype[]; + active_worktype_id?: number | undefined; + }> { return await this.dataSource.transaction(async (entityManager) => { - const repo = entityManager.getRepository(Worktype); + const WorktypeRepo = entityManager.getRepository(Worktype); + const accountRepo = entityManager.getRepository(Account); - const worktypes = await repo.find({ where: { account_id: accountId } }); - return worktypes; + const account = await accountRepo.findOne({ where: { id: accountId } }); + + // 運用上アカウントがいないことはあり得ないが、プログラム上発生しうるのでエラーとして処理 + if (!account) { + throw new AccountNotFoundError(); + } + + const worktypes = await WorktypeRepo.find({ + where: { account_id: account.id }, + }); + + return { + worktypes, + active_worktype_id: account.active_worktype_id ?? undefined, + }; }); } /**