From 964077a480adffadc77a7d7a6edfe243a318d8a3 Mon Sep 17 00:00:00 2001 From: "makabe.t" Date: Thu, 5 Oct 2023 07:49:55 +0000 Subject: [PATCH] =?UTF-8?q?Merged=20PR=20460:=20Author=E4=B8=80=E8=A6=A7?= =?UTF-8?q?=E5=8F=96=E5=BE=97API=E5=AE=9F=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 概要 [Task2748: Author一覧取得API実装](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2748) - Author一覧を取得するAPIとテストを実装しました。 ## レビューポイント - テストケースは適切か ## UIの変更 - なし ## 動作確認状況 - ローカルで確認 --- .../features/accounts/accounts.controller.ts | 4 +- .../accounts/accounts.service.spec.ts | 108 ++++++++++++++++++ .../src/features/accounts/accounts.service.ts | 59 ++++++++++ .../users/users.repository.service.ts | 19 +++ 4 files changed, 188 insertions(+), 2 deletions(-) diff --git a/dictation_server/src/features/accounts/accounts.controller.ts b/dictation_server/src/features/accounts/accounts.controller.ts index 4ac1c64..21becf3 100644 --- a/dictation_server/src/features/accounts/accounts.controller.ts +++ b/dictation_server/src/features/accounts/accounts.controller.ts @@ -231,9 +231,9 @@ export class AccountsController { const { userId } = jwt.decode(accessToken, { json: true }) as AccessToken; const context = makeContext(userId); - console.log(context.trackingId); + const authors = await this.accountService.getAuthors(context, userId); - return { authors: [] }; + return { authors }; } @ApiResponse({ diff --git a/dictation_server/src/features/accounts/accounts.service.spec.ts b/dictation_server/src/features/accounts/accounts.service.spec.ts index 7fe4171..170f607 100644 --- a/dictation_server/src/features/accounts/accounts.service.spec.ts +++ b/dictation_server/src/features/accounts/accounts.service.spec.ts @@ -66,6 +66,7 @@ import { WorktypesRepositoryService } from '../../repositories/worktypes/worktyp import { AdB2cUser } from '../../gateways/adb2c/types/types'; import { Worktype } from '../../repositories/worktypes/entity/worktype.entity'; import { AccountsRepositoryService } from '../../repositories/accounts/accounts.repository.service'; +import { UsersRepositoryService } from '../../repositories/users/users.repository.service'; describe('createAccount', () => { let source: DataSource = null; @@ -5204,3 +5205,110 @@ describe('getAccountInfo', () => { } }); }); + +describe('getAuthors', () => { + let source: DataSource = null; + beforeEach(async () => { + source = new DataSource({ + type: 'sqlite', + database: ':memory:', + logging: false, + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: true, // trueにすると自動的にmigrationが行われるため注意 + }); + return source.initialize(); + }); + + afterEach(async () => { + await source.destroy(); + source = null; + }); + it('アカウント内のAuthorユーザーの一覧を取得できる', async () => { + const module = await makeTestingModule(source); + // 第五階層のアカウント作成 + const { account, admin } = await makeTestAccount(source, { tier: 5 }); + + const { id: userId1 } = await makeTestUser(source, { + account_id: account.id, + role: USER_ROLES.AUTHOR, + author_id: 'AUTHOR_ID_1', + }); + const { id: userId2 } = await makeTestUser(source, { + account_id: account.id, + role: USER_ROLES.AUTHOR, + author_id: 'AUTHOR_ID_2', + }); + const { id: userId3 } = await makeTestUser(source, { + account_id: account.id, + role: USER_ROLES.TYPIST, + }); + + // 作成したデータを確認 + { + const users = await getUsers(source); + expect(users.length).toBe(4); + expect(users[1].id).toBe(userId1); + expect(users[2].id).toBe(userId2); + expect(users[3].id).toBe(userId3); + } + + const service = module.get(AccountsService); + const context = makeContext(admin.external_id); + const authors = await service.getAuthors(context, admin.external_id); + + //実行結果を確認 + { + expect(authors.length).toBe(2); + expect(authors[0].id).toBe(userId1); + expect(authors[0].authorId).toBe('AUTHOR_ID_1'); + expect(authors[1].id).toBe(userId2); + expect(authors[1].authorId).toBe('AUTHOR_ID_2'); + } + }); + it('アカウント内のAuthorユーザーの一覧を取得できる(0件)', async () => { + const module = await makeTestingModule(source); + // 第五階層のアカウント作成 + const { admin } = await makeTestAccount(source, { tier: 5 }); + + // 作成したデータを確認 + { + const users = await getUsers(source); + expect(users.length).toBe(1); + } + + const service = module.get(AccountsService); + const context = makeContext(admin.external_id); + const authors = await service.getAuthors(context, admin.external_id); + + //実行結果を確認 + { + expect(authors.length).toBe(0); + } + }); + it('DBアクセスに失敗した場合、500エラーとなる', async () => { + const module = await makeTestingModule(source); + // 第五階層のアカウント作成 + const { admin } = await makeTestAccount(source, { tier: 5 }); + + const service = module.get(AccountsService); + const context = makeContext(admin.external_id); + + //DBアクセスに失敗するようにする + const usersService = module.get( + UsersRepositoryService, + ); + usersService.findAuthorUsers = jest.fn().mockRejectedValue('DB failed'); + + //実行結果を確認 + try { + await service.getAuthors(context, admin.external_id); + } catch (e) { + if (e instanceof HttpException) { + expect(e.getStatus()).toEqual(HttpStatus.INTERNAL_SERVER_ERROR); + expect(e.getResponse()).toEqual(makeErrorResponse('E009999')); + } else { + fail(); + } + } + }); +}); diff --git a/dictation_server/src/features/accounts/accounts.service.ts b/dictation_server/src/features/accounts/accounts.service.ts index 495fee5..361ab8b 100644 --- a/dictation_server/src/features/accounts/accounts.service.ts +++ b/dictation_server/src/features/accounts/accounts.service.ts @@ -32,6 +32,7 @@ import { GetOptionItemsResponse, GetPartnersResponse, PostWorktypeOptionItem, + Author, } from './types/types'; import { DateWithZeroTime, @@ -554,6 +555,64 @@ export class AccountsService { } } + /** + * アカウント内のAuthorを取得する + * @param context + * @param externalId + * @returns authors + */ + async getAuthors(context: Context, externalId: string): Promise { + this.logger.log( + `[IN] [${context.trackingId}] ${this.getAuthors.name} | params: { externalId: ${externalId} };`, + ); + + try { + const { account } = await this.usersRepository.findUserByExternalId( + externalId, + ); + + if (!account) { + throw new AccountNotFoundError( + `account not found. externalId: ${externalId}`, + ); + } + + const authorUsers = await this.usersRepository.findAuthorUsers( + account.id, + ); + + const authors = authorUsers.map((x) => { + return { + id: x.id, + authorId: x.author_id, + }; + }); + return authors; + } catch (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, + ); + } finally { + this.logger.log(`[OUT] [${context.trackingId}] ${this.getAuthors.name}`); + } + } + /** * パートナーを追加する * @param companyName パートナーの会社名 diff --git a/dictation_server/src/repositories/users/users.repository.service.ts b/dictation_server/src/repositories/users/users.repository.service.ts index b4c388d..4ecb668 100644 --- a/dictation_server/src/repositories/users/users.repository.service.ts +++ b/dictation_server/src/repositories/users/users.repository.service.ts @@ -375,6 +375,25 @@ export class UsersRepositoryService { }); } + /** + * アカウント内のAuthorユーザーを取得する + * @param accountId + * @returns author users + */ + async findAuthorUsers(accountId: number): Promise { + return await this.dataSource.transaction(async (entityManager) => { + const repo = entityManager.getRepository(User); + const authors = await repo.find({ + where: { + account_id: accountId, + role: USER_ROLES.AUTHOR, + deleted_at: IsNull(), + }, + }); + return authors; + }); + } + /** * UserID指定のユーザーとソート条件を同時に削除する * @param userId