From 78cbfd15e8dfd751d88169a21b650944c8137bcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B0=B4=E6=9C=AC=20=E7=A5=90=E5=B8=8C?= Date: Fri, 15 Sep 2023 02:17:54 +0000 Subject: [PATCH] =?UTF-8?q?Merged=20PR=20400:=20API=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=EF=BC=88=E3=82=A2=E3=82=AB=E3=82=A6=E3=83=B3=E3=83=88=E6=83=85?= =?UTF-8?q?=E5=A0=B1=E5=8F=96=E5=BE=97API=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 概要 [Task2601: API修正(アカウント情報取得API)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2601) - 元PBI or タスクへのリンク(内容・目的などはそちらにあるはず) - 何をどう変更したか、追加したライブラリなど - アカウント情報取得APIで返却する値を追加 - テストしやすさを考慮し、getMyAccountInfoのパラメータと関数名を修正 - ログ出力について規約に沿った形に修正 - このPull Requestでの対象/対象外 - 影響範囲(他の機能にも影響があるか) ## レビューポイント - 特にレビューしてほしい箇所 アクセストークンを使ったユニットテストがあれば教えてください。 - 軽微なものや自明なものは記載不要 - 修正範囲が大きい場合などに記載 - 全体的にや仕様を満たしているか等は本当に必要な時のみ記載 ## UIの変更 - Before/Afterのスクショなど - スクショ置き場 ## 動作確認状況 - ローカルで確認 アクセストークンからアカウント情報を取得するAPIであるため、ポストマンで確認しました。 - 確認事項 - 追加したtier、country、parentAccountId、delegationPermission、primaryAdminUserId、secondryAdminUserIdが返却されることを確認。 - 異常系 - MySQLにてusersとaccountsがない場合のエラーメッセージが返却されるかを確認   ## 補足 - 相談、参考資料などがあれば --- dictation_server/src/api/odms/openapi.json | 16 ++++- .../features/accounts/accounts.controller.ts | 6 +- .../accounts/accounts.service.spec.ts | 53 +++++++++++++++ .../src/features/accounts/accounts.service.ts | 67 ++++++++++--------- .../src/features/accounts/types/types.ts | 19 ++++++ 5 files changed, 127 insertions(+), 34 deletions(-) diff --git a/dictation_server/src/api/odms/openapi.json b/dictation_server/src/api/odms/openapi.json index bf171db..9931cf2 100644 --- a/dictation_server/src/api/odms/openapi.json +++ b/dictation_server/src/api/odms/openapi.json @@ -2837,9 +2837,21 @@ "type": "object", "properties": { "accountId": { "type": "number" }, - "companyName": { "type": "string" } + "companyName": { "type": "string" }, + "tier": { "type": "number" }, + "country": { "type": "string" }, + "parentAccountId": { "type": "number" }, + "delegationPermission": { "type": "boolean" }, + "primaryAdminUserId": { "type": "number" }, + "secondryAdminUserId": { "type": "number" } }, - "required": ["accountId", "companyName"] + "required": [ + "accountId", + "companyName", + "tier", + "country", + "delegationPermission" + ] }, "GetMyAccountResponse": { "type": "object", diff --git a/dictation_server/src/features/accounts/accounts.controller.ts b/dictation_server/src/features/accounts/accounts.controller.ts index 88cd108..27a3980 100644 --- a/dictation_server/src/features/accounts/accounts.controller.ts +++ b/dictation_server/src/features/accounts/accounts.controller.ts @@ -190,8 +190,12 @@ export class AccountsController { // アクセストークン取得 const accessToken = retrieveAuthorizationToken(req); const payload = jwt.decode(accessToken, { json: true }) as AccessToken; + const context = makeContext(payload.userId); //アカウントID取得処理 - const accountInfo = await this.accountService.getMyAccountInfo(payload); + const accountInfo = await this.accountService.getAccountInfo( + context, + payload.userId, + ); return accountInfo; } diff --git a/dictation_server/src/features/accounts/accounts.service.spec.ts b/dictation_server/src/features/accounts/accounts.service.spec.ts index f83453c..2e30743 100644 --- a/dictation_server/src/features/accounts/accounts.service.spec.ts +++ b/dictation_server/src/features/accounts/accounts.service.spec.ts @@ -4757,3 +4757,56 @@ describe('パートナー一覧取得', () => { expect(partners.total).toBe(0); }); }); + +describe('getAccountInfo', () => { + 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('パラメータのユーザに対応するアカウント情報を取得できる', async () => { + const module = await makeTestingModule(source); + // 第五階層のアカウント作成 + const { account, admin } = await makeTestAccount(source, { + parent_account_id: 123, + }); + + const service = module.get(AccountsService); + const context = makeContext(admin.external_id); + + const accountResponse = await service.getAccountInfo( + context, + admin.external_id, + ); + + //実行結果を確認 + { + expect(accountResponse.account.accountId).toBe(account.id); + expect(accountResponse.account.companyName).toBe(account.company_name); + expect(accountResponse.account.country).toBe(account.country); + expect(accountResponse.account.delegationPermission).toBe( + account.delegation_permission, + ); + expect(accountResponse.account.parentAccountId).toBe( + account.parent_account_id, + ); + expect(accountResponse.account.primaryAdminUserId).toBe( + account.primary_admin_user_id, + ); + expect(accountResponse.account.secondryAdminUserId).toBe(undefined); + expect(accountResponse.account.tier).toBe(account.tier); + } + }); +}); diff --git a/dictation_server/src/features/accounts/accounts.service.ts b/dictation_server/src/features/accounts/accounts.service.ts index acb6308..024089f 100644 --- a/dictation_server/src/features/accounts/accounts.service.ts +++ b/dictation_server/src/features/accounts/accounts.service.ts @@ -364,38 +364,47 @@ export class AccountsService { } /** - * アクセストークンからアカウント情報を取得する - * @param token - * @returns accountId + * パラメータのユーザIDからアカウント情報を取得する + * @param externalId + * @returns GetMyAccountResponse */ - async getMyAccountInfo(token: AccessToken): Promise { - this.logger.log(`[IN] ${this.getMyAccountInfo.name}`); - - let userInfo: User; + async getAccountInfo( + context: Context, + externalId: string, + ): Promise { + this.logger.log( + `[IN] [${context.trackingId}] ${this.getAccountInfo.name} | params: { ` + + `name: ${externalId}, };`, + ); try { - userInfo = await this.usersRepository.findUserByExternalId(token.userId); + let userInfo: User; + userInfo = await this.usersRepository.findUserByExternalId(externalId); + + let accountInfo: Account; + accountInfo = await this.accountRepository.findAccountById( + userInfo.account_id, + ); + + return { + account: { + accountId: userInfo.account_id, + companyName: accountInfo.company_name, + tier: accountInfo.tier, + country: accountInfo.country, + parentAccountId: accountInfo.parent_account_id ?? undefined, + delegationPermission: accountInfo.delegation_permission, + primaryAdminUserId: accountInfo.primary_admin_user_id ?? undefined, + secondryAdminUserId: accountInfo.secondary_admin_user_id ?? undefined, + }, + }; } catch (e) { + this.logger.error(`[${context.trackingId}] error=${e}`); switch (e.constructor) { case UserNotFoundError: throw new HttpException( makeErrorResponse('E010204'), HttpStatus.BAD_REQUEST, ); - default: - throw new HttpException( - makeErrorResponse('E009999'), - HttpStatus.INTERNAL_SERVER_ERROR, - ); - } - } - - let accountInfo: Account; - try { - accountInfo = await this.accountRepository.findAccountById( - userInfo.account_id, - ); - } catch (e) { - switch (e.constructor) { case AccountNotFoundError: throw new HttpException( makeErrorResponse('E010501'), @@ -407,15 +416,11 @@ export class AccountsService { HttpStatus.INTERNAL_SERVER_ERROR, ); } + } finally { + this.logger.log( + `[OUT] [${context.trackingId}] ${this.getAccountInfo.name}`, + ); } - - this.logger.log(`[OUT] ${this.getMyAccountInfo.name}`); - return { - account: { - accountId: userInfo.account_id, - companyName: accountInfo.company_name, - }, - }; } async getTypistGroups(externalId: string): Promise { diff --git a/dictation_server/src/features/accounts/types/types.ts b/dictation_server/src/features/accounts/types/types.ts index e67cb65..99672e3 100644 --- a/dictation_server/src/features/accounts/types/types.ts +++ b/dictation_server/src/features/accounts/types/types.ts @@ -103,8 +103,27 @@ export class GetLicenseSummaryResponse { export class Account { @ApiProperty() accountId: number; + @ApiProperty() companyName: string; + + @ApiProperty() + tier: number; + + @ApiProperty() + country: string; + + @ApiProperty({ required: false }) + parentAccountId?: number | undefined; + + @ApiProperty() + delegationPermission: boolean; + + @ApiProperty({ required: false }) + primaryAdminUserId?: number | undefined; + + @ApiProperty({ required: false }) + secondryAdminUserId?: number | undefined; } export class GetMyAccountResponse {