## 概要 [Task2295: [Sp20]既存APIのログを強化(外部連携API以外)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2295) - 何をどう変更したか、追加したライブラリなど 誰が操作したのかを追えるようにログを強化 ## レビューポイント - 特にレビューしてほしい箇所 特になし ## 動作確認状況 - ユニットテスト
386 lines
12 KiB
TypeScript
386 lines
12 KiB
TypeScript
import { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common';
|
|
import { WorkflowsRepositoryService } from '../../repositories/workflows/workflows.repository.service';
|
|
import { UsersRepositoryService } from '../../repositories/users/users.repository.service';
|
|
import { Context } from '../../common/log';
|
|
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
|
import { Workflow, WorkflowTypist } from './types/types';
|
|
import { AdB2cService } from '../../gateways/adb2c/adb2c.service';
|
|
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,
|
|
WorkflowNotFoundError,
|
|
} from '../../repositories/workflows/errors/types';
|
|
import { AccountNotFoundError } from '../../repositories/accounts/errors/types';
|
|
import { Assignee } from '../tasks/types/types';
|
|
|
|
@Injectable()
|
|
export class WorkflowsService {
|
|
private readonly logger = new Logger(WorkflowsService.name);
|
|
constructor(
|
|
private readonly usersRepository: UsersRepositoryService,
|
|
private readonly workflowsRepository: WorkflowsRepositoryService,
|
|
private readonly adB2cService: AdB2cService,
|
|
) {}
|
|
/**
|
|
* ワークフロー一覧を取得する
|
|
* @param context
|
|
* @param externalId
|
|
* @returns workflows
|
|
*/
|
|
async getWorkflows(
|
|
context: Context,
|
|
externalId: string,
|
|
): Promise<Workflow[]> {
|
|
this.logger.log(
|
|
`[IN] [${context.getTrackingId()}] ${
|
|
this.getWorkflows.name
|
|
} | params: { externalId: ${externalId} };`,
|
|
);
|
|
try {
|
|
const { account_id: accountId } =
|
|
await this.usersRepository.findUserByExternalId(externalId);
|
|
|
|
// DBからワークフロー一覧を取得
|
|
const workflowRecords = await this.workflowsRepository.getWorkflows(
|
|
accountId,
|
|
);
|
|
|
|
// ワークフロー一覧からtypistのexternalIdを取得
|
|
const externalIds = workflowRecords.flatMap((workflow) => {
|
|
const workflowTypists = workflow.workflowTypists?.flatMap(
|
|
(workflowTypist) => {
|
|
const { typist } = workflowTypist;
|
|
return typist ? [typist.external_id] : [];
|
|
},
|
|
);
|
|
return workflowTypists;
|
|
});
|
|
// externalIdsからundefinedを除外
|
|
const filteredExternalIds = externalIds.flatMap((externalId) =>
|
|
externalId ? [externalId] : [],
|
|
);
|
|
// externalIdsから重複を除外
|
|
const distinctedExternalIds = [...new Set(filteredExternalIds)];
|
|
|
|
// ADB2Cからユーザー一覧を取得
|
|
const adb2cUsers = await this.adB2cService.getUsers(
|
|
context,
|
|
distinctedExternalIds,
|
|
);
|
|
|
|
// DBから取得したワークフロー一覧を整形
|
|
const workflows = workflowRecords.map((workflow): Workflow => {
|
|
const { id, author, worktype, template, workflowTypists } = workflow;
|
|
if (!author || !author.id || !author.author_id) {
|
|
throw new Error('author is undefined');
|
|
}
|
|
|
|
const authorId = { id: author.id, authorId: author.author_id };
|
|
const worktypeId = worktype
|
|
? { id: worktype.id, worktypeId: worktype.custom_worktype_id }
|
|
: undefined;
|
|
const templateId = template
|
|
? { id: template.id, fileName: template.file_name }
|
|
: undefined;
|
|
|
|
if (!workflowTypists) {
|
|
throw new Error('workflowTypists is undefined');
|
|
}
|
|
|
|
// ルーティング候補を整形
|
|
const typists = workflowTypists.map((workflowTypist): Assignee => {
|
|
const { typist, typistGroup } = workflowTypist;
|
|
|
|
// typistがユーザーの場合はADB2Cからユーザー名を取得
|
|
const typistName = typist
|
|
? adb2cUsers.find(
|
|
(adb2cUser) => adb2cUser.id === typist.external_id,
|
|
)?.displayName
|
|
: typistGroup?.name;
|
|
|
|
if (!typistName) {
|
|
throw new Error('typistName is undefined');
|
|
}
|
|
|
|
return {
|
|
typistUserId: typist?.id,
|
|
typistGroupId: typistGroup?.id,
|
|
typistName,
|
|
};
|
|
});
|
|
|
|
return {
|
|
id,
|
|
author: authorId,
|
|
worktype: worktypeId,
|
|
template: templateId,
|
|
typists,
|
|
};
|
|
});
|
|
|
|
return workflows;
|
|
} catch (e) {
|
|
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
|
throw new HttpException(
|
|
makeErrorResponse('E009999'),
|
|
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
);
|
|
} finally {
|
|
this.logger.log(
|
|
`[OUT] [${context.getTrackingId()}] ${this.getWorkflows.name}`,
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* ワークフローを作成する
|
|
* @param context
|
|
* @param externalId
|
|
* @param authorId
|
|
* @param worktypeId
|
|
* @param templateId
|
|
* @param typists
|
|
* @returns workflow
|
|
*/
|
|
async createWorkflow(
|
|
context: Context,
|
|
externalId: string,
|
|
authorId: number,
|
|
typists: WorkflowTypist[],
|
|
worktypeId?: number | undefined,
|
|
templateId?: number | undefined,
|
|
): Promise<void> {
|
|
this.logger.log(
|
|
`[IN] [${context.getTrackingId()}] ${
|
|
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,
|
|
typists,
|
|
worktypeId,
|
|
templateId,
|
|
);
|
|
} catch (e) {
|
|
this.logger.error(`[${context.getTrackingId()}] 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.getTrackingId()}] ${this.createWorkflow.name}`,
|
|
);
|
|
}
|
|
}
|
|
/**
|
|
* アカウント内のワークフローを更新する
|
|
* @param context
|
|
* @param externalId
|
|
* @param workflowId
|
|
* @param authorId
|
|
* @param [worktypeId]
|
|
* @param [templateId]
|
|
* @param [typists]
|
|
* @returns workflow
|
|
*/
|
|
async updateWorkflow(
|
|
context: Context,
|
|
externalId: string,
|
|
workflowId: number,
|
|
authorId: number,
|
|
typists: WorkflowTypist[],
|
|
worktypeId?: number | undefined,
|
|
templateId?: number | undefined,
|
|
): Promise<void> {
|
|
this.logger.log(
|
|
`[IN] [${context.getTrackingId()}] ${
|
|
this.updateWorkflow.name
|
|
} | params: { ` +
|
|
`externalId: ${externalId}, ` +
|
|
`workflowId: ${workflowId}, ` +
|
|
`authorId: ${authorId}, ` +
|
|
`worktypeId: ${worktypeId}, ` +
|
|
`templateId: ${templateId}, ` +
|
|
`typists: ${JSON.stringify(typists)} };`,
|
|
);
|
|
try {
|
|
const { account_id: accountId } =
|
|
await this.usersRepository.findUserByExternalId(externalId);
|
|
|
|
await this.workflowsRepository.updatetWorkflow(
|
|
accountId,
|
|
workflowId,
|
|
authorId,
|
|
typists,
|
|
worktypeId,
|
|
templateId,
|
|
);
|
|
} catch (e) {
|
|
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
|
if (e instanceof Error) {
|
|
switch (e.constructor) {
|
|
case WorkflowNotFoundError:
|
|
throw new HttpException(
|
|
makeErrorResponse('E013002'),
|
|
HttpStatus.BAD_REQUEST,
|
|
);
|
|
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.getTrackingId()}] ${this.updateWorkflow.name}`,
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* ワークフローを削除する
|
|
* @param context
|
|
* @param externalId
|
|
* @param workflowId
|
|
* @returns workflow
|
|
*/
|
|
async deleteWorkflow(
|
|
context: Context,
|
|
externalId: string,
|
|
workflowId: number,
|
|
): Promise<void> {
|
|
this.logger.log(
|
|
`[IN] [${context.getTrackingId()}] ${
|
|
this.deleteWorkflow.name
|
|
} | params: { ` +
|
|
`externalId: ${externalId}, ` +
|
|
`workflowId: ${workflowId} };`,
|
|
);
|
|
try {
|
|
const { account } = await this.usersRepository.findUserByExternalId(
|
|
externalId,
|
|
);
|
|
|
|
if (!account) {
|
|
throw new AccountNotFoundError(
|
|
`account not found. externalId: ${externalId}`,
|
|
);
|
|
}
|
|
|
|
await this.workflowsRepository.deleteWorkflow(account.id, workflowId);
|
|
} catch (e) {
|
|
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
|
if (e instanceof Error) {
|
|
switch (e.constructor) {
|
|
case UserNotFoundError:
|
|
throw new HttpException(
|
|
makeErrorResponse('E010204'),
|
|
HttpStatus.BAD_REQUEST,
|
|
);
|
|
case AccountNotFoundError:
|
|
throw new HttpException(
|
|
makeErrorResponse('E010501'),
|
|
HttpStatus.BAD_REQUEST,
|
|
);
|
|
case WorkflowNotFoundError:
|
|
throw new HttpException(
|
|
makeErrorResponse('E013002'),
|
|
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.deleteWorkflow.name}`,
|
|
);
|
|
}
|
|
}
|
|
}
|