From 34ad2e489dcf9c4367eed44503d7c70b0be2dcde Mon Sep 17 00:00:00 2001 From: "maruyama.t" Date: Fri, 4 Aug 2023 02:08:42 +0000 Subject: [PATCH] =?UTF-8?q?Merged=20PR=20304:=20API-IF=E5=AE=9F=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 概要 [Task2338: API-IF実装](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2338) - 元PBI or タスクへのリンク(内容・目的などはそちらにあるはず) - 何をどう変更したか、追加したライブラリなど - このPull Requestでの対象/対象外 - 影響範囲(他の機能にも影響があるか) 新規のため、なし ## レビューポイント - 特にレビューしてほしい箇所 - 軽微なものや自明なものは記載不要 - 修正範囲が大きい場合などに記載 - 全体的にや仕様を満たしているか等は本当に必要な時のみ記載 ## UIの変更 - Before/Afterのスクショなど - スクショ置き場 ## 動作確認状況 - ローカル環境で確認 (POSTMANによる正常時の戻り値nullと各Error) ## 補足 - 相談、参考資料などがあれば --- dictation_server/src/api/odms/openapi.json | 69 ++++++++++++++++++- .../features/accounts/accounts.controller.ts | 62 +++++++++++++++-- .../accounts/accounts.service.spec.ts | 38 +++++----- .../src/features/accounts/accounts.service.ts | 8 +-- .../src/features/accounts/types/types.ts | 14 +++- 5 files changed, 158 insertions(+), 33 deletions(-) diff --git a/dictation_server/src/api/odms/openapi.json b/dictation_server/src/api/odms/openapi.json index 6aa43e8..432efab 100644 --- a/dictation_server/src/api/odms/openapi.json +++ b/dictation_server/src/api/odms/openapi.json @@ -423,7 +423,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/GetOrderHistoriesResponce" + "$ref": "#/components/schemas/GetOrderHistoriesResponse" } } } @@ -449,6 +449,59 @@ "security": [{ "bearer": [] }] } }, + "/accounts/licenses/issue": { + "post": { + "operationId": "issueLicense", + "summary": "", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/IssueLicenseRequest" } + } + } + }, + "responses": { + "200": { + "description": "成功時のレスポンス", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IssueLicenseResponse" + } + } + } + }, + "400": { + "description": "自身のライセンス数が不足している場合/すでに対象注文が発行済の場合", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ErrorResponse" } + } + } + }, + "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", @@ -2044,7 +2097,7 @@ "status" ] }, - "GetOrderHistoriesResponce": { + "GetOrderHistoriesResponse": { "type": "object", "properties": { "total": { "type": "number", "description": "合計件数" }, @@ -2055,6 +2108,18 @@ }, "required": ["total", "orderHistories"] }, + "IssueLicenseRequest": { + "type": "object", + "properties": { + "orderedAccountId": { + "type": "number", + "description": "注文元アカウントID" + }, + "poNumber": { "type": "string", "description": "POナンバー" } + }, + "required": ["orderedAccountId", "poNumber"] + }, + "IssueLicenseResponse": { "type": "object", "properties": {} }, "ConfirmRequest": { "type": "object", "properties": { "token": { "type": "string" } }, diff --git a/dictation_server/src/features/accounts/accounts.controller.ts b/dictation_server/src/features/accounts/accounts.controller.ts index 5545f43..e2a6ba3 100644 --- a/dictation_server/src/features/accounts/accounts.controller.ts +++ b/dictation_server/src/features/accounts/accounts.controller.ts @@ -29,8 +29,9 @@ import { GetPartnerLicensesRequest, GetPartnerLicensesResponse, GetOrderHistoriesRequest, - GetOrderHistoriesResponce, - LicenseOrder, + GetOrderHistoriesResponse, + IssueLicenseRequest, + IssueLicenseResponse, } from './types/types'; import { USER_ROLES, ADMIN_ROLES, TIERS } from '../../constants'; import { AuthGuard } from '../../common/guards/auth/authguards'; @@ -38,6 +39,7 @@ import { RoleGuard } from '../../common/guards/role/roleguards'; import { retrieveAuthorizationToken } from '../../common/http/helper'; import { AccessToken } from '../../common/token'; import jwt from 'jsonwebtoken'; +import { Context } from '../../common/log'; @ApiTags('accounts') @Controller('accounts') @@ -332,7 +334,7 @@ export class AccountsController { @Post('order-histories') @ApiResponse({ status: HttpStatus.OK, - type: GetOrderHistoriesResponce, + type: GetOrderHistoriesResponse, description: '成功時のレスポンス', }) @ApiResponse({ @@ -356,12 +358,60 @@ export class AccountsController { async getOrderHistories( @Req() req: Request, @Body() body: GetOrderHistoriesRequest, - ): Promise { + ): Promise { const { limit, offset, accountId } = body; - const getOrderHistoriesResponce = + const getOrderHistoriesResponse = await this.accountService.getOrderHistories(limit, offset, accountId); - return getOrderHistoriesResponce; + return getOrderHistoriesResponse; + } + + @Post('/licenses/issue') + @ApiResponse({ + status: HttpStatus.OK, + type: IssueLicenseResponse, + description: '成功時のレスポンス', + }) + @ApiResponse({ + status: HttpStatus.BAD_REQUEST, + description: + '自身のライセンス数が不足している場合/すでに対象注文が発行済の場合', + type: ErrorResponse, + }) + @ApiResponse({ + status: HttpStatus.UNAUTHORIZED, + description: '認証エラー', + type: ErrorResponse, + }) + @ApiResponse({ + status: HttpStatus.INTERNAL_SERVER_ERROR, + description: '想定外のサーバーエラー', + type: ErrorResponse, + }) + @ApiOperation({ operationId: 'issueLicense' }) + @ApiBearerAuth() + @UseGuards(AuthGuard) + @UseGuards( + RoleGuard.requireds({ + roles: [ADMIN_ROLES.ADMIN], + tiers: [TIERS.TIER1, TIERS.TIER2, TIERS.TIER3, TIERS.TIER4], + }), + ) + async issueLicense( + @Req() req: Request, + @Body() body: IssueLicenseRequest, + ): Promise { + console.log(req.header('Authorization')); + console.log(body); + const { orderedAccountId, poNumber } = body; + + /*await this.licensesService.issueLicense( + orderedAccountId + poNumber, + ); + */ + + return {}; } } diff --git a/dictation_server/src/features/accounts/accounts.service.spec.ts b/dictation_server/src/features/accounts/accounts.service.spec.ts index db6ed7d..2e4f66e 100644 --- a/dictation_server/src/features/accounts/accounts.service.spec.ts +++ b/dictation_server/src/features/accounts/accounts.service.spec.ts @@ -411,25 +411,25 @@ describe('createPartnerAccount', () => { const offset = 0; const limit = 20; - const responce = await service.getPartnerLicenses(limit, offset, accountId); + const response = await service.getPartnerLicenses(limit, offset, accountId); - expect(responce.total).toBe(2); + expect(response.total).toBe(2); - expect(responce.ownPartnerLicense.companyName).toBe('PARENTCORP'); - expect(responce.ownPartnerLicense.tier).toBe(1); - expect(responce.ownPartnerLicense.stockLicense).toBe(3); - expect(responce.ownPartnerLicense.issuedRequested).toBe(15); - expect(responce.ownPartnerLicense.shortage).toBe(12); + expect(response.ownPartnerLicense.companyName).toBe('PARENTCORP'); + expect(response.ownPartnerLicense.tier).toBe(1); + expect(response.ownPartnerLicense.stockLicense).toBe(3); + expect(response.ownPartnerLicense.issuedRequested).toBe(15); + expect(response.ownPartnerLicense.shortage).toBe(12); - expect(responce.childrenPartnerLicenses[0].companyName).toBe('CHILDCORP1'); - expect(responce.childrenPartnerLicenses[0].tier).toBe(2); - expect(responce.childrenPartnerLicenses[0].stockLicense).toBe(1); - expect(responce.childrenPartnerLicenses[0].issueRequesting).toBe(10); + expect(response.childrenPartnerLicenses[0].companyName).toBe('CHILDCORP1'); + expect(response.childrenPartnerLicenses[0].tier).toBe(2); + expect(response.childrenPartnerLicenses[0].stockLicense).toBe(1); + expect(response.childrenPartnerLicenses[0].issueRequesting).toBe(10); - expect(responce.childrenPartnerLicenses[1].companyName).toBe('CHILDCORP2'); - expect(responce.childrenPartnerLicenses[1].tier).toBe(2); - expect(responce.childrenPartnerLicenses[1].stockLicense).toBe(2); - expect(responce.childrenPartnerLicenses[1].issueRequesting).toBe(5); + expect(response.childrenPartnerLicenses[1].companyName).toBe('CHILDCORP2'); + expect(response.childrenPartnerLicenses[1].tier).toBe(2); + expect(response.childrenPartnerLicenses[1].stockLicense).toBe(2); + expect(response.childrenPartnerLicenses[1].issueRequesting).toBe(5); }); }); @@ -505,12 +505,12 @@ describe('getOrderHistories', () => { const offset = 1; const limit = 2; - const responce = await service.getOrderHistories(limit, offset, accountId); + const response = await service.getOrderHistories(limit, offset, accountId); - expect(responce.total).toBe(5); + expect(response.total).toBe(5); - expect(responce.orderHistories[0].poNumber).toBe('TEST004'); - expect(responce.orderHistories[1].poNumber).toBe('TEST003'); + expect(response.orderHistories[0].poNumber).toBe('TEST004'); + expect(response.orderHistories[1].poNumber).toBe('TEST003'); }); it('注文履歴情報の取得に失敗した場合、エラーとなる', async () => { const limit = 0; diff --git a/dictation_server/src/features/accounts/accounts.service.ts b/dictation_server/src/features/accounts/accounts.service.ts index 3d53f23..14c20a1 100644 --- a/dictation_server/src/features/accounts/accounts.service.ts +++ b/dictation_server/src/features/accounts/accounts.service.ts @@ -20,7 +20,7 @@ import { TypistGroup, GetPartnerLicensesResponse, PartnerLicenseInfo, - GetOrderHistoriesResponce, + GetOrderHistoriesResponse, LicenseOrder, } from './types/types'; import { DateWithZeroTime } from '../licenses/types/types'; @@ -504,13 +504,13 @@ export class AccountsService { * @param limit * @param offset * @param accountId - * @returns getOrderHistoriesResponce + * @returns getOrderHistoriesResponse */ async getOrderHistories( limit: number, offset: number, accountId: number, - ): Promise { + ): Promise { this.logger.log(`[IN] ${this.getOrderHistories.name}`); try { @@ -542,7 +542,7 @@ export class AccountsService { }; orderHistories.push(returnLicenseOrder); } - const getOrderHistoriesResponse: GetOrderHistoriesResponce = { + const getOrderHistoriesResponse: GetOrderHistoriesResponse = { total: licenseHistoryInfo.total, orderHistories: orderHistories, }; diff --git a/dictation_server/src/features/accounts/types/types.ts b/dictation_server/src/features/accounts/types/types.ts index bb2930f..e9a1334 100644 --- a/dictation_server/src/features/accounts/types/types.ts +++ b/dictation_server/src/features/accounts/types/types.ts @@ -1,5 +1,5 @@ import { ApiProperty } from '@nestjs/swagger'; -import { IsEmail, IsInt, IsOptional, Min } from 'class-validator'; +import { IsEmail, IsInt, IsOptional, Matches, Min } from 'class-validator'; export class CreateAccountRequest { @ApiProperty() @@ -218,9 +218,19 @@ export class LicenseOrder { @ApiProperty({ description: '注文状態' }) status: string; } -export class GetOrderHistoriesResponce { +export class GetOrderHistoriesResponse { @ApiProperty({ description: '合計件数' }) total: number; @ApiProperty({ type: [LicenseOrder] }) orderHistories: LicenseOrder[]; } + +export class IssueLicenseRequest { + @ApiProperty({ description: '注文元アカウントID' }) + orderedAccountId: number; + @ApiProperty({ description: 'POナンバー' }) + @Matches(/^[A-Z0-9]+$/) + poNumber: string; +} + +export class IssueLicenseResponse {}