Merged PR 361: API実装(TypistGroup取得API)
## 概要 [Task2461: API実装(TypistGroup取得API)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2461) - TypistGroup取得APIとテストを実装しました。 ## レビューポイント - DBからの取得ロジックに問題はないか - テストケースは十分か ## UIの変更 - なし ## 動作確認状況 - ローカルで確認
This commit is contained in:
parent
1c4026eff9
commit
5b1c3a0e99
@ -373,7 +373,7 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/GetTypistGroupsResponse"
|
||||
"$ref": "#/components/schemas/GetTypistGroupResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2449,6 +2449,14 @@
|
||||
},
|
||||
"required": ["typistGroups"]
|
||||
},
|
||||
"GetTypistGroupResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"typistGroupName": { "type": "string" },
|
||||
"typistIds": { "type": "array", "items": { "type": "integer" } }
|
||||
},
|
||||
"required": ["typistGroupName", "typistIds"]
|
||||
},
|
||||
"CreateTypistGroupRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@ -47,4 +47,5 @@ export const ErrorCodes = [
|
||||
'E010805', // ライセンス有効期限切れエラー
|
||||
'E010806', // ライセンス割り当て不可エラー
|
||||
'E010807', // ライセンス割り当て解除済みエラー
|
||||
'E010908', // タイピストグループ不在エラー
|
||||
] as const;
|
||||
|
||||
@ -36,4 +36,5 @@ export const errors: Errors = {
|
||||
E010805: 'License is expired Error',
|
||||
E010806: 'License is unavailable Error',
|
||||
E010807: 'License is already deallocated Error',
|
||||
E010908: 'Typist Group not exist Error',
|
||||
};
|
||||
|
||||
@ -245,7 +245,7 @@ export class AccountsController {
|
||||
|
||||
@ApiResponse({
|
||||
status: HttpStatus.OK,
|
||||
type: GetTypistGroupsResponse,
|
||||
type: GetTypistGroupResponse,
|
||||
description: '成功時のレスポンス',
|
||||
})
|
||||
@ApiResponse({
|
||||
@ -276,14 +276,21 @@ export class AccountsController {
|
||||
@Req() req: Request,
|
||||
@Param() param: GetTypistGroupRequest,
|
||||
): Promise<GetTypistGroupResponse> {
|
||||
console.log(req.header('Authorization'));
|
||||
const { typistGroupId } = param;
|
||||
|
||||
// アクセストークン取得
|
||||
const accessToken = retrieveAuthorizationToken(req);
|
||||
const payload = jwt.decode(accessToken, { json: true }) as AccessToken;
|
||||
const { userId } = jwt.decode(accessToken, { json: true }) as AccessToken;
|
||||
|
||||
console.log(param.typistGroupId);
|
||||
const context = makeContext(userId);
|
||||
|
||||
return { typistGroupName: '', typistIds: [] };
|
||||
const typistGroup = await this.accountService.getTypistGroup(
|
||||
context,
|
||||
userId,
|
||||
typistGroupId,
|
||||
);
|
||||
|
||||
return typistGroup;
|
||||
}
|
||||
|
||||
@ApiResponse({
|
||||
|
||||
@ -18,6 +18,7 @@ import {
|
||||
getSortCriteria,
|
||||
getTypistGroup,
|
||||
getTypistGroupMember,
|
||||
createTypistGroup,
|
||||
} from './test/utility';
|
||||
import { DataSource } from 'typeorm';
|
||||
import { makeTestingModule } from '../../common/test/modules';
|
||||
@ -31,7 +32,7 @@ import {
|
||||
} from '../../common/test/utility';
|
||||
import { AccountsService } from './accounts.service';
|
||||
import { Context, makeContext } from '../../common/log';
|
||||
import { TIERS } from '../../constants';
|
||||
import { TIERS, USER_ROLES } from '../../constants';
|
||||
import { License } from '../../repositories/licenses/entity/license.entity';
|
||||
import {
|
||||
overrideAccountsRepositoryService,
|
||||
@ -2590,3 +2591,188 @@ describe('createTypistGroup', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getTypistGroup', () => {
|
||||
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('指定したIDのTypistGroupを取得できる', async () => {
|
||||
const module = await makeTestingModule(source);
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
|
||||
// 作成したアカウントにユーザーを3名追加する
|
||||
const typiptUserExternalIds = [
|
||||
'typist-user-external-id1',
|
||||
'typist-user-external-id2',
|
||||
'typist-user-external-id3',
|
||||
];
|
||||
const userIds: number[] = [];
|
||||
for (const typiptUserExternalId of typiptUserExternalIds) {
|
||||
const { id: userId } = await makeTestUser(source, {
|
||||
account_id: account.id,
|
||||
external_id: typiptUserExternalId,
|
||||
role: USER_ROLES.TYPIST,
|
||||
});
|
||||
userIds.push(userId);
|
||||
}
|
||||
|
||||
// アカウントにタイピストグループを作成する
|
||||
const typistGroupName = 'typist-group-name';
|
||||
|
||||
const { id: typistGroupId } = await createTypistGroup(
|
||||
source,
|
||||
account.id,
|
||||
typistGroupName,
|
||||
userIds,
|
||||
);
|
||||
|
||||
//作成したデータを確認
|
||||
{
|
||||
const group = await getTypistGroup(source, account.id);
|
||||
expect(group.length).toBe(1);
|
||||
expect(group[0].name).toBe(typistGroupName);
|
||||
const groupUsers = await getTypistGroupMember(source, group[0].id);
|
||||
expect(groupUsers.length).toBe(3);
|
||||
expect(groupUsers.map((user) => user.user_id)).toEqual(userIds);
|
||||
}
|
||||
const service = module.get<AccountsService>(AccountsService);
|
||||
const context = makeContext(admin.external_id);
|
||||
const typistGroup = await service.getTypistGroup(
|
||||
context,
|
||||
admin.external_id,
|
||||
typistGroupId,
|
||||
);
|
||||
//実行結果を確認
|
||||
{
|
||||
const typistGroups = await getTypistGroup(source, account.id);
|
||||
expect(typistGroups.length).toBe(1);
|
||||
expect(typistGroup.typistGroupName).toBe(typistGroupName);
|
||||
expect(typistGroup.typistIds.length).toBe(3);
|
||||
expect(typistGroup.typistIds).toEqual(userIds);
|
||||
}
|
||||
});
|
||||
|
||||
it('指定したタイピストグループIDのタイピストグループが存在しない場合、400エラーを返却する', async () => {
|
||||
const module = await makeTestingModule(source);
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
// 作成したアカウントにユーザーを3名追加する
|
||||
const typiptUserExternalIds = [
|
||||
'typist-user-external-id1',
|
||||
'typist-user-external-id2',
|
||||
'typist-user-external-id3',
|
||||
];
|
||||
const userIds: number[] = [];
|
||||
for (const typiptUserExternalId of typiptUserExternalIds) {
|
||||
const { id: userId } = await makeTestUser(source, {
|
||||
account_id: account.id,
|
||||
external_id: typiptUserExternalId,
|
||||
role: USER_ROLES.TYPIST,
|
||||
});
|
||||
userIds.push(userId);
|
||||
}
|
||||
|
||||
// アカウントにタイピストグループを作成する
|
||||
const typistGroupName = 'typist-group-name';
|
||||
await createTypistGroup(source, account.id, typistGroupName, userIds);
|
||||
|
||||
//作成したデータを確認
|
||||
{
|
||||
const group = await getTypistGroup(source, account.id);
|
||||
expect(group.length).toBe(1);
|
||||
expect(group[0].name).toBe(typistGroupName);
|
||||
const groupUsers = await getTypistGroupMember(source, group[0].id);
|
||||
expect(groupUsers.length).toBe(3);
|
||||
expect(groupUsers.map((user) => user.user_id)).toEqual(userIds);
|
||||
}
|
||||
const service = module.get<AccountsService>(AccountsService);
|
||||
const context = makeContext(admin.external_id);
|
||||
|
||||
try {
|
||||
await service.getTypistGroup(context, admin.external_id, 999);
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
|
||||
expect(e.getResponse()).toEqual(makeErrorResponse('E010908'));
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('DBアクセスに失敗した場合、500エラーを返却する', async () => {
|
||||
const module = await makeTestingModule(source);
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
// 作成したアカウントにユーザーを3名追加する
|
||||
const typiptUserExternalIds = [
|
||||
'typist-user-external-id1',
|
||||
'typist-user-external-id2',
|
||||
'typist-user-external-id3',
|
||||
];
|
||||
const userIds: number[] = [];
|
||||
for (const typiptUserExternalId of typiptUserExternalIds) {
|
||||
const { id: userId } = await makeTestUser(source, {
|
||||
account_id: account.id,
|
||||
external_id: typiptUserExternalId,
|
||||
role: USER_ROLES.TYPIST,
|
||||
});
|
||||
userIds.push(userId);
|
||||
}
|
||||
|
||||
// アカウントにタイピストグループを作成する
|
||||
const typistGroupName = 'typist-group-name';
|
||||
|
||||
const { id: typistGroupId } = await createTypistGroup(
|
||||
source,
|
||||
account.id,
|
||||
typistGroupName,
|
||||
userIds,
|
||||
);
|
||||
|
||||
//作成したデータを確認
|
||||
{
|
||||
const group = await getTypistGroup(source, account.id);
|
||||
expect(group.length).toBe(1);
|
||||
expect(group[0].name).toBe(typistGroupName);
|
||||
const groupUsers = await getTypistGroupMember(source, group[0].id);
|
||||
expect(groupUsers.length).toBe(3);
|
||||
expect(groupUsers.map((user) => user.user_id)).toEqual(userIds);
|
||||
}
|
||||
const service = module.get<AccountsService>(AccountsService);
|
||||
const context = makeContext(admin.external_id);
|
||||
|
||||
//DBアクセスに失敗するようにする
|
||||
const typistGroupService = module.get<UserGroupsRepositoryService>(
|
||||
UserGroupsRepositoryService,
|
||||
);
|
||||
typistGroupService.getTypistGroup = jest
|
||||
.fn()
|
||||
.mockRejectedValue('DB failed');
|
||||
|
||||
try {
|
||||
await service.getTypistGroup(context, admin.external_id, typistGroupId);
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
expect(e.getResponse()).toEqual(makeErrorResponse('E009999'));
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@ -21,6 +21,7 @@ import {
|
||||
GetDealersResponse,
|
||||
Dealer,
|
||||
GetMyAccountResponse,
|
||||
GetTypistGroupResponse,
|
||||
} from './types/types';
|
||||
import {
|
||||
DateWithZeroTime,
|
||||
@ -40,6 +41,7 @@ import {
|
||||
OrderNotFoundError,
|
||||
} from '../../repositories/licenses/errors/types';
|
||||
import { BlobstorageService } from '../../gateways/blobstorage/blobstorage.service';
|
||||
import { TypistGroupNotExistError } from '../../repositories/user_groups/errors/types';
|
||||
import { TypistIdInvalidError } from '../../repositories/user_groups/errors/types';
|
||||
|
||||
@Injectable()
|
||||
@ -416,6 +418,61 @@ export class AccountsService {
|
||||
this.logger.log(`[OUT] ${this.getTypistGroups.name}`);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* IDを指定してタイピストグループを取得する
|
||||
* @param context
|
||||
* @param externalId
|
||||
* @param typistGroupId
|
||||
* @returns typist group
|
||||
*/
|
||||
async getTypistGroup(
|
||||
context: Context,
|
||||
externalId: string,
|
||||
typistGroupId: number,
|
||||
): Promise<GetTypistGroupResponse> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.getTypistGroup.name} | params: { externalId: ${externalId}, typistGroupId: ${typistGroupId} };`,
|
||||
);
|
||||
|
||||
try {
|
||||
const { account_id } = await this.usersRepository.findUserByExternalId(
|
||||
externalId,
|
||||
);
|
||||
const userGroup = await this.userGroupsRepository.getTypistGroup(
|
||||
account_id,
|
||||
typistGroupId,
|
||||
);
|
||||
|
||||
return {
|
||||
typistGroupName: userGroup.name,
|
||||
typistIds: userGroup.userGroupMembers.map((x) => x.user_id),
|
||||
};
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case TypistGroupNotExistError:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E010908'),
|
||||
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.trackingId}] ${this.getTypistGroup.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets typists
|
||||
|
||||
@ -108,3 +108,34 @@ export const getTypistGroupMember = async (
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// タイピストグループを作成する
|
||||
export const createTypistGroup = async (
|
||||
datasource: DataSource,
|
||||
accountId: number,
|
||||
name: string,
|
||||
memberIds: number[],
|
||||
): Promise<UserGroup> => {
|
||||
const { identifiers } = await datasource.getRepository(UserGroup).insert({
|
||||
account_id: accountId,
|
||||
name: name,
|
||||
created_by: 'test_runner',
|
||||
created_at: new Date(),
|
||||
updated_by: 'updater',
|
||||
updated_at: new Date(),
|
||||
});
|
||||
const userGroup = identifiers.pop() as UserGroup;
|
||||
|
||||
for (const memberId of memberIds) {
|
||||
await datasource.getRepository(UserGroupMember).insert({
|
||||
user_group_id: userGroup.id,
|
||||
user_id: memberId,
|
||||
created_by: 'test_runner',
|
||||
created_at: new Date(),
|
||||
updated_by: 'updater',
|
||||
updated_at: new Date(),
|
||||
});
|
||||
}
|
||||
|
||||
return userGroup;
|
||||
};
|
||||
|
||||
@ -1,2 +1,4 @@
|
||||
// タイピストグループが存在しないエラー
|
||||
export class TypistGroupNotExistError extends Error {}
|
||||
// typistIdが不正な場合のエラー
|
||||
export class TypistIdInvalidError extends Error {}
|
||||
|
||||
@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common';
|
||||
import { DataSource, In, IsNull } from 'typeorm';
|
||||
import { UserGroup } from './entity/user_group.entity';
|
||||
import { UserGroupMember } from './entity/user_group_member.entity';
|
||||
import { TypistGroupNotExistError } from './errors/types';
|
||||
import { User } from '../users/entity/user.entity';
|
||||
import { TypistIdInvalidError } from './errors/types';
|
||||
import { USER_ROLES } from '../../constants';
|
||||
@ -46,6 +47,40 @@ export class UserGroupsRepositoryService {
|
||||
return groupMembers;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* タイピストグループと所属するメンバーのIDを取得します
|
||||
* @param accountId
|
||||
* @param typistGroupId
|
||||
* @returns typist group
|
||||
*/
|
||||
async getTypistGroup(
|
||||
accountId: number,
|
||||
typistGroupId: number,
|
||||
): Promise<UserGroup> {
|
||||
return await this.dataSource.transaction(async (entityManager) => {
|
||||
const userGroupRepo = entityManager.getRepository(UserGroup);
|
||||
|
||||
const userGroup = await userGroupRepo.findOne({
|
||||
where: {
|
||||
id: typistGroupId,
|
||||
account_id: accountId,
|
||||
deleted_at: IsNull(),
|
||||
},
|
||||
relations: {
|
||||
userGroupMembers: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!userGroup) {
|
||||
throw new TypistGroupNotExistError(
|
||||
`Typist Group is not exist. typistGroupId: ${typistGroupId}`,
|
||||
);
|
||||
}
|
||||
return userGroup;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定したアカウントIDでタイピストグループを作成し、そのタイピストグループとtypistIdsのユーザーを紐付ける
|
||||
* @param accountId
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user