Merged PR 458: ワークフロー追加API実装

## 概要
[Task2739: ワークフロー追加API実装](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2739)

- ワークフロー追加APIとテストを実装しました。

## レビューポイント
- リポジトリのチェックロジックは適切か
- テストケースは適切か

## UIの変更
- なし

## 動作確認状況
- ローカルで確認
This commit is contained in:
makabe.t 2023-10-05 00:20:42 +00:00
parent 6baeb0b049
commit c4c2038e6e
9 changed files with 1018 additions and 10 deletions

View File

@ -56,4 +56,6 @@ export const ErrorCodes = [
'E011001', // ワークタイプ重複エラー
'E011002', // ワークタイプ登録上限超過エラー
'E011003', // ワークタイプ不在エラー
'E012001', // テンプレートファイル不在エラー
'E013001', // ワークフローのAuthorIDとWorktypeIDのペア重複エラー
] as const;

View File

@ -45,4 +45,6 @@ export const errors: Errors = {
E011001: 'This WorkTypeID already used Error',
E011002: 'WorkTypeID create limit exceeded Error',
E011003: 'WorkTypeID not found Error',
E012001: 'Template file not found Error',
E013001: 'AuthorId and WorktypeId pair already exists Error',
};

View File

@ -25,7 +25,7 @@ export const createWorkflow = async (
return workflow;
};
// Workflowを取得する
// Workflow一覧を取得する
export const getWorkflows = async (
datasource: DataSource,
accountId: number,
@ -37,6 +37,20 @@ export const getWorkflows = async (
});
};
// Workflowを取得する
export const getWorkflow = async (
datasource: DataSource,
accountId: number,
id: number,
): Promise<Workflow> => {
return await datasource.getRepository(Workflow).findOne({
where: {
account_id: accountId,
id: id,
},
});
};
// Workflowを作成する
export const createWorkflowTypist = async (
datasource: DataSource,
@ -59,3 +73,22 @@ export const createWorkflowTypist = async (
return workflow;
};
// WorkflowTypist一覧を取得する
export const getWorkflowTypists = async (
datasource: DataSource,
workflowId: number,
): Promise<WorkflowTypist[]> => {
return await datasource.getRepository(WorkflowTypist).find({
where: {
workflow_id: workflowId,
},
});
};
// WorkflowTypist一覧全件を取得する
export const getAllWorkflowTypists = async (
datasource: DataSource,
): Promise<WorkflowTypist[]> => {
return await datasource.getRepository(WorkflowTypist).find();
};

View File

@ -104,13 +104,19 @@ export class WorkflowsController {
@Req() req: Request,
@Body() body: CreateWorkflowsRequest,
): Promise<CreateWorkflowsResponse> {
const { authorId } = body;
const { authorId, worktypeId, templateId, typists } = body;
const token = retrieveAuthorizationToken(req);
const { userId } = jwt.decode(token, { json: true }) as AccessToken;
const context = makeContext(userId);
console.log(context.trackingId);
console.log(authorId);
await this.workflowsService.createWorkflow(
context,
userId,
authorId,
worktypeId,
templateId,
typists,
);
return {};
}

View File

@ -9,6 +9,8 @@ import { createWorktype } from '../accounts/test/utility';
import {
createWorkflow,
createWorkflowTypist,
getAllWorkflowTypists,
getWorkflowTypists,
getWorkflows,
} from './test/utility';
import { createUserGroup } from '../users/test/utility';
@ -17,7 +19,7 @@ import { WorkflowsRepositoryService } from '../../repositories/workflows/workflo
import { HttpException, HttpStatus } from '@nestjs/common';
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
describe('getWorktypes', () => {
describe('getWorkflows', () => {
let source: DataSource = null;
beforeEach(async () => {
source = new DataSource({
@ -223,3 +225,703 @@ describe('getWorktypes', () => {
}
});
});
describe('createWorkflows', () => {
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('アカウント内にWorkflowを作成できるWorktypeIDあり、テンプレートファイルあり', async () => {
const module = await makeTestingModule(source);
// 第五階層のアカウント作成
const { account, admin } = await makeTestAccount(source, { tier: 5 });
const { id: authorId } = await makeTestUser(source, {
external_id: 'author1',
author_id: 'AUTHOR1',
account_id: account.id,
role: USER_ROLES.AUTHOR,
});
const { id: typistId } = await makeTestUser(source, {
external_id: 'typist1',
account_id: account.id,
role: USER_ROLES.TYPIST,
});
const { id: worktypeId } = await createWorktype(
source,
account.id,
'worktype1',
);
const { id: templateId } = await createTemplateFile(
source,
account.id,
'fileName1',
'url1',
);
//作成したデータを確認
{
const workflows = await getWorkflows(source, account.id);
const workflowTypists = await getAllWorkflowTypists(source);
expect(workflows.length).toBe(0);
expect(workflowTypists.length).toBe(0);
}
const service = module.get<WorkflowsService>(WorkflowsService);
const context = makeContext(admin.external_id);
await service.createWorkflow(
context,
admin.external_id,
authorId,
worktypeId,
templateId,
[
{
typistId: typistId,
},
],
);
//実行結果を確認
{
const workflows = await getWorkflows(source, account.id);
expect(workflows.length).toBe(1);
expect(workflows[0].account_id).toBe(account.id);
expect(workflows[0].author_id).toBe(authorId);
expect(workflows[0].worktype_id).toBe(worktypeId);
expect(workflows[0].template_id).toBe(templateId);
const workflowTypists = await getWorkflowTypists(source, workflows[0].id);
expect(workflowTypists.length).toBe(1);
expect(workflowTypists[0].typist_id).toBe(typistId);
expect(workflowTypists[0].typist_group_id).toBe(null);
}
});
it('アカウント内にWorkflowを作成できるWorktypeIDなし、テンプレートファイルあり', async () => {
const module = await makeTestingModule(source);
// 第五階層のアカウント作成
const { account, admin } = await makeTestAccount(source, { tier: 5 });
const { id: authorId } = await makeTestUser(source, {
external_id: 'author1',
author_id: 'AUTHOR1',
account_id: account.id,
role: USER_ROLES.AUTHOR,
});
const { id: typistId } = await makeTestUser(source, {
external_id: 'typist1',
account_id: account.id,
role: USER_ROLES.TYPIST,
});
const { id: templateId } = await createTemplateFile(
source,
account.id,
'fileName1',
'url1',
);
//作成したデータを確認
{
const workflows = await getWorkflows(source, account.id);
const workflowTypists = await getAllWorkflowTypists(source);
expect(workflows.length).toBe(0);
expect(workflowTypists.length).toBe(0);
}
const service = module.get<WorkflowsService>(WorkflowsService);
const context = makeContext(admin.external_id);
await service.createWorkflow(
context,
admin.external_id,
authorId,
undefined,
templateId,
[
{
typistId: typistId,
},
],
);
//実行結果を確認
{
const workflows = await getWorkflows(source, account.id);
expect(workflows.length).toBe(1);
expect(workflows[0].account_id).toBe(account.id);
expect(workflows[0].author_id).toBe(authorId);
expect(workflows[0].worktype_id).toBe(null);
expect(workflows[0].template_id).toBe(templateId);
const workflowTypists = await getWorkflowTypists(source, workflows[0].id);
expect(workflowTypists.length).toBe(1);
expect(workflowTypists[0].typist_id).toBe(typistId);
expect(workflowTypists[0].typist_group_id).toBe(null);
}
});
it('アカウント内にWorkflowを作成できるWorktypeIDあり、テンプレートファイルなし', async () => {
const module = await makeTestingModule(source);
// 第五階層のアカウント作成
const { account, admin } = await makeTestAccount(source, { tier: 5 });
const { id: authorId } = await makeTestUser(source, {
external_id: 'author1',
author_id: 'AUTHOR1',
account_id: account.id,
role: USER_ROLES.AUTHOR,
});
const { id: typistId } = await makeTestUser(source, {
external_id: 'typist1',
account_id: account.id,
role: USER_ROLES.TYPIST,
});
const { id: worktypeId } = await createWorktype(
source,
account.id,
'worktype1',
);
//作成したデータを確認
{
const workflows = await getWorkflows(source, account.id);
const workflowTypists = await getAllWorkflowTypists(source);
expect(workflows.length).toBe(0);
expect(workflowTypists.length).toBe(0);
}
const service = module.get<WorkflowsService>(WorkflowsService);
const context = makeContext(admin.external_id);
await service.createWorkflow(
context,
admin.external_id,
authorId,
worktypeId,
undefined,
[
{
typistId: typistId,
},
],
);
//実行結果を確認
{
const workflows = await getWorkflows(source, account.id);
expect(workflows.length).toBe(1);
expect(workflows[0].account_id).toBe(account.id);
expect(workflows[0].author_id).toBe(authorId);
expect(workflows[0].worktype_id).toBe(worktypeId);
expect(workflows[0].template_id).toBe(null);
const workflowTypists = await getWorkflowTypists(source, workflows[0].id);
expect(workflowTypists.length).toBe(1);
expect(workflowTypists[0].typist_id).toBe(typistId);
expect(workflowTypists[0].typist_group_id).toBe(null);
}
});
it('アカウント内にWorkflowを作成できるWorktypeIDなし、テンプレートファイルなし', async () => {
const module = await makeTestingModule(source);
// 第五階層のアカウント作成
const { account, admin } = await makeTestAccount(source, { tier: 5 });
const { id: authorId } = await makeTestUser(source, {
external_id: 'author1',
author_id: 'AUTHOR1',
account_id: account.id,
role: USER_ROLES.AUTHOR,
});
const { id: typistId } = await makeTestUser(source, {
external_id: 'typist1',
account_id: account.id,
role: USER_ROLES.TYPIST,
});
//作成したデータを確認
{
const workflows = await getWorkflows(source, account.id);
const workflowTypists = await getAllWorkflowTypists(source);
expect(workflows.length).toBe(0);
expect(workflowTypists.length).toBe(0);
}
const service = module.get<WorkflowsService>(WorkflowsService);
const context = makeContext(admin.external_id);
await service.createWorkflow(
context,
admin.external_id,
authorId,
undefined,
undefined,
[
{
typistId: typistId,
},
],
);
//実行結果を確認
{
const workflows = await getWorkflows(source, account.id);
expect(workflows.length).toBe(1);
expect(workflows[0].account_id).toBe(account.id);
expect(workflows[0].author_id).toBe(authorId);
expect(workflows[0].worktype_id).toBe(null);
expect(workflows[0].template_id).toBe(null);
const workflowTypists = await getWorkflowTypists(source, workflows[0].id);
expect(workflowTypists.length).toBe(1);
expect(workflowTypists[0].typist_id).toBe(typistId);
expect(workflowTypists[0].typist_group_id).toBe(null);
}
});
it('DBにAuthorが存在しない場合、400エラーとなること', async () => {
const module = await makeTestingModule(source);
// 第五階層のアカウント作成
const { account, admin } = await makeTestAccount(source, { tier: 5 });
const { id: typistId } = await makeTestUser(source, {
external_id: 'typist1',
account_id: account.id,
role: USER_ROLES.TYPIST,
});
const { id: worktypeId } = await createWorktype(
source,
account.id,
'worktype1',
);
const { id: templateId } = await createTemplateFile(
source,
account.id,
'fileName1',
'url1',
);
//作成したデータを確認
{
const workflows = await getWorkflows(source, account.id);
const workflowTypists = await getAllWorkflowTypists(source);
expect(workflows.length).toBe(0);
expect(workflowTypists.length).toBe(0);
}
const service = module.get<WorkflowsService>(WorkflowsService);
const context = makeContext(admin.external_id);
//実行結果を確認
try {
await service.createWorkflow(
context,
admin.external_id,
0,
worktypeId,
templateId,
[
{
typistId: typistId,
},
],
);
} catch (e) {
if (e instanceof HttpException) {
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
expect(e.getResponse()).toEqual(makeErrorResponse('E010204'));
} else {
fail();
}
}
});
it('DBにWorktypeIDが存在しない場合、400エラーとなること', async () => {
const module = await makeTestingModule(source);
// 第五階層のアカウント作成
const { account, admin } = await makeTestAccount(source, { tier: 5 });
const { id: authorId } = await makeTestUser(source, {
external_id: 'author1',
author_id: 'AUTHOR1',
account_id: account.id,
role: USER_ROLES.AUTHOR,
});
const { id: typistId } = await makeTestUser(source, {
external_id: 'typist1',
account_id: account.id,
role: USER_ROLES.TYPIST,
});
const { id: templateId } = await createTemplateFile(
source,
account.id,
'fileName1',
'url1',
);
//作成したデータを確認
{
const workflows = await getWorkflows(source, account.id);
const workflowTypists = await getAllWorkflowTypists(source);
expect(workflows.length).toBe(0);
expect(workflowTypists.length).toBe(0);
}
const service = module.get<WorkflowsService>(WorkflowsService);
const context = makeContext(admin.external_id);
//実行結果を確認
try {
await service.createWorkflow(
context,
admin.external_id,
authorId,
9999,
templateId,
[
{
typistId: typistId,
},
],
);
} catch (e) {
if (e instanceof HttpException) {
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
expect(e.getResponse()).toEqual(makeErrorResponse('E011003'));
} else {
fail();
}
}
});
it('DBにテンプレートファイルが存在しない場合、400エラーとなること', async () => {
const module = await makeTestingModule(source);
// 第五階層のアカウント作成
const { account, admin } = await makeTestAccount(source, { tier: 5 });
const { id: authorId } = await makeTestUser(source, {
external_id: 'author1',
author_id: 'AUTHOR1',
account_id: account.id,
role: USER_ROLES.AUTHOR,
});
const { id: typistId } = await makeTestUser(source, {
external_id: 'typist1',
account_id: account.id,
role: USER_ROLES.TYPIST,
});
const { id: worktypeId } = await createWorktype(
source,
account.id,
'worktype1',
);
//作成したデータを確認
{
const workflows = await getWorkflows(source, account.id);
const workflowTypists = await getAllWorkflowTypists(source);
expect(workflows.length).toBe(0);
expect(workflowTypists.length).toBe(0);
}
const service = module.get<WorkflowsService>(WorkflowsService);
const context = makeContext(admin.external_id);
//実行結果を確認
try {
await service.createWorkflow(
context,
admin.external_id,
authorId,
worktypeId,
9999,
[
{
typistId: typistId,
},
],
);
} catch (e) {
if (e instanceof HttpException) {
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
expect(e.getResponse()).toEqual(makeErrorResponse('E012001'));
} else {
fail();
}
}
});
it('DBにルーティング候補ユーザーが存在しない場合、400エラーとなること', async () => {
const module = await makeTestingModule(source);
// 第五階層のアカウント作成
const { account, admin } = await makeTestAccount(source, { tier: 5 });
const { id: authorId } = await makeTestUser(source, {
external_id: 'author1',
author_id: 'AUTHOR1',
account_id: account.id,
role: USER_ROLES.AUTHOR,
});
const { id: worktypeId } = await createWorktype(
source,
account.id,
'worktype1',
);
const { id: templateId } = await createTemplateFile(
source,
account.id,
'fileName1',
'url1',
);
//作成したデータを確認
{
const workflows = await getWorkflows(source, account.id);
const workflowTypists = await getAllWorkflowTypists(source);
expect(workflows.length).toBe(0);
expect(workflowTypists.length).toBe(0);
}
const service = module.get<WorkflowsService>(WorkflowsService);
const context = makeContext(admin.external_id);
//実行結果を確認
try {
await service.createWorkflow(
context,
admin.external_id,
authorId,
worktypeId,
templateId,
[
{
typistId: 9999,
},
],
);
} catch (e) {
if (e instanceof HttpException) {
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
expect(e.getResponse()).toEqual(makeErrorResponse('E010204'));
} else {
fail();
}
}
});
it('DBにルーティング候補グループが存在しない場合、400エラーとなること', async () => {
const module = await makeTestingModule(source);
// 第五階層のアカウント作成
const { account, admin } = await makeTestAccount(source, { tier: 5 });
const { id: authorId } = await makeTestUser(source, {
external_id: 'author1',
author_id: 'AUTHOR1',
account_id: account.id,
role: USER_ROLES.AUTHOR,
});
const { id: worktypeId } = await createWorktype(
source,
account.id,
'worktype1',
);
const { id: templateId } = await createTemplateFile(
source,
account.id,
'fileName1',
'url1',
);
//作成したデータを確認
{
const workflows = await getWorkflows(source, account.id);
const workflowTypists = await getAllWorkflowTypists(source);
expect(workflows.length).toBe(0);
expect(workflowTypists.length).toBe(0);
}
const service = module.get<WorkflowsService>(WorkflowsService);
const context = makeContext(admin.external_id);
//実行結果を確認
try {
await service.createWorkflow(
context,
admin.external_id,
authorId,
worktypeId,
templateId,
[
{
typistGroupId: 9999,
},
],
);
} catch (e) {
if (e instanceof HttpException) {
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
expect(e.getResponse()).toEqual(makeErrorResponse('E010908'));
} else {
fail();
}
}
});
it('DBにAuthorIDとWorktypeIDのペアがすでに存在する場合、400エラーとなること', async () => {
const module = await makeTestingModule(source);
// 第五階層のアカウント作成
const { account, admin } = await makeTestAccount(source, { tier: 5 });
const { id: authorId } = await makeTestUser(source, {
external_id: 'author1',
author_id: 'AUTHOR1',
account_id: account.id,
role: USER_ROLES.AUTHOR,
});
const { id: typistId } = await makeTestUser(source, {
external_id: 'typist1',
account_id: account.id,
role: USER_ROLES.TYPIST,
});
const { id: worktypeId } = await createWorktype(
source,
account.id,
'worktype1',
);
const { id: templateId } = await createTemplateFile(
source,
account.id,
'fileName1',
'url1',
);
await createWorkflow(source, account.id, authorId, worktypeId, templateId);
//作成したデータを確認
{
const workflows = await getWorkflows(source, account.id);
expect(workflows.length).toBe(1);
expect(workflows[0].account_id).toBe(account.id);
expect(workflows[0].author_id).toBe(authorId);
expect(workflows[0].worktype_id).toBe(worktypeId);
expect(workflows[0].template_id).toBe(templateId);
}
const service = module.get<WorkflowsService>(WorkflowsService);
const context = makeContext(admin.external_id);
//実行結果を確認
try {
await service.createWorkflow(
context,
admin.external_id,
authorId,
worktypeId,
templateId,
[
{
typistId: typistId,
},
],
);
} catch (e) {
if (e instanceof HttpException) {
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
expect(e.getResponse()).toEqual(makeErrorResponse('E013001'));
} else {
fail();
}
}
});
it('DBアクセスに失敗した場合、500エラーを返却する', async () => {
const module = await makeTestingModule(source);
// 第五階層のアカウント作成
const { account, admin } = await makeTestAccount(source, { tier: 5 });
const { id: authorId } = await makeTestUser(source, {
external_id: 'author1',
author_id: 'AUTHOR1',
account_id: account.id,
role: USER_ROLES.AUTHOR,
});
const { id: typistId } = await makeTestUser(source, {
external_id: 'typist1',
account_id: account.id,
role: USER_ROLES.TYPIST,
});
const { id: worktypeId } = await createWorktype(
source,
account.id,
'worktype1',
);
const { id: templateId } = await createTemplateFile(
source,
account.id,
'fileName1',
'url1',
);
//作成したデータを確認
{
const workflows = await getWorkflows(source, account.id);
const workflowTypists = await getAllWorkflowTypists(source);
expect(workflows.length).toBe(0);
expect(workflowTypists.length).toBe(0);
}
const service = module.get<WorkflowsService>(WorkflowsService);
const context = makeContext(admin.external_id);
//DBアクセスに失敗するようにする
const templatesService = module.get<WorkflowsRepositoryService>(
WorkflowsRepositoryService,
);
templatesService.createtWorkflows = jest
.fn()
.mockRejectedValue('DB failed');
//実行結果を確認
try {
await service.createWorkflow(
context,
admin.external_id,
authorId,
worktypeId,
templateId,
[
{
typistId: typistId,
},
],
);
} catch (e) {
if (e instanceof HttpException) {
expect(e.getStatus()).toEqual(HttpStatus.INTERNAL_SERVER_ERROR);
expect(e.getResponse()).toEqual(makeErrorResponse('E009999'));
} else {
fail();
}
}
});
});

View File

@ -1,9 +1,15 @@
import { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common';
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
import { Context } from '../../common/log';
import { Workflow } from './types/types';
import { UsersRepositoryService } from '../../repositories/users/users.repository.service';
import { WorkflowsRepositoryService } from '../../repositories/workflows/workflows.repository.service';
import { UsersRepositoryService } from '../../repositories/users/users.repository.service';
import { WorkflowTypist } from './types/types';
import { Context } from '../../common/log';
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
import { UserNotFoundError } from '../../repositories/users/errors/types';
import { TypistGroupNotExistError } from '../../repositories/user_groups/errors/types';
import { WorktypeIdNotFoundError } from '../../repositories/worktypes/errors/types';
import { TemplateFileNotExistError } from '../../repositories/template_files/errors/types';
import { AuthorIdAndWorktypeIdPairAlreadyExistsError } from '../../repositories/workflows/errors/types';
import { Workflow } from './types/types';
import { AdB2cService } from '../../gateways/adb2c/adb2c.service';
@Injectable()
@ -106,4 +112,88 @@ export class WorkflowsService {
);
}
}
/**
*
* @param context
* @param externalId
* @param authorId
* @param worktypeId
* @param templateId
* @param typists
* @returns workflow
*/
async createWorkflow(
context: Context,
externalId: string,
authorId: number,
worktypeId?: number | undefined,
templateId?: number | undefined,
typists?: WorkflowTypist[],
): Promise<void> {
this.logger.log(
`[IN] [${context.trackingId}] ${this.createWorkflow.name} | | params: { ` +
`externalId: ${externalId}, ` +
`authorId: ${authorId}, ` +
`worktypeId: ${worktypeId}, ` +
`templateId: ${templateId}, ` +
`typists: ${JSON.stringify(typists)} };`,
);
try {
const { account_id: accountId } =
await this.usersRepository.findUserByExternalId(externalId);
await this.workflowsRepository.createtWorkflows(
accountId,
authorId,
worktypeId,
templateId,
typists,
);
} catch (e) {
this.logger.error(`[${context.trackingId}] error=${e}`);
if (e instanceof Error) {
switch (e.constructor) {
case UserNotFoundError:
throw new HttpException(
makeErrorResponse('E010204'),
HttpStatus.BAD_REQUEST,
);
case TypistGroupNotExistError:
throw new HttpException(
makeErrorResponse('E010908'),
HttpStatus.BAD_REQUEST,
);
case WorktypeIdNotFoundError:
throw new HttpException(
makeErrorResponse('E011003'),
HttpStatus.BAD_REQUEST,
);
case TemplateFileNotExistError:
throw new HttpException(
makeErrorResponse('E012001'),
HttpStatus.BAD_REQUEST,
);
case AuthorIdAndWorktypeIdPairAlreadyExistsError:
throw new HttpException(
makeErrorResponse('E013001'),
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.createWorkflow.name}`,
);
}
}
}

View File

@ -0,0 +1,2 @@
// テンプレートファイルが存在しないエラー
export class TemplateFileNotExistError extends Error {}

View File

@ -0,0 +1,2 @@
// AuthorIDとWorktypeIDのペア重複エラー
export class AuthorIdAndWorktypeIdPairAlreadyExistsError extends Error {}

View File

@ -1,6 +1,17 @@
import { Injectable } from '@nestjs/common';
import { DataSource } from 'typeorm';
import { DataSource, In } from 'typeorm';
import { Workflow } from './entity/workflow.entity';
import { WorkflowTypist as DbWorkflowTypist } from './entity/workflow_typists.entity';
import { User } from '../users/entity/user.entity';
import { WorkflowTypist } from '../../features/workflows/types/types';
import { Worktype } from '../worktypes/entity/worktype.entity';
import { TemplateFile } from '../template_files/entity/template_file.entity';
import { UserGroup } from '../user_groups/entity/user_group.entity';
import { TypistGroupNotExistError } from '../user_groups/errors/types';
import { UserNotFoundError } from '../users/errors/types';
import { WorktypeIdNotFoundError } from '../worktypes/errors/types';
import { TemplateFileNotExistError } from '../template_files/errors/types';
import { AuthorIdAndWorktypeIdPairAlreadyExistsError } from './errors/types';
@Injectable()
export class WorkflowsRepositoryService {
@ -31,4 +42,162 @@ export class WorkflowsRepositoryService {
return workflows;
});
}
/**
*
* @param accountId
* @param authorId
* @param worktypeId
* @param templateId
* @param typists
* @returns workflows
*/
async createtWorkflows(
accountId: number,
authorId: number,
worktypeId?: number | undefined,
templateId?: number | undefined,
typists?: WorkflowTypist[],
): Promise<void> {
return await this.dataSource.transaction(async (entityManager) => {
// authorの存在確認
const userRepo = entityManager.getRepository(User);
const author = await userRepo.findOne({
where: { account_id: accountId, id: authorId },
});
if (!author) {
throw new UserNotFoundError(`author not found. id: ${authorId}`);
}
// worktypeの存在確認
if (worktypeId !== undefined) {
const worktypeRepo = entityManager.getRepository(Worktype);
const worktypes = await worktypeRepo.find({
where: { account_id: accountId, id: worktypeId },
});
if (worktypes.length === 0) {
throw new WorktypeIdNotFoundError(
`worktype not found. id: ${worktypeId}`,
);
}
}
// templateの存在確認
if (templateId !== undefined) {
const templateRepo = entityManager.getRepository(TemplateFile);
const template = await templateRepo.findOne({
where: { account_id: accountId, id: templateId },
});
if (!template) {
throw new TemplateFileNotExistError('template not found');
}
}
// ルーティング候補ユーザーの存在確認
const typistIds = typists.flatMap((typist) =>
typist.typistId ? [typist.typistId] : [],
);
const typistUsers = await userRepo.find({
where: { account_id: accountId, id: In(typistIds) },
});
if (typistUsers.length !== typistIds.length) {
throw new UserNotFoundError(`typist not found. ids: ${typistIds}`);
}
// ルーティング候補ユーザーグループの存在確認
const groupIds = typists.flatMap((typist) => {
return typist.typistGroupId ? [typist.typistGroupId] : [];
});
const userGroupRepo = entityManager.getRepository(UserGroup);
const typistGroups = await userGroupRepo.find({
where: { account_id: accountId, id: In(groupIds) },
});
if (typistGroups.length !== groupIds.length) {
throw new TypistGroupNotExistError(
`typist group not found. ids: ${groupIds}`,
);
}
const workflowRepo = entityManager.getRepository(Workflow);
// ワークフローの重複確認
const workflow = await workflowRepo.find({
where: {
account_id: accountId,
author_id: authorId,
worktype_id: worktypeId,
},
});
if (workflow.length !== 0) {
throw new AuthorIdAndWorktypeIdPairAlreadyExistsError(
'workflow already exists',
);
}
// ワークフローのデータ作成
const newWorkflow = this.makeWorkflow(
accountId,
authorId,
worktypeId,
templateId,
);
await workflowRepo.save(newWorkflow);
// ルーティング候補のデータ作成
const workflowTypists = typists.map((typist) =>
this.makeWorkflowTypist(
newWorkflow.id,
typist.typistId,
typist.typistGroupId,
),
);
const workflowTypistsRepo = entityManager.getRepository(DbWorkflowTypist);
await workflowTypistsRepo.save(workflowTypists);
});
}
/**
* DBに保存するワークフローデータを作成する
* @param accountId
* @param authorId
* @param worktypeId
* @param templateId
* @returns workflow
*/
private makeWorkflow(
accountId: number,
authorId: number,
worktypeId?: number | undefined,
templateId?: number | undefined,
): Workflow {
const workflow = new Workflow();
workflow.account_id = accountId;
workflow.author_id = authorId;
workflow.worktype_id = worktypeId;
workflow.template_id = templateId;
return workflow;
}
/**
* DBに保存するルーティング候補データを作成する
* @param workflowId
* @param typistId
* @param typistGroupId
* @returns workflow typist
*/
private makeWorkflowTypist(
workflowId: number,
typistId: number,
typistGroupId: number,
): DbWorkflowTypist {
const workflowTypist = new DbWorkflowTypist();
workflowTypist.workflow_id = workflowId;
workflowTypist.typist_id = typistId;
workflowTypist.typist_group_id = typistGroupId;
return workflowTypist;
}
}