Merged PR 136: API実装(ソート条件取得API)
## 概要 [Task1923: API実装(ソート条件取得API)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/1923) - ソート条件取得APIを実装 - テスト追加 ## レビューポイント - ソート条件取得APIのレスポンスのデータは足りているか ## UIの変更 - Before/Afterのスクショなど - スクショ置き場 ## 動作確認状況 - ローカルで確認 ## 補足 - 相談、参考資料などがあれば
This commit is contained in:
parent
9441049201
commit
942ac30d8f
@ -398,7 +398,9 @@
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": { "$ref": "#/components/schemas/SortCriteriaRequest" }
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PostSortCriteriaRequest"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -408,7 +410,51 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/SortCriteriaResponse"
|
||||
"$ref": "#/components/schemas/PostSortCriteriaResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"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": ["users"],
|
||||
"security": [{ "bearer": [] }]
|
||||
},
|
||||
"get": {
|
||||
"operationId": "getSortCcriteria",
|
||||
"summary": "",
|
||||
"description": "ログインしているユーザーのタスクソート条件を取得します",
|
||||
"parameters": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "成功時のレスポンス",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PostSortCriteriaResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1529,7 +1575,7 @@
|
||||
"prompt"
|
||||
]
|
||||
},
|
||||
"SortCriteriaRequest": {
|
||||
"PostSortCriteriaRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"direction": { "type": "string", "description": "ASC/DESC" },
|
||||
@ -1540,7 +1586,7 @@
|
||||
},
|
||||
"required": ["direction", "paramName"]
|
||||
},
|
||||
"SortCriteriaResponse": { "type": "object", "properties": {} },
|
||||
"PostSortCriteriaResponse": { "type": "object", "properties": {} },
|
||||
"AudioOptionItem": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@ -12,6 +12,10 @@ import { UsersRepositoryService } from '../../../repositories/users/users.reposi
|
||||
import { UsersService } from '../users.service';
|
||||
import { SortCriteria } from '../../../repositories/sort_criteria/entity/sort_criteria.entity';
|
||||
import { SortCriteriaRepositoryService } from '../../../repositories/sort_criteria/sort_criteria.repository.service';
|
||||
import {
|
||||
SortDirection,
|
||||
TaskListSortableAttribute,
|
||||
} from '../../../common/types/sort';
|
||||
|
||||
export type CryptoMockValue = {
|
||||
getPublicKey: string | Error;
|
||||
@ -19,6 +23,7 @@ export type CryptoMockValue = {
|
||||
|
||||
export type SortCriteriaRepositoryMockValue = {
|
||||
updateSortCriteria: SortCriteria | Error;
|
||||
getSortCriteria: SortCriteria | Error;
|
||||
};
|
||||
|
||||
export type UsersRepositoryMockValue = {
|
||||
@ -93,15 +98,29 @@ export const makeUsersServiceMock = async (
|
||||
export const makeSortCriteriaRepositoryMock = (
|
||||
value: SortCriteriaRepositoryMockValue,
|
||||
) => {
|
||||
const { updateSortCriteria } = value;
|
||||
const { updateSortCriteria, getSortCriteria } = value;
|
||||
|
||||
return {
|
||||
updateSortCriteria:
|
||||
updateSortCriteria instanceof Error
|
||||
? jest.fn<Promise<void>, []>().mockRejectedValue(updateSortCriteria)
|
||||
? jest
|
||||
.fn<
|
||||
Promise<void>,
|
||||
[number, TaskListSortableAttribute, SortDirection]
|
||||
>()
|
||||
.mockRejectedValue(updateSortCriteria)
|
||||
: jest
|
||||
.fn<Promise<SortCriteria>, []>()
|
||||
.fn<
|
||||
Promise<SortCriteria>,
|
||||
[number, TaskListSortableAttribute, SortDirection]
|
||||
>()
|
||||
.mockResolvedValue(updateSortCriteria),
|
||||
getSortCriteria:
|
||||
getSortCriteria instanceof Error
|
||||
? jest.fn<Promise<void>, [number]>().mockRejectedValue(getSortCriteria)
|
||||
: jest
|
||||
.fn<Promise<SortCriteria>, [number]>()
|
||||
.mockResolvedValue(getSortCriteria),
|
||||
};
|
||||
};
|
||||
|
||||
@ -303,6 +322,7 @@ export const makeDefaultSortCriteriaRepositoryMockValue =
|
||||
}
|
||||
return {
|
||||
updateSortCriteria: sortCriteria,
|
||||
getSortCriteria: sortCriteria,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -134,7 +134,7 @@ export class GetRelationsResponse {
|
||||
prompt: boolean;
|
||||
}
|
||||
|
||||
export class SortCriteriaRequest {
|
||||
export class PostSortCriteriaRequest {
|
||||
@ApiProperty({ description: 'ASC/DESC' })
|
||||
@IsIn(['ASC', 'DESC'], { message: 'invalid direction' })
|
||||
direction: string;
|
||||
@ -148,4 +148,16 @@ export class SortCriteriaRequest {
|
||||
paramName: string;
|
||||
}
|
||||
|
||||
export class SortCriteriaResponse {}
|
||||
export class PostSortCriteriaResponse {}
|
||||
|
||||
export class GetSortCriteriaRequest {}
|
||||
|
||||
export class GetSortCriteriaResponse {
|
||||
@ApiProperty({ description: 'ASC/DESC' })
|
||||
direction: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: `${TASK_LIST_SORTABLE_ATTRIBUTES.join('/')}`,
|
||||
})
|
||||
paramName: string;
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import {
|
||||
Req,
|
||||
HttpException,
|
||||
UseGuards,
|
||||
Query,
|
||||
} from '@nestjs/common';
|
||||
import {
|
||||
ApiBearerAuth,
|
||||
@ -29,8 +30,10 @@ import {
|
||||
GetUsersResponse,
|
||||
SignupRequest,
|
||||
SignupResponse,
|
||||
SortCriteriaRequest,
|
||||
SortCriteriaResponse,
|
||||
PostSortCriteriaRequest,
|
||||
PostSortCriteriaResponse,
|
||||
GetSortCriteriaRequest,
|
||||
GetSortCriteriaResponse,
|
||||
} from './types/types';
|
||||
import { UsersService } from './users.service';
|
||||
import jwt from 'jsonwebtoken';
|
||||
@ -279,7 +282,7 @@ export class UsersController {
|
||||
|
||||
@ApiResponse({
|
||||
status: HttpStatus.OK,
|
||||
type: SortCriteriaResponse,
|
||||
type: PostSortCriteriaResponse,
|
||||
description: '成功時のレスポンス',
|
||||
})
|
||||
@ApiResponse({
|
||||
@ -305,9 +308,9 @@ export class UsersController {
|
||||
@UseGuards(AuthGuard)
|
||||
@Post('sort-criteria')
|
||||
async updateSortCriteria(
|
||||
@Body() body: SortCriteriaRequest,
|
||||
@Body() body: PostSortCriteriaRequest,
|
||||
@Req() req: Request,
|
||||
): Promise<SortCriteriaResponse> {
|
||||
): Promise<PostSortCriteriaResponse> {
|
||||
const { direction, paramName } = body;
|
||||
const accessToken = retrieveAuthorizationToken(req);
|
||||
const decodedToken = jwt.decode(accessToken, { json: true }) as AccessToken;
|
||||
@ -329,4 +332,40 @@ export class UsersController {
|
||||
);
|
||||
return {};
|
||||
}
|
||||
|
||||
@ApiResponse({
|
||||
status: HttpStatus.OK,
|
||||
type: GetSortCriteriaResponse,
|
||||
description: '成功時のレスポンス',
|
||||
})
|
||||
@ApiResponse({
|
||||
status: HttpStatus.UNAUTHORIZED,
|
||||
description: '認証エラー',
|
||||
type: ErrorResponse,
|
||||
})
|
||||
@ApiResponse({
|
||||
status: HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
description: '想定外のサーバーエラー',
|
||||
type: ErrorResponse,
|
||||
})
|
||||
@ApiOperation({
|
||||
operationId: 'getSortCcriteria',
|
||||
description: 'ログインしているユーザーのタスクソート条件を取得します',
|
||||
})
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(AuthGuard)
|
||||
@Get('sort-criteria')
|
||||
async getSortCriteria(
|
||||
@Query() query: GetSortCriteriaRequest,
|
||||
@Req() req: Request,
|
||||
): Promise<GetSortCriteriaResponse> {
|
||||
const {} = query;
|
||||
const accessToken = retrieveAuthorizationToken(req);
|
||||
const decodedToken = jwt.decode(accessToken, { json: true }) as AccessToken;
|
||||
|
||||
const { direction, paramName } = await this.usersService.getSortCriteria(
|
||||
decodedToken,
|
||||
);
|
||||
return { direction, paramName };
|
||||
}
|
||||
}
|
||||
|
||||
@ -727,7 +727,6 @@ it('ユーザー情報が存在せず、ソート条件を変更できない', a
|
||||
const sortCriteriaRepositoryMockValue =
|
||||
makeDefaultSortCriteriaRepositoryMockValue();
|
||||
|
||||
// モックでDBからのユーザ取得がエラーとなる
|
||||
usersRepositoryMockValue.findUserByExternalId = new Error('user not found');
|
||||
|
||||
const service = await makeUsersServiceMock(
|
||||
@ -764,8 +763,6 @@ it('ソート条件が存在せず、ソート条件を変更できない', asyn
|
||||
'sort criteria not found',
|
||||
);
|
||||
|
||||
// モックでDBからのユーザ取得を空にする
|
||||
|
||||
const service = await makeUsersServiceMock(
|
||||
cryptoMockValue,
|
||||
usersRepositoryMockValue,
|
||||
@ -787,3 +784,100 @@ it('ソート条件が存在せず、ソート条件を変更できない', asyn
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it('ソート条件を取得できる', async () => {
|
||||
const cryptoMockValue = makeDefaultCryptoMockValue();
|
||||
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
|
||||
const adb2cParam = makeDefaultAdB2cMockValue();
|
||||
const sendgridMockValue = makeDefaultSendGridlValue();
|
||||
const configMockValue = makeDefaultConfigValue();
|
||||
const sortCriteriaRepositoryMockValue =
|
||||
makeDefaultSortCriteriaRepositoryMockValue();
|
||||
const service = await makeUsersServiceMock(
|
||||
cryptoMockValue,
|
||||
usersRepositoryMockValue,
|
||||
adb2cParam,
|
||||
sendgridMockValue,
|
||||
configMockValue,
|
||||
sortCriteriaRepositoryMockValue,
|
||||
);
|
||||
|
||||
expect(
|
||||
await service.getSortCriteria({
|
||||
role: 'none admin',
|
||||
userId: 'xxxxxxxxxxxx',
|
||||
}),
|
||||
).toEqual({ direction: 'ASC', paramName: 'JOB_NUMBER' });
|
||||
});
|
||||
|
||||
it('ソート条件が存在せず、ソート条件を取得できない', async () => {
|
||||
const cryptoMockValue = makeDefaultCryptoMockValue();
|
||||
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
|
||||
const adb2cParam = makeDefaultAdB2cMockValue();
|
||||
const sendgridMockValue = makeDefaultSendGridlValue();
|
||||
const configMockValue = makeDefaultConfigValue();
|
||||
const sortCriteriaRepositoryMockValue =
|
||||
makeDefaultSortCriteriaRepositoryMockValue();
|
||||
|
||||
sortCriteriaRepositoryMockValue.getSortCriteria = new Error(
|
||||
'sort criteria not found',
|
||||
);
|
||||
|
||||
const service = await makeUsersServiceMock(
|
||||
cryptoMockValue,
|
||||
usersRepositoryMockValue,
|
||||
adb2cParam,
|
||||
sendgridMockValue,
|
||||
configMockValue,
|
||||
sortCriteriaRepositoryMockValue,
|
||||
);
|
||||
|
||||
await expect(
|
||||
service.getSortCriteria({
|
||||
role: 'none admin',
|
||||
userId: 'xxxxxxxxxxxx',
|
||||
}),
|
||||
).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it('DBから取得した値が不正だった場合、エラーとなる', async () => {
|
||||
const cryptoMockValue = makeDefaultCryptoMockValue();
|
||||
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
|
||||
const adb2cParam = makeDefaultAdB2cMockValue();
|
||||
const sendgridMockValue = makeDefaultSendGridlValue();
|
||||
const configMockValue = makeDefaultConfigValue();
|
||||
const sortCriteriaRepositoryMockValue =
|
||||
makeDefaultSortCriteriaRepositoryMockValue();
|
||||
sortCriteriaRepositoryMockValue.getSortCriteria = {
|
||||
id: 1,
|
||||
direction: 'AAA',
|
||||
parameter: 'BBBBB',
|
||||
user_id: 1,
|
||||
};
|
||||
|
||||
const service = await makeUsersServiceMock(
|
||||
cryptoMockValue,
|
||||
usersRepositoryMockValue,
|
||||
adb2cParam,
|
||||
sendgridMockValue,
|
||||
configMockValue,
|
||||
sortCriteriaRepositoryMockValue,
|
||||
);
|
||||
|
||||
await expect(
|
||||
service.getSortCriteria({
|
||||
role: 'none admin',
|
||||
userId: 'xxxxxxxxxxxx',
|
||||
}),
|
||||
).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
@ -7,6 +7,8 @@ import { AccessToken } from '../../common/token';
|
||||
import {
|
||||
TaskListSortableAttribute,
|
||||
SortDirection,
|
||||
isTaskListSortableAttribute,
|
||||
isSortDirection,
|
||||
} from '../../common/types/sort';
|
||||
import {
|
||||
AdB2cService,
|
||||
@ -386,4 +388,52 @@ export class UsersService {
|
||||
this.logger.log(`[OUT] ${this.updateSortCriteria.name}`);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Gets sort criteria
|
||||
* @param token
|
||||
* @returns sort criteria
|
||||
*/
|
||||
async getSortCriteria(token: AccessToken): Promise<{
|
||||
paramName: TaskListSortableAttribute;
|
||||
direction: SortDirection;
|
||||
}> {
|
||||
this.logger.log(`[IN] ${this.getSortCriteria.name}`);
|
||||
let user: EntityUser;
|
||||
try {
|
||||
// ユーザー情報を取得
|
||||
const sub = token.userId;
|
||||
user = await this.usersRepository.findUserByExternalId(sub);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
// ユーザーのソート条件を取得
|
||||
const sortCriteria = await this.sortCriteriaRepository.getSortCriteria(
|
||||
user.id,
|
||||
);
|
||||
const { direction, parameter } = sortCriteria;
|
||||
//型チェック
|
||||
if (
|
||||
!isTaskListSortableAttribute(parameter) ||
|
||||
!isSortDirection(direction)
|
||||
) {
|
||||
throw new Error('The value stored in the DB is invalid.');
|
||||
}
|
||||
return { direction, paramName: parameter };
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(`[OUT] ${this.getSortCriteria.name}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,4 +45,25 @@ export class SortCriteriaRepositoryService {
|
||||
return persisted;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Gets sort criteria
|
||||
* @param userId
|
||||
* @returns sort criteria
|
||||
*/
|
||||
async getSortCriteria(userId: number): Promise<SortCriteria> {
|
||||
this.logger.log(` ${this.updateSortCriteria.name}; userId:${userId}`);
|
||||
|
||||
const repo = this.dataSource.getRepository(SortCriteria);
|
||||
const sortCriteria = await repo.findOne({
|
||||
where: {
|
||||
user_id: userId,
|
||||
},
|
||||
});
|
||||
// 運用上はあり得ないが、プログラム上発生しうるのでエラーとして処理
|
||||
if (!sortCriteria) {
|
||||
throw new Error('sort criteria not found ');
|
||||
}
|
||||
|
||||
return sortCriteria;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user