Merged PR 817: API IF実装(親アカウント変更API)
## 概要 [Task3852: API IF実装](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/3852) - 親アカウント変更APIのIFを実装し、OpenAPIの生成もしました。 - 影響範囲(他の機能にも影響があるか) - なし ## レビューポイント - controllerのメソッド名にほか良い案ないか? - validationに過不足や間違いないか? - ~~controllerのテストは正常系ひとつだけ追加しているが、他にあったほうがいいものあるか?~~ - ~~個人的には、テスト追加してもnpmライブラリのvalidatorのテストになるだけな気がするため不要では?と思っています。~~ - 「npmライブラリのvalidatorを正しいパラメータで正しく利用しているか」が目的であるとの認識を得たため異常系も追加しました。 ## 動作確認状況 - apigenを実行してOpenAPI生成できることを確認、controllerテスト通ることを確認。 - 行った修正がデグレを発生させていないことを確認できるか - 新規APIのため無し
This commit is contained in:
parent
2e6b7c8ab5
commit
f386a8f7e0
@ -1664,6 +1664,59 @@
|
||||
"security": [{ "bearer": [] }]
|
||||
}
|
||||
},
|
||||
"/accounts/parent/switch": {
|
||||
"post": {
|
||||
"operationId": "switchParent",
|
||||
"summary": "",
|
||||
"parameters": [],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": { "$ref": "#/components/schemas/SwitchParentRequest" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "成功時のレスポンス",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/SwitchParentResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"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",
|
||||
@ -4541,6 +4594,23 @@
|
||||
"required": ["accountId", "restricted"]
|
||||
},
|
||||
"UpdateRestrictionStatusResponse": { "type": "object", "properties": {} },
|
||||
"SwitchParentRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"to": {
|
||||
"type": "number",
|
||||
"description": "切り替え先の親アカウントID"
|
||||
},
|
||||
"children": {
|
||||
"minItems": 1,
|
||||
"description": "親を変更したいアカウントIDのリスト",
|
||||
"type": "array",
|
||||
"items": { "type": "integer" }
|
||||
}
|
||||
},
|
||||
"required": ["to", "children"]
|
||||
},
|
||||
"SwitchParentResponse": { "type": "object", "properties": {} },
|
||||
"ConfirmRequest": {
|
||||
"type": "object",
|
||||
"properties": { "token": { "type": "string" } },
|
||||
|
||||
@ -3,6 +3,9 @@ import { AccountsController } from './accounts.controller';
|
||||
import { AccountsService } from './accounts.service';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { AuthService } from '../auth/auth.service';
|
||||
import { SwitchParentRequest } from './types/types';
|
||||
import { plainToClass } from 'class-transformer';
|
||||
import { validate } from 'class-validator';
|
||||
|
||||
describe('AccountsController', () => {
|
||||
let controller: AccountsController;
|
||||
@ -32,4 +35,39 @@ describe('AccountsController', () => {
|
||||
it('should be defined', () => {
|
||||
expect(controller).toBeDefined();
|
||||
});
|
||||
|
||||
describe('valdation switchParentRequest', () => {
|
||||
it('最低限の有効なリクエストが成功する', async () => {
|
||||
const request = new SwitchParentRequest();
|
||||
request.to = 1;
|
||||
request.children = [2];
|
||||
|
||||
const valdationObject = plainToClass(SwitchParentRequest, request);
|
||||
|
||||
const errors = await validate(valdationObject);
|
||||
expect(errors.length).toBe(0);
|
||||
});
|
||||
|
||||
it('子アカウントが指定されていない場合、リクエストが失敗する', async () => {
|
||||
const request = new SwitchParentRequest();
|
||||
request.to = 1;
|
||||
request.children = [];
|
||||
|
||||
const valdationObject = plainToClass(SwitchParentRequest, request);
|
||||
|
||||
const errors = await validate(valdationObject);
|
||||
expect(errors.length).toBe(1);
|
||||
});
|
||||
|
||||
it('子アカウントが重複指定されている場合、リクエストが失敗する', async () => {
|
||||
const request = new SwitchParentRequest();
|
||||
request.to = 1;
|
||||
request.children = [2, 2];
|
||||
|
||||
const valdationObject = plainToClass(SwitchParentRequest, request);
|
||||
|
||||
const errors = await validate(valdationObject);
|
||||
expect(errors.length).toBe(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -77,6 +77,8 @@ import {
|
||||
UpdateFileDeleteSettingResponse,
|
||||
UpdateRestrictionStatusRequest,
|
||||
UpdateRestrictionStatusResponse,
|
||||
SwitchParentRequest,
|
||||
SwitchParentResponse,
|
||||
} from './types/types';
|
||||
import { USER_ROLES, ADMIN_ROLES, TIERS } from '../../constants';
|
||||
import { AuthGuard } from '../../common/guards/auth/authguards';
|
||||
@ -2319,4 +2321,84 @@ export class AccountsController {
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@ApiResponse({
|
||||
status: HttpStatus.OK,
|
||||
type: SwitchParentResponse,
|
||||
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: 'switchParent' })
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(AuthGuard)
|
||||
@UseGuards(
|
||||
RoleGuard.requireds({
|
||||
roles: [ADMIN_ROLES.ADMIN],
|
||||
tiers: [TIERS.TIER1, TIERS.TIER2],
|
||||
}),
|
||||
)
|
||||
@Post('parent/switch')
|
||||
async switchParent(
|
||||
@Req() req: Request,
|
||||
@Body() body: SwitchParentRequest,
|
||||
): Promise<SwitchParentResponse> {
|
||||
const accessToken = retrieveAuthorizationToken(req);
|
||||
if (!accessToken) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000107'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
|
||||
const ip = retrieveIp(req);
|
||||
if (!ip) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000401'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
|
||||
const requestId = retrieveRequestId(req);
|
||||
if (!requestId) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000501'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
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, requestId);
|
||||
this.logger.log(`[${context.getTrackingId()}] ip : ${ip}`);
|
||||
|
||||
// TODO:service層を呼び出す。本実装時に以下は削除する。
|
||||
const { to, children } = body;
|
||||
this.logger.log(
|
||||
`[${context.getTrackingId()}] to : ${to}, children : ${children.join(
|
||||
', ',
|
||||
)}`,
|
||||
);
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
@ -369,6 +369,27 @@ export class UpdateRestrictionStatusRequest {
|
||||
restricted: boolean;
|
||||
}
|
||||
|
||||
export class SwitchParentRequest {
|
||||
@ApiProperty({ description: '切り替え先の親アカウントID' })
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
@Min(1)
|
||||
to: number;
|
||||
|
||||
@ApiProperty({
|
||||
minItems: 1,
|
||||
isArray: true,
|
||||
type: 'integer',
|
||||
description: '親を変更したいアカウントIDのリスト',
|
||||
})
|
||||
@ArrayMinSize(1)
|
||||
@IsArray()
|
||||
@IsInt({ each: true })
|
||||
@Min(1, { each: true })
|
||||
@IsUnique()
|
||||
children: number[];
|
||||
}
|
||||
|
||||
// ==============================
|
||||
// RESPONSE
|
||||
// ==============================
|
||||
@ -686,6 +707,8 @@ export class UpdateFileDeleteSettingResponse {}
|
||||
|
||||
export class UpdateRestrictionStatusResponse {}
|
||||
|
||||
export class SwitchParentResponse {}
|
||||
|
||||
// ==============================
|
||||
// Request/Response外の型
|
||||
// TODO: Request/Response/その他の型を別ファイルに分ける
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user