Merged PR 921: API修正
## 概要 [Task4478: API修正](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/4478) - 元PBI or タスクへのリンク(内容・目的などはそちらにあるはず) - 何をどう変更したか、追加したライブラリなど - このPull Requestでの対象/対象外 - 影響範囲(他の機能にも影響があるか) ## レビューポイント - 特にレビューしてほしい箇所 - 軽微なものや自明なものは記載不要 - 修正範囲が大きい場合などに記載 - 全体的にや仕様を満たしているか等は本当に必要な時のみ記載 - 修正箇所がほかの機能に影響していないか ## UIの変更 - Before/Afterのスクショなど - スクショ置き場 ## クエリの変更 - Repositoryを変更し、クエリが変更された場合は変更内容を確認する - Before/Afterのクエリ - クエリ置き場 ## 動作確認状況 - ローカルで確認、develop環境で確認など - 行った修正がデグレを発生させていないことを確認できるか - 具体的にどのような確認をしたか - どのケースに対してどのような手段でデグレがないことを担保しているか ## 補足 - 相談、参考資料などがあれば
This commit is contained in:
parent
6690302ac3
commit
f1b75a7ff0
@ -494,132 +494,7 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
|||||||
expect(resultCheckoutPermission[0].user_id).toEqual(typistUserId);
|
expect(resultCheckoutPermission[0].user_id).toEqual(typistUserId);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('タスク作成時に、自動ルーティングを行うことができる(API実行者のAuthorIDとworkType)', async () => {
|
it('タスク作成時に、音声ファイルメタ情報のAuthorIDに存在しないIDが入っていた場合自動ルーティングを行うことができない', async () => {
|
||||||
if (!source) fail();
|
|
||||||
const { id: accountId } = await makeTestSimpleAccount(source);
|
|
||||||
// 音声ファイルの録音者のユーザー
|
|
||||||
const { author_id: authorAuthorId } = await makeTestUser(source, {
|
|
||||||
account_id: accountId,
|
|
||||||
external_id: 'author-user-external-id',
|
|
||||||
role: 'author',
|
|
||||||
author_id: 'AUTHOR_ID',
|
|
||||||
});
|
|
||||||
// ルーティング先のタイピストのユーザー
|
|
||||||
const { id: typistUserId } = await makeTestUser(source, {
|
|
||||||
account_id: accountId,
|
|
||||||
external_id: 'typist-user-external-id',
|
|
||||||
role: 'typist',
|
|
||||||
author_id: undefined,
|
|
||||||
});
|
|
||||||
// API実行者のユーザー
|
|
||||||
const { external_id: myExternalId, id: myUserId } = await makeTestUser(
|
|
||||||
source,
|
|
||||||
{
|
|
||||||
account_id: accountId,
|
|
||||||
external_id: 'my-author-user-external-id',
|
|
||||||
role: 'author',
|
|
||||||
author_id: 'MY_AUTHOR_ID',
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// ワークタイプを作成
|
|
||||||
const { id: worktypeId, custom_worktype_id } = await createWorktype(
|
|
||||||
source,
|
|
||||||
accountId,
|
|
||||||
'worktypeId',
|
|
||||||
);
|
|
||||||
|
|
||||||
// テンプレートファイルを作成
|
|
||||||
const { id: templateFileId } = await createTemplateFile(
|
|
||||||
source,
|
|
||||||
accountId,
|
|
||||||
'templateFile',
|
|
||||||
'http://blob/url/templateFile.zip',
|
|
||||||
);
|
|
||||||
|
|
||||||
// ワークフローを作成
|
|
||||||
const { id: workflowId } = await createWorkflow(
|
|
||||||
source,
|
|
||||||
accountId,
|
|
||||||
myUserId, // API実行者のユーザーIDを設定
|
|
||||||
worktypeId,
|
|
||||||
templateFileId,
|
|
||||||
);
|
|
||||||
// ユーザーグループを作成
|
|
||||||
const { userGroupId } = await createUserGroupAndMember(
|
|
||||||
source,
|
|
||||||
accountId,
|
|
||||||
'userGroupName',
|
|
||||||
typistUserId, // ルーティング先のタイピストのユーザーIDを設定
|
|
||||||
);
|
|
||||||
// ワークフロータイピストを作成
|
|
||||||
await createWorkflowTypist(
|
|
||||||
source,
|
|
||||||
workflowId,
|
|
||||||
undefined,
|
|
||||||
userGroupId, // ルーティング先のユーザーグループIDを設定
|
|
||||||
);
|
|
||||||
|
|
||||||
// 初期値のジョブナンバーでjob_numberテーブルを作成
|
|
||||||
await createJobNumber(source, accountId, '00000000');
|
|
||||||
|
|
||||||
const blobParam = makeBlobstorageServiceMockValue();
|
|
||||||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
|
||||||
|
|
||||||
const module = await makeTestingModuleWithBlobAndNotification(
|
|
||||||
source,
|
|
||||||
blobParam,
|
|
||||||
notificationParam,
|
|
||||||
);
|
|
||||||
if (!module) fail();
|
|
||||||
const service = module.get<FilesService>(FilesService);
|
|
||||||
const notificationHubService = module.get<NotificationhubService>(
|
|
||||||
NotificationhubService,
|
|
||||||
);
|
|
||||||
const result = await service.uploadFinished(
|
|
||||||
makeContext('trackingId', 'requestId'),
|
|
||||||
myExternalId, // API実行者のユーザーIDを設定
|
|
||||||
'http://blob/url/file.zip',
|
|
||||||
authorAuthorId ?? '', // 音声ファイルの情報には、録音者のAuthorIDが入る
|
|
||||||
'file.zip',
|
|
||||||
'11:22:33',
|
|
||||||
'2023-05-26T11:22:33.444',
|
|
||||||
'2023-05-26T11:22:33.444',
|
|
||||||
'2023-05-26T11:22:33.444',
|
|
||||||
256,
|
|
||||||
'01',
|
|
||||||
'DS2',
|
|
||||||
'comment',
|
|
||||||
custom_worktype_id,
|
|
||||||
optionItemList,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
expect(result.jobNumber).toEqual('00000001');
|
|
||||||
// 通知処理が想定通りの引数で呼ばれているか確認
|
|
||||||
expect(notificationHubService.notify).toHaveBeenCalledWith(
|
|
||||||
makeContext('trackingId', 'requestId'),
|
|
||||||
[`user_${typistUserId}`],
|
|
||||||
{
|
|
||||||
authorId: 'AUTHOR_ID',
|
|
||||||
filename: 'file',
|
|
||||||
priority: 'High',
|
|
||||||
uploadedAt: '2023-05-26T11:22:33.444',
|
|
||||||
},
|
|
||||||
);
|
|
||||||
// 作成したタスクを取得
|
|
||||||
const resultTask = await getTaskFromJobNumber(source, result.jobNumber);
|
|
||||||
// タスクのチェックアウト権限を取得
|
|
||||||
const resultCheckoutPermission = await getCheckoutPermissions(
|
|
||||||
source,
|
|
||||||
resultTask?.id ?? 0,
|
|
||||||
);
|
|
||||||
// タスクのテンプレートファイルIDを確認
|
|
||||||
expect(resultTask?.template_file_id).toEqual(templateFileId);
|
|
||||||
// タスクのチェックアウト権限が想定通り(ワークフローで設定されている)のユーザーIDで作成されているか確認
|
|
||||||
expect(resultCheckoutPermission.length).toEqual(1);
|
|
||||||
expect(resultCheckoutPermission[0].user_group_id).toEqual(userGroupId);
|
|
||||||
});
|
|
||||||
it('タスク作成時に、音声ファイルメタ情報のAuthorIDに存在しないものが入っていても自動ルーティングを行うことができる(API実行者のAuthorIDとworkType)', async () => {
|
|
||||||
if (!source) fail();
|
if (!source) fail();
|
||||||
const { id: accountId } = await makeTestSimpleAccount(source);
|
const { id: accountId } = await makeTestSimpleAccount(source);
|
||||||
// 音声ファイルの録音者のユーザー
|
// 音声ファイルの録音者のユーザー
|
||||||
@ -705,7 +580,7 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
|||||||
makeContext('trackingId', 'requestId'),
|
makeContext('trackingId', 'requestId'),
|
||||||
myExternalId, // API実行者のユーザーIDを設定
|
myExternalId, // API実行者のユーザーIDを設定
|
||||||
'http://blob/url/file.zip',
|
'http://blob/url/file.zip',
|
||||||
'XXXXXXXXXX', // 音声ファイルの情報には、録音者のAuthorIDが入る
|
'XXXXXX', // 存在しないAuthorIDを指定
|
||||||
'file.zip',
|
'file.zip',
|
||||||
'11:22:33',
|
'11:22:33',
|
||||||
'2023-05-26T11:22:33.444',
|
'2023-05-26T11:22:33.444',
|
||||||
@ -720,17 +595,8 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
|||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
expect(result.jobNumber).toEqual('00000001');
|
expect(result.jobNumber).toEqual('00000001');
|
||||||
// 通知処理が想定通りの引数で呼ばれているか確認
|
// 通知処理が呼ばれていないことを確認
|
||||||
expect(notificationHubService.notify).toHaveBeenCalledWith(
|
expect(notificationHubService.notify).not.toBeCalled();
|
||||||
makeContext('trackingId', 'requestId'),
|
|
||||||
[`user_${typistUserId}`],
|
|
||||||
{
|
|
||||||
authorId: 'XXXXXXXXXX',
|
|
||||||
filename: 'file',
|
|
||||||
priority: 'High',
|
|
||||||
uploadedAt: '2023-05-26T11:22:33.444',
|
|
||||||
},
|
|
||||||
);
|
|
||||||
// 作成したタスクを取得
|
// 作成したタスクを取得
|
||||||
const resultTask = await getTaskFromJobNumber(source, result.jobNumber);
|
const resultTask = await getTaskFromJobNumber(source, result.jobNumber);
|
||||||
// タスクのチェックアウト権限を取得
|
// タスクのチェックアウト権限を取得
|
||||||
@ -739,13 +605,12 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
|||||||
resultTask?.id ?? 0,
|
resultTask?.id ?? 0,
|
||||||
);
|
);
|
||||||
// タスクのテンプレートファイルIDを確認
|
// タスクのテンプレートファイルIDを確認
|
||||||
expect(resultTask?.template_file_id).toEqual(templateFileId);
|
expect(resultTask?.template_file_id).toBeNull();
|
||||||
// タスクのチェックアウト権限が想定通り(ワークフローで設定されている)のユーザーIDで作成されているか確認
|
// 存在しないAuthorIDを指定してタスクを作成したためルーティングが行われず、タスクのチェックアウト権限は誰にも付与されない
|
||||||
expect(resultCheckoutPermission.length).toEqual(1);
|
expect(resultCheckoutPermission.length).toEqual(0);
|
||||||
expect(resultCheckoutPermission[0].user_group_id).toEqual(userGroupId);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('ワークフローが見つからない場合、タスク作成時に、自動ルーティングを行うことができない', async () => {
|
it('ワークフローが見つからない場合、タスク作成時に自動ルーティングを行うことができない', async () => {
|
||||||
if (!source) fail();
|
if (!source) fail();
|
||||||
const { id: accountId } = await makeTestSimpleAccount(source);
|
const { id: accountId } = await makeTestSimpleAccount(source);
|
||||||
// 音声ファイルの録音者のユーザー
|
// 音声ファイルの録音者のユーザー
|
||||||
@ -785,7 +650,7 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
|||||||
'01',
|
'01',
|
||||||
'DS2',
|
'DS2',
|
||||||
'comment',
|
'comment',
|
||||||
'worktypeId',
|
'',
|
||||||
optionItemList,
|
optionItemList,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
@ -802,6 +667,97 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
|||||||
// 自動ルーティングが行われていないことを確認
|
// 自動ルーティングが行われていないことを確認
|
||||||
expect(resultCheckoutPermission.length).toEqual(0);
|
expect(resultCheckoutPermission.length).toEqual(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('WorkTypeIDの指定がないワークフローで、タスク作成時に自動ルーティングを行うことができる', async () => {
|
||||||
|
if (!source) fail();
|
||||||
|
const { id: accountId } = await makeTestSimpleAccount(source);
|
||||||
|
// 音声ファイルの録音者のユーザー
|
||||||
|
const {
|
||||||
|
external_id: authorExternalId,
|
||||||
|
author_id: authorAuthorId,
|
||||||
|
id: authorUserId,
|
||||||
|
} = await makeTestUser(source, {
|
||||||
|
account_id: accountId,
|
||||||
|
external_id: 'author-user-external-id',
|
||||||
|
role: 'author',
|
||||||
|
author_id: 'AUTHOR_ID',
|
||||||
|
});
|
||||||
|
const { id: typistUserId } = await makeTestUser(source, {
|
||||||
|
account_id: accountId,
|
||||||
|
external_id: 'typist-user-external-id',
|
||||||
|
role: 'typist',
|
||||||
|
author_id: undefined,
|
||||||
|
});
|
||||||
|
// ワークフローを作成
|
||||||
|
const { id: workflowId } = await createWorkflow(
|
||||||
|
source,
|
||||||
|
accountId,
|
||||||
|
authorUserId,
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
|
// ワークフロータイピストを作成
|
||||||
|
await createWorkflowTypist(source, workflowId, typistUserId);
|
||||||
|
|
||||||
|
// 初期値のジョブナンバーでjob_numberテーブルを作成
|
||||||
|
await createJobNumber(source, accountId, '00000000');
|
||||||
|
|
||||||
|
const blobParam = makeBlobstorageServiceMockValue();
|
||||||
|
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||||||
|
|
||||||
|
const module = await makeTestingModuleWithBlobAndNotification(
|
||||||
|
source,
|
||||||
|
blobParam,
|
||||||
|
notificationParam,
|
||||||
|
);
|
||||||
|
if (!module) fail();
|
||||||
|
const service = module.get<FilesService>(FilesService);
|
||||||
|
const notificationHubService = module.get<NotificationhubService>(
|
||||||
|
NotificationhubService,
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = await service.uploadFinished(
|
||||||
|
makeContext('trackingId', 'requestId'),
|
||||||
|
authorExternalId, // API実行者のユーザーIDを設定
|
||||||
|
'http://blob/url/file.zip',
|
||||||
|
authorAuthorId ?? '', // 音声ファイルの情報には、録音者のAuthorIDが入る
|
||||||
|
'file.zip',
|
||||||
|
'11:22:33',
|
||||||
|
'2023-05-26T11:22:33.444',
|
||||||
|
'2023-05-26T11:22:33.444',
|
||||||
|
'2023-05-26T11:22:33.444',
|
||||||
|
256,
|
||||||
|
'01',
|
||||||
|
'DS2',
|
||||||
|
'comment',
|
||||||
|
'',
|
||||||
|
optionItemList,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
expect(result.jobNumber).toEqual('00000001');
|
||||||
|
// 通知処理が想定通りの引数で呼ばれているか確認
|
||||||
|
expect(notificationHubService.notify).toHaveBeenCalledWith(
|
||||||
|
makeContext('trackingId', 'requestId'),
|
||||||
|
[`user_${typistUserId}`],
|
||||||
|
{
|
||||||
|
authorId: 'AUTHOR_ID',
|
||||||
|
filename: 'file',
|
||||||
|
priority: 'High',
|
||||||
|
uploadedAt: '2023-05-26T11:22:33.444',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
// タスクを取得
|
||||||
|
const resultTask = await getTaskFromJobNumber(source, result.jobNumber);
|
||||||
|
// タスクのチェックアウト権限を取得
|
||||||
|
const resultCheckoutPermission = await getCheckoutPermissions(
|
||||||
|
source,
|
||||||
|
resultTask?.id ?? 0,
|
||||||
|
);
|
||||||
|
// タスクがあることを確認
|
||||||
|
expect(resultTask).not.toBeNull();
|
||||||
|
// 自動ルーティングが行われていることを確認
|
||||||
|
expect(resultCheckoutPermission.length).toEqual(1);
|
||||||
|
expect(resultCheckoutPermission[0].user_id).toEqual(typistUserId);
|
||||||
|
});
|
||||||
it('第五階層アカウントのストレージ使用量が閾値と同値の場合、メール送信が行われない', async () => {
|
it('第五階層アカウントのストレージ使用量が閾値と同値の場合、メール送信が行われない', async () => {
|
||||||
if (!source) fail();
|
if (!source) fail();
|
||||||
const module = await makeTestingModule(source);
|
const module = await makeTestingModule(source);
|
||||||
|
|||||||
@ -71,7 +71,8 @@ export class FilesService {
|
|||||||
/**
|
/**
|
||||||
* Uploads finished
|
* Uploads finished
|
||||||
* @param url アップロード先Blob Storage(ファイル名含む)
|
* @param url アップロード先Blob Storage(ファイル名含む)
|
||||||
* @param authorId 自分自身(ログイン認証)したAuthorID
|
* @param userId 自分自身(ログイン認証)したUserID
|
||||||
|
* @param authorId 音声ファイルを管理するAuthorのAuthorID
|
||||||
* @param fileName 音声ファイル名
|
* @param fileName 音声ファイル名
|
||||||
* @param duration 音声ファイルの録音時間(ミリ秒の整数値)
|
* @param duration 音声ファイルの録音時間(ミリ秒の整数値)
|
||||||
* @param createdDate 音声ファイルの録音作成日時(開始日時)(yyyy-mm-ddThh:mm:ss.sss)'
|
* @param createdDate 音声ファイルの録音作成日時(開始日時)(yyyy-mm-ddThh:mm:ss.sss)'
|
||||||
@ -248,7 +249,6 @@ export class FilesService {
|
|||||||
context,
|
context,
|
||||||
task.audio_file_id,
|
task.audio_file_id,
|
||||||
user.account_id,
|
user.account_id,
|
||||||
user.author_id ?? undefined,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const groupMembers =
|
const groupMembers =
|
||||||
|
|||||||
@ -2741,7 +2741,9 @@ describe('checkin', () => {
|
|||||||
];
|
];
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const spy = jest.spyOn(service["sendgridService"], "sendMail").mockImplementation();
|
const spy = jest
|
||||||
|
.spyOn(service['sendgridService'], 'sendMail')
|
||||||
|
.mockImplementation();
|
||||||
|
|
||||||
const initTask = await getTask(source, taskId);
|
const initTask = await getTask(source, taskId);
|
||||||
|
|
||||||
@ -2834,7 +2836,7 @@ describe('checkin', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
let _to = Array(10);
|
let _to = Array(10);
|
||||||
overrideSendgridService(service, {
|
overrideSendgridService(service, {
|
||||||
sendMail: async (
|
sendMail: async (
|
||||||
context: Context,
|
context: Context,
|
||||||
to: string[],
|
to: string[],
|
||||||
@ -2844,7 +2846,7 @@ describe('checkin', () => {
|
|||||||
text: string,
|
text: string,
|
||||||
html: string,
|
html: string,
|
||||||
) => {
|
) => {
|
||||||
_to = to;
|
_to = to;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -2860,7 +2862,7 @@ describe('checkin', () => {
|
|||||||
expect(resultTask?.status).toEqual('Finished');
|
expect(resultTask?.status).toEqual('Finished');
|
||||||
expect(resultTask?.finished_at).not.toEqual(initTask?.finished_at);
|
expect(resultTask?.finished_at).not.toEqual(initTask?.finished_at);
|
||||||
//メール送信処理が呼ばれていない
|
//メール送信処理が呼ばれていない
|
||||||
expect(_to.length).toBe(1)
|
expect(_to.length).toBe(1);
|
||||||
expect(_to).toEqual(['author@example.com']);
|
expect(_to).toEqual(['author@example.com']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -3491,7 +3493,7 @@ describe('cancel', () => {
|
|||||||
// ワークフロータイピストを作成
|
// ワークフロータイピストを作成
|
||||||
await createWorkflowTypist(source, workflowId, typistUserId);
|
await createWorkflowTypist(source, workflowId, typistUserId);
|
||||||
|
|
||||||
const { taskId } = await createTask(
|
const { taskId, audioFileId } = await createTask(
|
||||||
source,
|
source,
|
||||||
accountId,
|
accountId,
|
||||||
authorUserId,
|
authorUserId,
|
||||||
@ -3510,7 +3512,7 @@ describe('cancel', () => {
|
|||||||
);
|
);
|
||||||
await service.cancel(
|
await service.cancel(
|
||||||
makeContext('trackingId', 'requestId'),
|
makeContext('trackingId', 'requestId'),
|
||||||
1,
|
audioFileId,
|
||||||
'typist-user-external-id',
|
'typist-user-external-id',
|
||||||
['typist', 'standard'],
|
['typist', 'standard'],
|
||||||
);
|
);
|
||||||
@ -3537,7 +3539,7 @@ describe('cancel', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('API実行者のRoleがAdminの場合、自身が文字起こし実行中のタスクをキャンセルし、そのタスクの自動ルーティングを行う(API実行者のAuthorIDと音声ファイルに紐づくWorkType)', async () => {
|
it('API実行者のRoleがAuthor,Adminの場合、文字起こし実行中のタスクをキャンセルし、そのタスクの自動ルーティングを行う', async () => {
|
||||||
if (!source) fail();
|
if (!source) fail();
|
||||||
const notificationhubServiceMockValue =
|
const notificationhubServiceMockValue =
|
||||||
makeDefaultNotificationhubServiceMockValue();
|
makeDefaultNotificationhubServiceMockValue();
|
||||||
@ -3594,7 +3596,7 @@ describe('cancel', () => {
|
|||||||
const { id: workflowId } = await createWorkflow(
|
const { id: workflowId } = await createWorkflow(
|
||||||
source,
|
source,
|
||||||
accountId,
|
accountId,
|
||||||
myAuthorUserId,
|
authorUserId,
|
||||||
workTypeId,
|
workTypeId,
|
||||||
templateFileId,
|
templateFileId,
|
||||||
);
|
);
|
||||||
@ -3646,6 +3648,106 @@ describe('cancel', () => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
it('API実行者のRoleがAuthor,Adminの場合、文字起こし実行中のタスクをキャンセルするが、一致するワークフローがない場合は自動ルーティングを行うことができない', async () => {
|
||||||
|
if (!source) fail();
|
||||||
|
const notificationhubServiceMockValue =
|
||||||
|
makeDefaultNotificationhubServiceMockValue();
|
||||||
|
const module = await makeTaskTestingModuleWithNotificaiton(
|
||||||
|
source,
|
||||||
|
notificationhubServiceMockValue,
|
||||||
|
);
|
||||||
|
if (!module) fail();
|
||||||
|
const { id: accountId } = await makeTestSimpleAccount(source);
|
||||||
|
// タスクの文字起こし担当者
|
||||||
|
const { id: typistUserId } = await makeTestUser(source, {
|
||||||
|
account_id: accountId,
|
||||||
|
external_id: 'typist-user-external-id',
|
||||||
|
role: 'typist',
|
||||||
|
});
|
||||||
|
// 自動ルーティングされるタイピストユーザーを作成
|
||||||
|
const { id: autoRoutingTypistUserId } = await makeTestUser(source, {
|
||||||
|
account_id: accountId,
|
||||||
|
external_id: 'auto-routing-typist-user-external-id',
|
||||||
|
role: 'typist',
|
||||||
|
});
|
||||||
|
// API実行者
|
||||||
|
const {
|
||||||
|
id: myAuthorUserId,
|
||||||
|
external_id,
|
||||||
|
role,
|
||||||
|
author_id: myAuthorId,
|
||||||
|
} = await makeTestUser(source, {
|
||||||
|
account_id: accountId,
|
||||||
|
external_id: 'my-author-user-external-id',
|
||||||
|
role: 'author admin',
|
||||||
|
author_id: 'MY_AUTHOR_ID',
|
||||||
|
});
|
||||||
|
// 音声ファイルのアップロード者
|
||||||
|
const { id: authorUserId, author_id } = await makeTestUser(source, {
|
||||||
|
account_id: accountId,
|
||||||
|
external_id: 'author-user-external-id',
|
||||||
|
role: 'author',
|
||||||
|
author_id: 'AUTHOR_ID',
|
||||||
|
});
|
||||||
|
//ワークタイプIDを作成
|
||||||
|
const { id: workTypeId, custom_worktype_id } = await createWorktype(
|
||||||
|
source,
|
||||||
|
accountId,
|
||||||
|
'01',
|
||||||
|
);
|
||||||
|
// テンプレートファイルを作成
|
||||||
|
const { id: templateFileId } = await createTemplateFile(
|
||||||
|
source,
|
||||||
|
accountId,
|
||||||
|
'template-file-name',
|
||||||
|
'https://example.com',
|
||||||
|
);
|
||||||
|
// ワークフローを作成
|
||||||
|
const { id: workflowId } = await createWorkflow(
|
||||||
|
source,
|
||||||
|
accountId,
|
||||||
|
authorUserId,
|
||||||
|
workTypeId,
|
||||||
|
templateFileId,
|
||||||
|
);
|
||||||
|
// ワークフロータイピストを作成
|
||||||
|
await createWorkflowTypist(source, workflowId, autoRoutingTypistUserId);
|
||||||
|
|
||||||
|
const { taskId, audioFileId } = await createTask(
|
||||||
|
source,
|
||||||
|
accountId,
|
||||||
|
myAuthorUserId,
|
||||||
|
myAuthorId ?? '',
|
||||||
|
custom_worktype_id,
|
||||||
|
'01',
|
||||||
|
'00000001',
|
||||||
|
'InProgress',
|
||||||
|
typistUserId,
|
||||||
|
);
|
||||||
|
await createCheckoutPermissions(source, taskId, typistUserId);
|
||||||
|
|
||||||
|
const service = module.get<TasksService>(TasksService);
|
||||||
|
const NotificationHubService = module.get<NotificationhubService>(
|
||||||
|
NotificationhubService,
|
||||||
|
);
|
||||||
|
await service.cancel(
|
||||||
|
makeContext('trackingId', 'requestId'),
|
||||||
|
audioFileId,
|
||||||
|
external_id,
|
||||||
|
role.split(' ') as Roles[],
|
||||||
|
);
|
||||||
|
const resultTask = await getTask(source, taskId);
|
||||||
|
const permisions = await getCheckoutPermissions(source, taskId);
|
||||||
|
|
||||||
|
expect(resultTask?.status).toEqual('Uploaded');
|
||||||
|
expect(resultTask?.typist_user_id).toEqual(null);
|
||||||
|
// タスクのテンプレートファイルIDを確認
|
||||||
|
expect(resultTask?.template_file_id).toEqual(null);
|
||||||
|
// タスクのチェックアウト権限が付与されていないことを確認
|
||||||
|
expect(permisions.length).toEqual(0);
|
||||||
|
// 通知処理が想定通りの引数で呼ばれているか確認
|
||||||
|
expect(NotificationHubService.notify).not.toBeCalled();
|
||||||
|
});
|
||||||
it('API実行者のRoleがTypistの場合、自身が文字起こし実行中のタスクをキャンセルするが、一致するワークフローがない場合は自動ルーティングを行うことができない', async () => {
|
it('API実行者のRoleがTypistの場合、自身が文字起こし実行中のタスクをキャンセルするが、一致するワークフローがない場合は自動ルーティングを行うことができない', async () => {
|
||||||
if (!source) fail();
|
if (!source) fail();
|
||||||
const notificationhubServiceMockValue =
|
const notificationhubServiceMockValue =
|
||||||
|
|||||||
@ -630,7 +630,6 @@ export class TasksService {
|
|||||||
context,
|
context,
|
||||||
audioFileId,
|
audioFileId,
|
||||||
user.account_id,
|
user.account_id,
|
||||||
user.author_id ?? undefined,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// 通知を送信する
|
// 通知を送信する
|
||||||
|
|||||||
@ -1215,7 +1215,6 @@ export class TasksRepositoryService {
|
|||||||
context: Context,
|
context: Context,
|
||||||
audioFileId: number,
|
audioFileId: number,
|
||||||
accountId: number,
|
accountId: number,
|
||||||
myAuthorId?: string, // API実行者のAuthorId
|
|
||||||
): Promise<{ typistIds: number[]; typistGroupIds: number[] }> {
|
): Promise<{ typistIds: number[]; typistGroupIds: number[] }> {
|
||||||
return await this.dataSource.transaction(async (entityManager) => {
|
return await this.dataSource.transaction(async (entityManager) => {
|
||||||
// 音声ファイルを取得
|
// 音声ファイルを取得
|
||||||
@ -1243,6 +1242,11 @@ export class TasksRepositoryService {
|
|||||||
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
|
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
|
||||||
lock: { mode: 'pessimistic_write' },
|
lock: { mode: 'pessimistic_write' },
|
||||||
});
|
});
|
||||||
|
if (!authorUser) {
|
||||||
|
throw new Error(
|
||||||
|
`author not found. author_id:${audio.author_id}, accountId:${accountId}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// TaskとFileを取得
|
// TaskとFileを取得
|
||||||
const taskRepo = entityManager.getRepository(Task);
|
const taskRepo = entityManager.getRepository(Task);
|
||||||
@ -1277,7 +1281,7 @@ export class TasksRepositoryService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 音声ファイル上のworktypeIdが設定されているが、一致するworktypeが存在しない場合はエラーを出して終了
|
// 音声ファイル上のworktypeIdが設定されているが、一致するworktypeが存在しない場合はエラーを出して終了
|
||||||
if (!worktypeRecord && audioFile.work_type_id !== '') {
|
if (audioFile.work_type_id !== '' && !worktypeRecord) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`worktype not found. worktype:${audioFile.work_type_id}, accountId:${accountId}`,
|
`worktype not found. worktype:${audioFile.work_type_id}, accountId:${accountId}`,
|
||||||
);
|
);
|
||||||
@ -1291,7 +1295,7 @@ export class TasksRepositoryService {
|
|||||||
},
|
},
|
||||||
where: {
|
where: {
|
||||||
account_id: accountId,
|
account_id: accountId,
|
||||||
author_id: authorUser?.id ?? IsNull(), // authorUserが存在しない場合は、必ずヒットしないようにNULLを設定する
|
author_id: authorUser.id,
|
||||||
worktype_id: worktypeRecord?.id ?? IsNull(),
|
worktype_id: worktypeRecord?.id ?? IsNull(),
|
||||||
},
|
},
|
||||||
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
|
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
|
||||||
@ -1299,61 +1303,14 @@ export class TasksRepositoryService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Workflow(ルーティングルール)があればタスクのチェックアウト権限を設定する
|
// Workflow(ルーティングルール)があればタスクのチェックアウト権限を設定する
|
||||||
if (workflow) {
|
if (!workflow) {
|
||||||
return await this.setCheckoutPermissionAndTemplate(
|
|
||||||
context,
|
|
||||||
workflow,
|
|
||||||
task,
|
|
||||||
accountId,
|
|
||||||
entityManager,
|
|
||||||
userRepo,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 音声ファイルの情報からルーティングルールを取得できない場合は、
|
|
||||||
// API実行者のAuthorIdと音声ファイルのWorktypeをもとにルーティングルールを取得する
|
|
||||||
// API実行者のAuthorIdがない場合はエラーを出して終了
|
|
||||||
if (!myAuthorId) {
|
|
||||||
throw new Error(`There is no AuthorId for the API executor.`);
|
|
||||||
}
|
|
||||||
// API実行者のAuthorIdをもとにユーザーを取得
|
|
||||||
const myAuthorUser = await userRepo.findOne({
|
|
||||||
where: {
|
|
||||||
author_id: myAuthorId,
|
|
||||||
account_id: accountId,
|
|
||||||
},
|
|
||||||
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
|
|
||||||
lock: { mode: 'pessimistic_write' },
|
|
||||||
});
|
|
||||||
if (!myAuthorUser) {
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`user not found. authorId:${myAuthorId}, accountId:${accountId}`,
|
`workflow not found. authorUserId:${authorUser.id}, accountId:${accountId}, worktypeId:${worktypeRecord?.id}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const defaultWorkflow = await workflowRepo.findOne({
|
|
||||||
relations: {
|
|
||||||
workflowTypists: true,
|
|
||||||
},
|
|
||||||
where: {
|
|
||||||
account_id: accountId,
|
|
||||||
author_id: myAuthorUser.id,
|
|
||||||
worktype_id: worktypeRecord?.id ?? IsNull(),
|
|
||||||
},
|
|
||||||
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
|
|
||||||
lock: { mode: 'pessimistic_write' },
|
|
||||||
});
|
|
||||||
|
|
||||||
// API実行者のAuthorIdと音声ファイルのWorktypeをもとにルーティングルールを取得できない場合はエラーを出して終了
|
|
||||||
if (!defaultWorkflow) {
|
|
||||||
throw new Error(
|
|
||||||
`workflow not found. authorUserId:${myAuthorUser.id}, accountId:${accountId}, worktypeId:${worktypeRecord?.id}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Workflow(ルーティングルール)があればタスクのチェックアウト権限を設定する
|
|
||||||
return await this.setCheckoutPermissionAndTemplate(
|
return await this.setCheckoutPermissionAndTemplate(
|
||||||
context,
|
context,
|
||||||
defaultWorkflow,
|
workflow,
|
||||||
task,
|
task,
|
||||||
accountId,
|
accountId,
|
||||||
entityManager,
|
entityManager,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user