Merged PR 597: ライセンス確認画面(第五階層)に会社名を表示する

## 概要
[Task2762: ライセンス確認画面(第五階層)に会社名を表示する](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2762)

- 何をどう変更したか、追加したライブラリなど
ライセンス確認画面(第5階層)の会社名を取得するAPIを実装
- このPull Requestでの対象/対象外
画面側の実装は別ブランチで対応するためここでは対象外

## レビューポイント
特になし

## 動作確認状況
- ポストマン、ユニットテスト
This commit is contained in:
水本 祐希 2023-12-05 07:39:13 +00:00
parent f82f202b63
commit 302f302473
5 changed files with 225 additions and 0 deletions

View File

@ -1455,6 +1455,52 @@
"tags": ["accounts"]
}
},
"/accounts/company-name": {
"post": {
"operationId": "getCompanyName",
"summary": "",
"description": "指定したアカウントの会社名を取得します",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/GetCompanyNameRequest" }
}
}
},
"responses": {
"200": {
"description": "成功時のレスポンス",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GetCompanyNameResponse"
}
}
}
},
"401": {
"description": "認証エラー",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/ErrorResponse" }
}
}
},
"500": {
"description": "想定外のサーバーエラー",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/ErrorResponse" }
}
}
}
},
"tags": ["accounts"],
"security": [{ "bearer": [] }]
}
},
"/users/confirm": {
"post": {
"operationId": "confirmUser",
@ -4009,6 +4055,16 @@
"properties": { "tier": { "type": "number", "description": "階層" } },
"required": ["tier"]
},
"GetCompanyNameRequest": {
"type": "object",
"properties": { "accountId": { "type": "number" } },
"required": ["accountId"]
},
"GetCompanyNameResponse": {
"type": "object",
"properties": { "companyName": { "type": "string" } },
"required": ["companyName"]
},
"ConfirmRequest": {
"type": "object",
"properties": { "token": { "type": "string" } },

View File

@ -68,6 +68,8 @@ import {
GetAccountInfoMinimalAccessResponse,
DeleteWorktypeRequestParam,
DeleteWorktypeResponse,
GetCompanyNameRequest,
GetCompanyNameResponse,
} from './types/types';
import { USER_ROLES, ADMIN_ROLES, TIERS } from '../../constants';
import { AuthGuard } from '../../common/guards/auth/authguards';
@ -1550,4 +1552,56 @@ export class AccountsController {
);
return { tier };
}
@ApiResponse({
status: HttpStatus.OK,
type: GetCompanyNameResponse,
description: '成功時のレスポンス',
})
@ApiResponse({
status: HttpStatus.UNAUTHORIZED,
description: '認証エラー',
type: ErrorResponse,
})
@ApiResponse({
status: HttpStatus.INTERNAL_SERVER_ERROR,
description: '想定外のサーバーエラー',
type: ErrorResponse,
})
@ApiOperation({
operationId: 'getCompanyName',
description: '指定したアカウントの会社名を取得します',
})
@ApiBearerAuth()
@UseGuards(AuthGuard)
@UseGuards(
RoleGuard.requireds({ roles: [ADMIN_ROLES.ADMIN], delegation: true }),
)
@Post('company-name')
async getCompanyName(
@Req() req: Request,
@Body() body: GetCompanyNameRequest,
): Promise<GetCompanyNameResponse> {
const accessToken = retrieveAuthorizationToken(req);
if (!accessToken) {
throw new HttpException(
makeErrorResponse('E000107'),
HttpStatus.UNAUTHORIZED,
);
}
const decodedAccessToken = jwt.decode(accessToken, { json: true });
if (!decodedAccessToken) {
throw new HttpException(
makeErrorResponse('E000101'),
HttpStatus.UNAUTHORIZED,
);
}
const { userId } = decodedAccessToken as AccessToken;
const context = makeContext(userId);
const companyName = await this.accountService.getCompanyName(
context,
body.accountId,
);
return companyName;
}
}

View File

@ -6694,3 +6694,60 @@ describe('getAccountInfoMinimalAccess', () => {
}
});
});
describe('getCompanyName', () => {
let source: DataSource | null = 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 () => {
if (!source) return;
await source.destroy();
source = null;
});
it('アカウントIDから会社名が取得できること', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<AccountsService>(AccountsService);
// 第五階層のアカウント作成
const { account, admin } = await makeTestAccount(source, {
tier: 5,
company_name: 'testCompany',
});
const context = makeContext(admin.external_id);
const response = await service.getCompanyName(context, account.id);
expect({ companyName: 'testCompany' }).toEqual(response);
});
it('アカウントが存在しない場合、400エラーとなること', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<AccountsService>(AccountsService);
// 第五階層のアカウント作成
const { account, admin } = await makeTestAccount(source, {
tier: 5,
company_name: 'testCompany',
});
const context = makeContext(admin.external_id);
try {
await service.getCompanyName(context, 123);
} catch (e) {
if (e instanceof HttpException) {
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
expect(e.getResponse()).toEqual(makeErrorResponse('E010501'));
} else {
fail();
}
}
});
});

View File

@ -34,6 +34,7 @@ import {
PostWorktypeOptionItem,
Author,
Partner,
GetCompanyNameResponse,
} from './types/types';
import {
DateWithZeroTime,
@ -2151,4 +2152,51 @@ export class AccountsService {
);
}
}
/**
*
* @param accountId
* @returns CompanyName
*/
async getCompanyName(
context: Context,
accountId: number,
): Promise<GetCompanyNameResponse> {
this.logger.log(
`[IN] [${context.getTrackingId()}] ${
this.getCompanyName.name
} | params: { accountId: ${accountId}, };`,
);
try {
const { company_name } = await this.accountRepository.findAccountById(
accountId,
);
return { companyName: company_name };
} catch (e) {
this.logger.error(`[${context.getTrackingId()}] 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.getTrackingId()}] ${this.getCompanyName.name}`,
);
}
}
}

View File

@ -599,3 +599,13 @@ export class GetAccountInfoMinimalAccessResponse {
@ApiProperty({ description: '階層' })
tier: number;
}
export class GetCompanyNameRequest {
@ApiProperty()
@IsInt()
@Type(() => Number)
accountId: number;
}
export class GetCompanyNameResponse {
@ApiProperty()
companyName: string;
}