Merged PR 724: API実装

## 概要
[Task3535: API実装](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/3535)

- タイピストグループ削除APIとテストを実装しました。

accountのテストがうまくいっていないようなので別途見直します。
※タイピストグループ削除のテストはうまくいっています

## レビューポイント
- エラーケースと出力されるコードは適切でしょうか?
- テストケースは適切でしょうか?

## UIの変更
- なし

## 動作確認状況
- ローカルで確認
This commit is contained in:
makabe.t 2024-02-06 07:46:57 +00:00
parent feeec9d1f5
commit 19b544540e
10 changed files with 620 additions and 25 deletions

View File

@ -76,4 +76,7 @@ export const ErrorCodes = [
'E014007', // ユーザー削除エラー(削除しようとしたユーザーが有効なライセンスを持っていた)
'E014008', // ユーザー削除エラー(削除しようとしたユーザーが自分自身だった)
'E014009', // ユーザー削除エラー(削除しようとしたユーザーがタスクのルーティング(文字起こし候補)になっている場合)
'E015001', // タイピストグループ削除エラー(削除しようとしたタイピストグループがすでに削除済みだった)
'E015002', // タイピストグループ削除エラー削除しようとしたタイピストグループがWorkflowのTypist候補として指定されていた
'E015003', // タイピストグループ削除エラー(削除しようとしたタイピストグループがチェックアウト可能なタスクが存在した)
] as const;

View File

@ -65,4 +65,7 @@ export const errors: Errors = {
E014007: 'User delete failed Error: enabled license assigned',
E014008: 'User delete failed Error: delete myself',
E014009: 'User delete failed Error: user has checkout permissions.',
E015001: 'Typist Group delete failed Error: already deleted',
E015002: 'Typist Group delete failed Error: workflow assigned',
E015003: 'Typist Group delete failed Error: checkout permission existed',
};

View File

@ -80,7 +80,7 @@ export const makeTestingModule = async (
WorktypesRepositoryModule,
TermsRepositoryModule,
RedisModule,
CacheModule.register({ isGlobal: true }),
CacheModule.register({ isGlobal: true, ttl: 86400 }),
],
providers: [
AuthService,

View File

@ -834,7 +834,7 @@ export class AccountsController {
const context = makeContext(userId, requestId);
this.logger.log(`[${context.getTrackingId()}] ip : ${ip}`);
// TODO: 削除処理
await this.accountService.deleteTypistGroup(context, userId, typistGroupId);
return {};
}

View File

@ -22,6 +22,7 @@ import {
getSortCriteria,
getTypistGroup,
getTypistGroupMember,
getTypistGroupMembers,
getWorktypes,
} from './test/utility';
import { DataSource } from 'typeorm';
@ -46,6 +47,7 @@ import {
LICENSE_ISSUE_STATUS,
LICENSE_TYPE,
OPTION_ITEM_VALUE_TYPE,
TASK_STATUS,
TIERS,
USER_ROLES,
WORKTYPE_MAX_COUNT,
@ -76,9 +78,16 @@ import { AdB2cUser } from '../../gateways/adb2c/types/types';
import { Worktype } from '../../repositories/worktypes/entity/worktype.entity';
import { AccountsRepositoryService } from '../../repositories/accounts/accounts.repository.service';
import { UsersRepositoryService } from '../../repositories/users/users.repository.service';
import { createWorkflow, getWorkflows } from '../workflows/test/utility';
import {
createWorkflow,
createWorkflowTypist,
getWorkflowTypists,
getWorkflows,
} from '../workflows/test/utility';
import { UsersService } from '../users/users.service';
import { truncateAllTable } from '../../common/test/init';
import { createTask, getCheckoutPermissions } from '../tasks/test/utility';
import { createCheckoutPermissions } from '../tasks/test/utility';
describe('createAccount', () => {
let source: DataSource | null = null;
@ -134,8 +143,8 @@ describe('createAccount', () => {
},
});
let _subject: string = "";
let _url: string | undefined = "";
let _subject: string = '';
let _url: string | undefined = '';
overrideSendgridService(service, {
sendMail: async (
context: Context,
@ -199,7 +208,9 @@ describe('createAccount', () => {
// 想定通りのメールが送られているか確認
expect(_subject).toBe('User Registration Notification [U-102]');
expect(_url?.startsWith('http://localhost:8081/mail-confirm?verify=')).toBeTruthy();
expect(
_url?.startsWith('http://localhost:8081/mail-confirm?verify='),
).toBeTruthy();
});
it('アカウントを作成がAzure AD B2Cへの通信失敗によって失敗すると500エラーが発生する', async () => {
@ -2281,6 +2292,9 @@ describe('issueLicense', () => {
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<AccountsService>(AccountsService);
overrideAdB2cService(service, {
getUsers: async () => [],
});
overrideSendgridService(service, {});
const now = new Date();
@ -2378,6 +2392,9 @@ describe('issueLicense', () => {
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<AccountsService>(AccountsService);
overrideAdB2cService(service, {
getUsers: async () => [],
});
overrideSendgridService(service, {});
const now = new Date();
// 親と子アカウントを作成する
@ -2477,6 +2494,9 @@ describe('issueLicense', () => {
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<AccountsService>(AccountsService);
overrideAdB2cService(service, {
getUsers: async () => [],
});
const now = new Date();
// 親と子アカウントを作成する
const { id: parentAccountId } = (
@ -3611,6 +3631,319 @@ describe('updateTypistGroup', () => {
});
});
describe('deleteTypistGroup', () => {
let source: DataSource | null = null;
beforeAll(async () => {
if (source == null) {
source = await (async () => {
const s = new DataSource({
type: 'mysql',
host: 'test_mysql_db',
port: 3306,
username: 'user',
password: 'password',
database: 'odms',
entities: [__dirname + '/../../**/*.entity{.ts,.js}'],
synchronize: false, // trueにすると自動的にmigrationが行われるため注意
});
return await s.initialize();
})();
}
});
beforeEach(async () => {
if (source) {
await truncateAllTable(source);
}
});
afterAll(async () => {
await source?.destroy();
source = null;
});
it('TypistGroupを削除できる', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
// 第五階層のアカウント作成
const { account, admin } = await makeTestAccount(source, { tier: 5 });
// 作成したアカウントにユーザーを追加する
const { id: typistUserId } = await makeTestUser(source, {
account_id: account.id,
external_id: 'typist-user-external-id',
role: USER_ROLES.TYPIST,
});
});
it('TypistGroupを削除できる', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
// 第五階層のアカウント作成
const { account, admin } = await makeTestAccount(source, { tier: 5 });
// 作成したアカウントにユーザーを追加する
const { id: typistUserId } = await makeTestUser(source, {
account_id: account.id,
external_id: 'typist-user-external-id',
role: USER_ROLES.TYPIST,
});
const service = module.get<AccountsService>(AccountsService);
const context = makeContext(admin.external_id, 'requestId');
const typistGroupName = 'typist-group-name';
await service.createTypistGroup(
context,
admin.external_id,
typistGroupName,
[typistUserId],
);
//作成したデータを確認
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(1);
expect(groupUsers[0].user_group_id).toBe(group[0].id);
expect(groupUsers[0].user_id).toBe(typistUserId);
}
await service.deleteTypistGroup(context, admin.external_id, group[0].id);
//実行結果を確認
{
const typistGroups = await getTypistGroup(source, account.id);
expect(typistGroups.length).toBe(0);
const typistGroupUsers = await getTypistGroupMembers(source);
expect(typistGroupUsers.length).toBe(0);
}
});
it('タイピストグループが存在しない場合、400エラーを返却する', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
// 第五階層のアカウント作成
const { account, admin } = await makeTestAccount(source, { tier: 5 });
// 作成したアカウントにユーザーを追加する
const user = await makeTestUser(source, {
account_id: account.id,
external_id: 'typist-user-external-id',
role: USER_ROLES.TYPIST,
});
const typistGroupName = 'typist-group-name';
const service = module.get<AccountsService>(AccountsService);
const context = makeContext(admin.external_id, 'requestId');
await service.createTypistGroup(
context,
admin.external_id,
typistGroupName,
[user.id],
);
//作成したデータを確認
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(1);
expect(groupUsers[0].user_group_id).toBe(group[0].id);
}
try {
await service.deleteTypistGroup(context, admin.external_id, 999);
} catch (e) {
if (e instanceof HttpException) {
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
expect(e.getResponse()).toEqual(makeErrorResponse('E015001'));
} else {
fail();
}
}
});
it('タイピストグループがルーティングルールに紐づいていた場合、400エラーを返却する', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
// 第五階層のアカウント作成
const { account, admin } = await makeTestAccount(source, { tier: 5 });
// 作成したアカウントにユーザーを追加する
const { id: typistUserId } = await makeTestUser(source, {
account_id: account.id,
external_id: 'typist-user-external-id',
role: USER_ROLES.TYPIST,
});
const { id: authorUserId } = await makeTestUser(source, {
account_id: account.id,
external_id: 'author-user-external-id',
role: USER_ROLES.AUTHOR,
});
const service = module.get<AccountsService>(AccountsService);
const context = makeContext(admin.external_id, 'requestId');
const typistGroupName = 'typist-group-name';
await service.createTypistGroup(
context,
admin.external_id,
typistGroupName,
[typistUserId],
);
const group = await getTypistGroup(source, account.id);
const workflow = await createWorkflow(source, account.id, authorUserId);
await createWorkflowTypist(source, workflow.id, undefined, group[0].id);
//作成したデータを確認
{
const workflowTypists = await getWorkflowTypists(source, workflow.id);
expect(group.length).toBe(1);
expect(group[0].name).toBe(typistGroupName);
const groupUsers = await getTypistGroupMember(source, group[0].id);
expect(groupUsers.length).toBe(1);
expect(groupUsers[0].user_group_id).toBe(group[0].id);
expect(groupUsers[0].user_id).toBe(typistUserId);
expect(workflowTypists.length).toBe(1);
expect(workflowTypists[0].typist_group_id).toBe(group[0].id);
}
try {
await service.deleteTypistGroup(context, admin.external_id, group[0].id);
} catch (e) {
if (e instanceof HttpException) {
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
expect(e.getResponse()).toEqual(makeErrorResponse('E015002'));
} else {
fail();
}
}
});
it('タイピストグループがタスクのチェックアウト候補だった場合、400エラーを返却する', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
// 第五階層のアカウント作成
const { account, admin } = await makeTestAccount(source, { tier: 5 });
// 作成したアカウントにユーザーを追加する
const { id: typistUserId } = await makeTestUser(source, {
account_id: account.id,
external_id: 'typist-user-external-id',
role: USER_ROLES.TYPIST,
});
const authorId = 'AUTHOR_ID';
const { id: authorUserId } = await makeTestUser(source, {
account_id: account.id,
external_id: 'author-user-external-id',
role: USER_ROLES.AUTHOR,
author_id: authorId,
});
const service = module.get<AccountsService>(AccountsService);
const context = makeContext(admin.external_id, 'requestId');
const typistGroupName = 'typist-group-name';
await service.createTypistGroup(
context,
admin.external_id,
typistGroupName,
[typistUserId],
);
const group = await getTypistGroup(source, account.id);
const { taskId } = await createTask(
source,
account.id,
authorUserId,
authorId,
'worktypeId',
'01',
'00000001',
TASK_STATUS.UPLOADED,
);
await createCheckoutPermissions(source, taskId, undefined, group[0].id);
//作成したデータを確認
{
const checkoutPermission = await getCheckoutPermissions(source, taskId);
expect(group.length).toBe(1);
expect(group[0].name).toBe(typistGroupName);
const groupUsers = await getTypistGroupMember(source, group[0].id);
expect(groupUsers.length).toBe(1);
expect(groupUsers[0].user_group_id).toBe(group[0].id);
expect(groupUsers[0].user_id).toBe(typistUserId);
expect(checkoutPermission.length).toBe(1);
expect(checkoutPermission[0].user_group_id).toBe(group[0].id);
}
try {
await service.deleteTypistGroup(context, admin.external_id, group[0].id);
} catch (e) {
if (e instanceof HttpException) {
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
expect(e.getResponse()).toEqual(makeErrorResponse('E015003'));
} else {
fail();
}
}
});
it('DBアクセスに失敗した場合、500エラーを返却する', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
// 第五階層のアカウント作成
const { account, admin } = await makeTestAccount(source, { tier: 5 });
// 作成したアカウントにユーザーを追加する
const typiptUserExternalId = 'typist-user-external-id';
const { id: typistUserId } = await makeTestUser(source, {
account_id: account.id,
external_id: typiptUserExternalId,
role: USER_ROLES.TYPIST,
});
const service = module.get<AccountsService>(AccountsService);
const context = makeContext(admin.external_id, 'requestId');
const typistGroupName = 'typist-group-name';
await service.createTypistGroup(
context,
admin.external_id,
typistGroupName,
[typistUserId],
);
//作成したデータを確認
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(1);
expect(groupUsers[0].user_group_id).toEqual(group[0].id);
expect(groupUsers[0].user_id).toEqual(typistUserId);
}
//DBアクセスに失敗するようにする
const typistGroupService = module.get<UserGroupsRepositoryService>(
UserGroupsRepositoryService,
);
typistGroupService.deleteTypistGroup = jest
.fn()
.mockRejectedValue('DB failed');
try {
await service.deleteTypistGroup(context, admin.external_id, group[0].id);
} catch (e) {
if (e instanceof HttpException) {
expect(e.getStatus()).toEqual(HttpStatus.INTERNAL_SERVER_ERROR);
expect(e.getResponse()).toEqual(makeErrorResponse('E009999'));
} else {
fail();
}
}
});
});
describe('getWorktypes', () => {
let source: DataSource | null = null;
beforeAll(async () => {
@ -5256,6 +5589,9 @@ describe('ライセンス発行キャンセル', () => {
);
const service = module.get<AccountsService>(AccountsService);
overrideAdB2cService(service, {
getUsers: async () => [],
});
overrideSendgridService(service, {});
await service.cancelIssue(
makeContext('trackingId', 'requestId'),
@ -5320,6 +5656,9 @@ describe('ライセンス発行キャンセル', () => {
);
const service = module.get<AccountsService>(AccountsService);
overrideAdB2cService(service, {
getUsers: async () => [],
});
overrideSendgridService(service, {});
await service.cancelIssue(
makeContext('trackingId', 'requestId'),
@ -5358,6 +5697,9 @@ describe('ライセンス発行キャンセル', () => {
});
const poNumber = 'CANCEL_TEST';
const service = module.get<AccountsService>(AccountsService);
overrideAdB2cService(service, {
getUsers: async () => [],
});
overrideSendgridService(service, {});
await expect(
service.cancelIssue(
@ -5405,6 +5747,9 @@ describe('ライセンス発行キャンセル', () => {
null,
);
const service = module.get<AccountsService>(AccountsService);
overrideAdB2cService(service, {
getUsers: async () => [],
});
overrideSendgridService(service, {});
await expect(
service.cancelIssue(
@ -5452,6 +5797,9 @@ describe('ライセンス発行キャンセル', () => {
null,
);
const service = module.get<AccountsService>(AccountsService);
overrideAdB2cService(service, {
getUsers: async () => [],
});
overrideSendgridService(service, {});
await expect(
service.cancelIssue(
@ -5500,6 +5848,9 @@ describe('ライセンス発行キャンセル', () => {
null,
);
const service = module.get<AccountsService>(AccountsService);
overrideAdB2cService(service, {
getUsers: async () => [],
});
overrideSendgridService(service, {});
await expect(
service.cancelIssue(
@ -5729,8 +6080,13 @@ describe('アカウント情報更新', () => {
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<AccountsService>(AccountsService);
let _subject: string = "";
let _url: string | undefined = "";
overrideAdB2cService(service, {
getUser: async () => {
return { id: 'admin.external_id', displayName: 'admin' };
},
});
let _subject: string = '';
let _url: string | undefined = '';
overrideSendgridService(service, {
sendMail: async (
context: Context,
@ -5797,6 +6153,11 @@ describe('アカウント情報更新', () => {
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<AccountsService>(AccountsService);
overrideAdB2cService(service, {
getUser: async () => {
return { id: 'admin.external_id', displayName: 'admin' };
},
});
overrideSendgridService(service, {
sendMail: async () => {
return;
@ -5831,6 +6192,11 @@ describe('アカウント情報更新', () => {
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<AccountsService>(AccountsService);
overrideAdB2cService(service, {
getUser: async () => {
return { id: 'admin.external_id', displayName: 'admin' };
},
});
overrideSendgridService(service, {
sendMail: async () => {
return;
@ -5866,6 +6232,11 @@ describe('アカウント情報更新', () => {
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<AccountsService>(AccountsService);
overrideAdB2cService(service, {
getUser: async () => {
return { id: 'admin.external_id', displayName: 'admin' };
},
});
overrideSendgridService(service, {
sendMail: async () => {
return;
@ -5898,6 +6269,11 @@ describe('アカウント情報更新', () => {
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<AccountsService>(AccountsService);
overrideAdB2cService(service, {
getUser: async () => {
return { id: 'admin.external_id', displayName: 'admin' };
},
});
overrideSendgridService(service, {
sendMail: async () => {
return;
@ -5929,6 +6305,11 @@ describe('アカウント情報更新', () => {
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<AccountsService>(AccountsService);
overrideAdB2cService(service, {
getUser: async () => {
return { id: 'admin.external_id', displayName: 'admin' };
},
});
overrideSendgridService(service, {
sendMail: async () => {
return;
@ -6000,6 +6381,9 @@ describe('getAccountInfo', () => {
});
const service = module.get<AccountsService>(AccountsService);
overrideAdB2cService(service, {
getUsers: async () => [],
});
const context = makeContext(admin.external_id, 'requestId');
const accountResponse = await service.getAccountInfo(
@ -6422,6 +6806,14 @@ describe('deleteAccountAndData', () => {
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<AccountsService>(AccountsService);
// ADB2Cユーザーの削除成功
overrideAdB2cService(service, {
deleteUsers: jest.fn(),
getUsers: jest.fn(),
getUser: async () => {
return { id: 'admin.external_id', displayName: 'admin' };
},
});
let _subject: string = '';
let _url: string | undefined = '';
overrideSendgridService(service, {
@ -6672,6 +7064,14 @@ describe('deleteAccountAndData', () => {
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<AccountsService>(AccountsService);
// ADB2Cユーザーの削除成功
overrideAdB2cService(service, {
deleteUsers: jest.fn(),
getUsers: jest.fn(),
getUser: async () => {
return { id: 'admin.external_id', displayName: 'admin' };
},
});
overrideSendgridService(service, {});
const loggerSpy = jest.spyOn(service['logger'], 'log').mockImplementation();
// 第五階層のアカウント作成
@ -6698,11 +7098,6 @@ describe('deleteAccountAndData', () => {
deleteAccountAndInsertArchives: jest.fn().mockRejectedValue(new Error()),
});
// ADB2Cユーザーの削除成功
overrideAdB2cService(service, {
deleteUsers: jest.fn(),
});
// blobstorageコンテナの削除成功
overrideBlobstorageService(service, {
deleteContainer: jest.fn(),
@ -6737,6 +7132,14 @@ describe('deleteAccountAndData', () => {
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<AccountsService>(AccountsService);
// ADB2Cユーザーの削除失敗
overrideAdB2cService(service, {
deleteUsers: jest.fn().mockRejectedValue(new Error()),
getUsers: jest.fn(),
getUser: async () => {
return { id: 'admin.external_id', displayName: 'admin' };
},
});
overrideSendgridService(service, {});
const loggerSpy = jest.spyOn(service['logger'], 'log').mockImplementation();
// 第五階層のアカウント作成
@ -6758,11 +7161,6 @@ describe('deleteAccountAndData', () => {
account_id: tier5Accounts.account.id,
});
// ADB2Cユーザーの削除失敗
overrideAdB2cService(service, {
deleteUsers: jest.fn().mockRejectedValue(new Error()),
});
// blobstorageコンテナの削除成功
overrideBlobstorageService(service, {
deleteContainer: jest.fn(),
@ -6792,6 +7190,14 @@ describe('deleteAccountAndData', () => {
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<AccountsService>(AccountsService);
// ADB2Cユーザーの削除成功
overrideAdB2cService(service, {
deleteUsers: jest.fn(),
getUsers: jest.fn(),
getUser: async () => {
return { id: 'admin.external_id', displayName: 'admin' };
},
});
overrideSendgridService(service, {});
const loggerSpy = jest.spyOn(service['logger'], 'log').mockImplementation();
@ -6814,11 +7220,6 @@ describe('deleteAccountAndData', () => {
account_id: tier5Accounts.account.id,
});
// ADB2Cユーザーの削除成功
overrideAdB2cService(service, {
deleteUsers: jest.fn(),
});
// blobstorageコンテナの削除失敗
overrideBlobstorageService(service, {
deleteContainer: jest.fn().mockRejectedValue(new Error()),
@ -6989,6 +7390,7 @@ describe('getAccountInfoMinimalAccess', () => {
}
});
});
describe('getCompanyName', () => {
let source: DataSource | null = null;
beforeAll(async () => {

View File

@ -60,6 +60,8 @@ import {
} from '../../repositories/licenses/errors/types';
import { BlobstorageService } from '../../gateways/blobstorage/blobstorage.service';
import {
AssignedWorkflowDeleteFailedError,
ExistsCheckoutPermissionDeleteFailedError,
TypistGroupNameAlreadyExistError,
TypistGroupNotExistError,
TypistIdInvalidError,
@ -1348,6 +1350,78 @@ export class AccountsService {
}
}
/**
*
* @param context
* @param externalId
* @param typistGroupId
* @returns typist group
*/
async deleteTypistGroup(
context: Context,
externalId: string,
typistGroupId: number,
): Promise<void> {
this.logger.log(
`[IN] [${context.getTrackingId()}] ${
this.deleteTypistGroup.name
} | params: { ` +
`externalId: ${externalId}, ` +
`typistGroupId: ${typistGroupId}, `,
);
try {
// 外部IDをもとにユーザー情報を取得する
const { account_id } = await this.usersRepository.findUserByExternalId(
context,
externalId,
);
// タイピストグループを削除する
await this.userGroupsRepository.deleteTypistGroup(
context,
account_id,
typistGroupId,
);
} catch (e) {
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
if (e instanceof Error) {
switch (e.constructor) {
// タイピストグループ削除済み
case TypistGroupNotExistError:
throw new HttpException(
makeErrorResponse('E015001'),
HttpStatus.BAD_REQUEST,
);
// タイピストグループがルーティングルールに使用されている
case AssignedWorkflowDeleteFailedError:
throw new HttpException(
makeErrorResponse('E015002'),
HttpStatus.BAD_REQUEST,
);
// タイピストグループがタスクの文字起こし候補に使用されている
case ExistsCheckoutPermissionDeleteFailedError:
throw new HttpException(
makeErrorResponse('E015003'),
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.deleteTypistGroup.name}`,
);
}
}
/**
*
* @param context

View File

@ -42,6 +42,7 @@ export type UserGroupsRepositoryMockValue = {
export type AdB2cMockValue = {
createUser: string | ConflictError | Error;
getUsers: AdB2cUser[] | Error;
getUser: AdB2cUser | Error;
};
export type SendGridMockValue = {
sendMail: undefined | Error;
@ -206,7 +207,7 @@ export const makeUserGroupsRepositoryMock = (
};
};
export const makeAdB2cServiceMock = (value: AdB2cMockValue) => {
const { createUser, getUsers } = value;
const { createUser, getUsers, getUser } = value;
return {
createUser:
@ -219,6 +220,10 @@ export const makeAdB2cServiceMock = (value: AdB2cMockValue) => {
getUsers instanceof Error
? jest.fn<Promise<void>, []>().mockRejectedValue(getUsers)
: jest.fn<Promise<AdB2cUser[]>, []>().mockResolvedValue(getUsers),
getUser:
getUser instanceof Error
? jest.fn<Promise<void>, []>().mockRejectedValue(getUser)
: jest.fn<Promise<AdB2cUser>, []>().mockResolvedValue(getUser),
};
};
export const makeConfigMock = (value: ConfigMockValue) => {
@ -437,6 +442,10 @@ export const makeDefaultAdB2cMockValue = (): AdB2cMockValue => {
displayName: 'Typist3',
},
],
getUser: {
id: 'typist1',
displayName: 'Typist1',
},
};
};
export const makeDefaultSendGridlValue = (): SendGridMockValue => {

View File

@ -123,6 +123,13 @@ export const getTypistGroupMember = async (
});
};
// タイピストグループメンバー一覧を取得する
export const getTypistGroupMembers = async (
datasource: DataSource,
): Promise<UserGroupMember[]> => {
return await datasource.getRepository(UserGroupMember).find();
};
// Worktypeを作成する
export const createWorktype = async (
datasource: DataSource,

View File

@ -12,10 +12,26 @@ export class TypistIdInvalidError extends Error {
this.name = 'TypistIdInvalidError';
}
}
// 削除対象グループがWorkflowにアサインされている事が原因の削除失敗エラー
export class AssignedWorkflowDeleteFailedError extends Error {
constructor(message: string) {
super(message);
this.name = 'AssignedWorkflowDeleteFailedError';
}
}
// 削除対象グループがチェックアウト権限を持っている事が原因の削除失敗エラー
export class ExistsCheckoutPermissionDeleteFailedError extends Error {
constructor(message: string) {
super(message);
this.name = 'ExistsCheckoutPermissionDeleteFailedError';
}
}
// 同名のタイピストグループが存在する場合のエラー
export class TypistGroupNameAlreadyExistError extends Error {
constructor(message: string) {
super(message);
this.name = 'TypistGroupNameAlreadyExistError';
}
}
}

View File

@ -3,7 +3,10 @@ import { DataSource, In, IsNull, Not } from 'typeorm';
import { UserGroup } from './entity/user_group.entity';
import { UserGroupMember } from './entity/user_group_member.entity';
import { User } from '../users/entity/user.entity';
import { WorkflowTypist } from '../workflows/entity/workflow_typists.entity';
import {
AssignedWorkflowDeleteFailedError,
ExistsCheckoutPermissionDeleteFailedError,
TypistGroupNameAlreadyExistError,
TypistGroupNotExistError,
TypistIdInvalidError,
@ -16,6 +19,7 @@ import {
deleteEntity,
} from '../../common/repository';
import { Context } from '../../common/log';
import { CheckoutPermission } from '../checkout_permissions/entity/checkout_permission.entity';
@Injectable()
export class UserGroupsRepositoryService {
@ -285,4 +289,81 @@ export class UserGroupsRepositoryService {
return typistGroup;
});
}
/**
* IDのタイピストグループを削除します
* @param context
* @param accountId
* @param typistGroupId
* @returns typist group
*/
async deleteTypistGroup(
context: Context,
accountId: number,
typistGroupId: number,
): Promise<void> {
await this.dataSource.transaction(async (entityManager) => {
const userGroupRepo = entityManager.getRepository(UserGroup);
// GroupIdが自アカウント内に存在するか確認する
const typistGroup = await userGroupRepo.findOne({
relations: { userGroupMembers: true },
where: {
id: typistGroupId,
account_id: accountId,
},
lock: { mode: 'pessimistic_write' },
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
});
if (!typistGroup) {
throw new TypistGroupNotExistError(
`TypistGroup not exists Error. accountId: ${accountId}; typistGroupId: ${typistGroupId}`,
);
}
// ルーティングルールに紐づくタイピストグループは削除できない
const workflowTypistRepo = entityManager.getRepository(WorkflowTypist);
const workflowTypist = await workflowTypistRepo.findOne({
where: { typist_group_id: typistGroupId },
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
});
if (workflowTypist) {
throw new AssignedWorkflowDeleteFailedError(
`Typist Group is used in routing rule. typistGroupId: ${typistGroupId}`,
);
}
// タスクのチェックアウト候補のタイピストグループは削除できない
const checkoutPermissionRepo =
entityManager.getRepository(CheckoutPermission);
const checkoutPermission = await checkoutPermissionRepo.findOne({
where: { user_group_id: typistGroupId },
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
});
if (checkoutPermission) {
throw new ExistsCheckoutPermissionDeleteFailedError(
`Typist Group is used in task checkout permission. typistGroupId: ${typistGroupId}`,
);
}
const userGroupMemberRepo = entityManager.getRepository(UserGroupMember);
// 対象のタイピストグループのユーザーを削除する
await deleteEntity(
userGroupMemberRepo,
{ user_group_id: typistGroupId },
this.isCommentOut,
context,
);
// 対象のタイピストグループを削除する
await deleteEntity(
userGroupRepo,
{ id: typistGroupId },
this.isCommentOut,
context,
);
});
}
}