## 概要 [ユーザー ストーリー 4489: 【PH1エンハンス】Dictation Finishedになったファイルのステータスを変更したい](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/OMDSDictation-2nd/_workitems/edit/4489) [ユーザー ストーリー 4491: 【PH1エンハンス】通知にユーザーIDを付加する](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/OMDSDictation-2nd/_workitems/edit/4491)
3676 lines
115 KiB
TypeScript
3676 lines
115 KiB
TypeScript
import { HttpException, HttpStatus } from '@nestjs/common';
|
||
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||
import { makeBlobstorageServiceMockValue } from './test/files.service.mock';
|
||
import { DataSource } from 'typeorm';
|
||
import {
|
||
createLicense,
|
||
createTask,
|
||
createUserGroupAndMember,
|
||
getTaskFromJobNumber,
|
||
makeTestingModuleWithBlobAndNotification,
|
||
updateTaskStatusAndIsJobNumberEnabled,
|
||
} from './test/utility';
|
||
import { FilesService } from './files.service';
|
||
import { makeContext } from '../../common/log';
|
||
import {
|
||
createJobNumber,
|
||
getJobNumber,
|
||
getTasks,
|
||
makeHierarchicalAccounts,
|
||
makeTestAccount,
|
||
makeTestSimpleAccount,
|
||
makeTestUser,
|
||
updateJobNumber,
|
||
} from '../../common/test/utility';
|
||
import { makeTestingModule } from '../../common/test/modules';
|
||
import {
|
||
overrideAdB2cService,
|
||
overrideBlobstorageService,
|
||
} from '../../common/test/overrides';
|
||
import {
|
||
createTemplateFile,
|
||
getTemplateFiles,
|
||
} from '../templates/test/utility';
|
||
import { TemplateFilesRepositoryService } from '../../repositories/template_files/template_files.repository.service';
|
||
import { makeDefaultNotificationhubServiceMockValue } from '../tasks/test/tasks.service.mock';
|
||
import {
|
||
createWorkflow,
|
||
createWorkflowTypist,
|
||
} from '../workflows/test/utility';
|
||
import { createWorktype } from '../accounts/test/utility';
|
||
import { TasksRepositoryService } from '../../repositories/tasks/tasks.repository.service';
|
||
import { NotificationhubService } from '../../gateways/notificationhub/notificationhub.service';
|
||
import {
|
||
createCheckoutPermissions,
|
||
getAudioFile,
|
||
getCheckoutPermissions,
|
||
} from '../tasks/test/utility';
|
||
import { DateWithZeroTime } from '../licenses/types/types';
|
||
import {
|
||
LICENSE_ALLOCATED_STATUS,
|
||
LICENSE_TYPE,
|
||
TASK_STATUS,
|
||
USER_ROLES,
|
||
} from '../../constants';
|
||
import { truncateAllTable } from '../../common/test/init';
|
||
import { TestLogger } from '../../common/test/logger';
|
||
import { TasksService } from '../tasks/tasks.service';
|
||
|
||
describe('publishUploadSas', () => {
|
||
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が行われるため注意
|
||
logger: new TestLogger('none'),
|
||
logging: true,
|
||
});
|
||
return await s.initialize();
|
||
})();
|
||
}
|
||
});
|
||
|
||
beforeEach(async () => {
|
||
if (source) {
|
||
await truncateAllTable(source);
|
||
}
|
||
});
|
||
|
||
afterAll(async () => {
|
||
await source?.destroy();
|
||
source = null;
|
||
});
|
||
|
||
it('音声アップロードSASトークンが乗っているURLを取得できる', async () => {
|
||
if (!source) fail();
|
||
const module = await makeTestingModule(source);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
// 第五階層のアカウント作成
|
||
const { account: account } = await makeTestAccount(source, { tier: 5 });
|
||
const { external_id: externalId, id: userId } = await makeTestUser(source, {
|
||
account_id: account.id,
|
||
external_id: 'author-user-external-id',
|
||
role: 'author',
|
||
author_id: 'AUTHOR_ID',
|
||
});
|
||
// 本日の日付を作成
|
||
let today = new Date();
|
||
today.setDate(today.getDate());
|
||
today = new DateWithZeroTime(today);
|
||
// 有効期限内のライセンスを作成して紐づける
|
||
await createLicense(
|
||
source,
|
||
1,
|
||
today,
|
||
account.id,
|
||
LICENSE_TYPE.NORMAL,
|
||
LICENSE_ALLOCATED_STATUS.ALLOCATED,
|
||
userId,
|
||
null,
|
||
null,
|
||
null,
|
||
);
|
||
const context = makeContext(externalId, 'requestId');
|
||
const baseUrl = `https://saodmsusdev.blob.core.windows.net/account-${account.id}/${userId}`;
|
||
|
||
//SASトークンを返却する
|
||
overrideBlobstorageService(service, {
|
||
containerExists: async () => true,
|
||
publishUploadSas: async () => `${baseUrl}?sas-token`,
|
||
});
|
||
|
||
const url = await service.publishUploadSas(context, externalId);
|
||
|
||
expect(url).toBe(`${baseUrl}?sas-token`);
|
||
});
|
||
|
||
it('blobストレージにコンテナが存在しない場合はエラーとなる', async () => {
|
||
if (!source) fail();
|
||
const module = await makeTestingModule(source);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
// 第四階層のアカウント作成
|
||
const { admin } = await makeTestAccount(source, { tier: 4 });
|
||
|
||
const context = makeContext(admin.external_id, 'requestId');
|
||
|
||
//Blobコンテナ存在チェックに失敗するようにする
|
||
overrideBlobstorageService(service, {
|
||
containerExists: async () => false,
|
||
publishUploadSas: async () => '',
|
||
});
|
||
|
||
try {
|
||
await service.publishUploadSas(context, admin.external_id);
|
||
} catch (e) {
|
||
if (e instanceof HttpException) {
|
||
expect(e.getStatus()).toBe(HttpStatus.INTERNAL_SERVER_ERROR);
|
||
expect(e.getResponse()).toEqual(makeErrorResponse('E009999'));
|
||
} else {
|
||
fail();
|
||
}
|
||
}
|
||
});
|
||
|
||
it('SASトークンの取得に失敗した場合はエラーとなる', async () => {
|
||
if (!source) fail();
|
||
const module = await makeTestingModule(source);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
// 第四階層のアカウント作成
|
||
const { admin } = await makeTestAccount(source, { tier: 4 });
|
||
|
||
const context = makeContext(admin.external_id, 'requestId');
|
||
|
||
//BlobのSASトークン生成に失敗するようにする
|
||
overrideBlobstorageService(service, {
|
||
containerExists: async () => true,
|
||
publishUploadSas: async () => {
|
||
throw new Error('blob failed');
|
||
},
|
||
});
|
||
|
||
try {
|
||
await service.publishUploadSas(context, admin.external_id);
|
||
} catch (e) {
|
||
if (e instanceof HttpException) {
|
||
expect(e.getStatus()).toBe(HttpStatus.INTERNAL_SERVER_ERROR);
|
||
expect(e.getResponse()).toEqual(makeErrorResponse('E009999'));
|
||
} else {
|
||
fail();
|
||
}
|
||
}
|
||
});
|
||
it('アカウントがロックされている場合、エラーとなる', async () => {
|
||
if (!source) fail();
|
||
const module = await makeTestingModule(source);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
// 第五階層のアカウント作成
|
||
const { admin } = await makeTestAccount(source, { tier: 5, locked: true });
|
||
|
||
const context = makeContext(admin.external_id, 'requestId');
|
||
|
||
try {
|
||
await service.publishUploadSas(context, admin.external_id);
|
||
} catch (e) {
|
||
if (e instanceof HttpException) {
|
||
expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST);
|
||
expect(e.getResponse()).toEqual(makeErrorResponse('E010504'));
|
||
} else {
|
||
fail();
|
||
}
|
||
}
|
||
});
|
||
it('アップロード時にユーザーにライセンスが未割当の場合エラーとなる(第五階層限定)', async () => {
|
||
if (!source) fail();
|
||
// 第五階層のアカウントまで作成し、そのアカウントに紐づくユーザーを作成する(ライセンスは作成しない)
|
||
const { tier4Accounts: tier4Accounts } = await makeHierarchicalAccounts(
|
||
source,
|
||
);
|
||
const tier5Accounts = await makeTestAccount(source, {
|
||
parent_account_id: tier4Accounts[0].account.id,
|
||
tier: 5,
|
||
});
|
||
const { external_id: externalId, id: userId } = await makeTestUser(source, {
|
||
account_id: tier5Accounts.account.id,
|
||
external_id: 'author-user-external-id',
|
||
role: 'author',
|
||
author_id: 'AUTHOR_ID',
|
||
});
|
||
const url = `https://saodmsusdev.blob.core.windows.net/account-${tier5Accounts.account.id}/${userId}`;
|
||
|
||
const blobParam = makeBlobstorageServiceMockValue();
|
||
blobParam.publishUploadSas = `${url}?sas-token`;
|
||
blobParam.fileExists = false;
|
||
|
||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||
const module = await makeTestingModuleWithBlobAndNotification(
|
||
source,
|
||
blobParam,
|
||
notificationParam,
|
||
);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
|
||
await expect(
|
||
service.publishUploadSas(
|
||
makeContext('trackingId', 'requestId'),
|
||
externalId,
|
||
),
|
||
).rejects.toEqual(
|
||
new HttpException(makeErrorResponse('E010812'), HttpStatus.BAD_REQUEST),
|
||
);
|
||
});
|
||
});
|
||
|
||
describe('タスク作成から自動ルーティング(DB使用)', () => {
|
||
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が行われるため注意
|
||
logger: new TestLogger('none'),
|
||
logging: true,
|
||
});
|
||
return await s.initialize();
|
||
})();
|
||
}
|
||
});
|
||
|
||
beforeEach(async () => {
|
||
if (source) {
|
||
await truncateAllTable(source);
|
||
}
|
||
});
|
||
|
||
afterAll(async () => {
|
||
await source?.destroy();
|
||
source = null;
|
||
});
|
||
it('タスク作成時に、自動ルーティングを行うことができる(APIの引数として渡されたAuthorIDとworkType)', async () => {
|
||
if (!source) fail();
|
||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||
const {
|
||
external_id: authorExternalId,
|
||
id: authorUserId,
|
||
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,
|
||
});
|
||
// ワークタイプを作成
|
||
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,
|
||
authorUserId,
|
||
worktypeId,
|
||
templateFileId,
|
||
);
|
||
// ワークフロータイピストを作成
|
||
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,
|
||
'http://blob/url/file.zip',
|
||
authorAuthorId ?? '',
|
||
'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',
|
||
id: '2',
|
||
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_id).toEqual(typistUserId);
|
||
});
|
||
|
||
it('別のタスクが既に存在する場合、タスク作成時に、自動ルーティングを行うことができる(APIの引数として渡されたAuthorIDとworkType)', async () => {
|
||
if (!source) fail();
|
||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||
const {
|
||
external_id: authorExternalId,
|
||
id: authorUserId,
|
||
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,
|
||
});
|
||
//タスクを作成
|
||
await createTask(
|
||
source,
|
||
accountId,
|
||
'http://blob/url/file.zip',
|
||
'file.zip',
|
||
'Uploaded',
|
||
typistUserId,
|
||
authorAuthorId ?? '',
|
||
);
|
||
// ワークタイプを作成
|
||
const { id: worktypeId, custom_worktype_id } = await createWorktype(
|
||
source,
|
||
accountId,
|
||
'worktypeId',
|
||
);
|
||
// ワークフローを作成
|
||
const { id: workflowId } = await createWorkflow(
|
||
source,
|
||
accountId,
|
||
authorUserId,
|
||
worktypeId,
|
||
);
|
||
// ワークフロータイピストを作成
|
||
await createWorkflowTypist(source, workflowId, typistUserId);
|
||
|
||
// 最新のジョブナンバーでjob_numberテーブルを作成
|
||
await createJobNumber(source, accountId, '00000001');
|
||
|
||
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,
|
||
'http://blob/url/file.zip',
|
||
authorAuthorId ?? '',
|
||
'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('00000002');
|
||
// 通知処理が想定通りの引数で呼ばれているか確認
|
||
expect(notificationHubService.notify).toHaveBeenCalledWith(
|
||
makeContext('trackingId', 'requestId'),
|
||
`user_${typistUserId}`,
|
||
{
|
||
authorId: 'AUTHOR_ID',
|
||
filename: 'file',
|
||
id: '2',
|
||
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).toBeNull();
|
||
// タスクのチェックアウト権限が想定通り(ワークフローで設定されている)のユーザーIDで作成されているか確認
|
||
expect(resultCheckoutPermission.length).toEqual(1);
|
||
expect(resultCheckoutPermission[0].user_id).toEqual(typistUserId);
|
||
});
|
||
|
||
it('タスク作成時に、音声ファイルメタ情報のAuthorIDに存在しないIDが入っていた場合自動ルーティングを行うことができない', async () => {
|
||
if (!source) fail();
|
||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||
// 音声ファイルの録音者のユーザー
|
||
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',
|
||
'XXXXXX', // 存在しない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).not.toBeCalled();
|
||
// 作成したタスクを取得
|
||
const resultTask = await getTaskFromJobNumber(source, result.jobNumber);
|
||
// タスクのチェックアウト権限を取得
|
||
const resultCheckoutPermission = await getCheckoutPermissions(
|
||
source,
|
||
resultTask?.id ?? 0,
|
||
);
|
||
// タスクのテンプレートファイルIDを確認
|
||
expect(resultTask?.template_file_id).toBeNull();
|
||
// 存在しないAuthorIDを指定してタスクを作成したためルーティングが行われず、タスクのチェックアウト権限は誰にも付与されない
|
||
expect(resultCheckoutPermission.length).toEqual(0);
|
||
});
|
||
|
||
it('ワークフローが見つからない場合、タスク作成時に自動ルーティングを行うことができない', async () => {
|
||
if (!source) fail();
|
||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||
// 音声ファイルの録音者のユーザー
|
||
const { external_id: authorExternalId, author_id: authorAuthorId } =
|
||
await makeTestUser(source, {
|
||
account_id: accountId,
|
||
external_id: 'author-user-external-id',
|
||
role: 'author',
|
||
author_id: 'AUTHOR_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 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');
|
||
// タスクを取得
|
||
const resultTask = await getTaskFromJobNumber(source, result.jobNumber);
|
||
// タスクのチェックアウト権限を取得
|
||
const resultCheckoutPermission = await getCheckoutPermissions(
|
||
source,
|
||
resultTask?.id ?? 0,
|
||
);
|
||
// タスクがあることを確認
|
||
expect(resultTask).not.toBeNull();
|
||
// 自動ルーティングが行われていないことを確認
|
||
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',
|
||
id: '2',
|
||
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 () => {
|
||
if (!source) fail();
|
||
const module = await makeTestingModule(source);
|
||
if (!module) fail();
|
||
|
||
// アカウントを作成する
|
||
const { id: accountId } = (
|
||
await makeTestAccount(source, {
|
||
tier: 5,
|
||
company_name: 'company1',
|
||
})
|
||
).account;
|
||
|
||
// 音声ファイルの録音者のユーザー
|
||
const { external_id: authorExternalId, author_id: authorAuthorId } =
|
||
await makeTestUser(source, {
|
||
account_id: accountId,
|
||
external_id: 'author-user-external-id',
|
||
role: 'author',
|
||
author_id: 'AUTHOR_ID',
|
||
});
|
||
|
||
// ライセンスを作成する。ライセンスが2つのため、5GB * 2 = 10GBの上限値となる。
|
||
// 閾値は、10GB * 0.8 = 8GBとなる。
|
||
const reusableLicense = 2;
|
||
for (let i = 0; i < reusableLicense; i++) {
|
||
await createLicense(
|
||
source,
|
||
i + 1,
|
||
new Date(2037, 1, 1, 23, 59, 59),
|
||
accountId,
|
||
LICENSE_TYPE.NORMAL,
|
||
LICENSE_ALLOCATED_STATUS.REUSABLE,
|
||
null,
|
||
null,
|
||
null,
|
||
null,
|
||
);
|
||
}
|
||
|
||
const fileSize = 2 * 1000 * 1000 * 1000; // 2GB
|
||
// 3つの音声ファイルを事前作成+uploadFinishedで、合計8GBのストレージ使用量状態を作成
|
||
for (let i = 0; i < 3; i++) {
|
||
await createTask(
|
||
source,
|
||
accountId,
|
||
'url',
|
||
'test.zip',
|
||
'InProgress',
|
||
undefined,
|
||
authorAuthorId ?? '',
|
||
undefined,
|
||
fileSize,
|
||
(i + 1).toString().padStart(8, '0'),
|
||
);
|
||
}
|
||
|
||
// 最新のジョブナンバーでjob_numberテーブルを更新
|
||
await updateJobNumber(source, accountId, '00000003');
|
||
|
||
const service = module.get<FilesService>(FilesService);
|
||
const spy = jest
|
||
.spyOn(service['sendGridService'], 'sendMail')
|
||
.mockImplementation();
|
||
const context = makeContext(`uuidv4`, 'xxx-xxx-xxx-xxx', 'requestId');
|
||
await service.uploadFinished(
|
||
context,
|
||
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',
|
||
fileSize,
|
||
'01',
|
||
'DS2',
|
||
'comment',
|
||
'worktypeId',
|
||
optionItemList,
|
||
false,
|
||
);
|
||
|
||
expect(spy).not.toHaveBeenCalled();
|
||
});
|
||
it('第五階層アカウントのストレージ使用量が閾値+1byteの場合、U-118メール送信が行われる', async () => {
|
||
if (!source) fail();
|
||
const module = await makeTestingModule(source);
|
||
if (!module) fail();
|
||
|
||
// アカウントを作成する
|
||
const { id: accountId } = (
|
||
await makeTestAccount(source, {
|
||
tier: 5,
|
||
company_name: 'company1',
|
||
})
|
||
).account;
|
||
|
||
// 音声ファイルの録音者のユーザー
|
||
const { external_id: authorExternalId, author_id: authorAuthorId } =
|
||
await makeTestUser(source, {
|
||
account_id: accountId,
|
||
external_id: 'author-user-external-id',
|
||
role: 'author',
|
||
author_id: 'AUTHOR_ID',
|
||
});
|
||
|
||
// ライセンスを作成する。ライセンスが2つのため、5GB * 2 = 10GBの上限値となる。
|
||
// 閾値は、10GB * 0.8 = 8GBとなる。
|
||
const reusableLicense = 2;
|
||
for (let i = 0; i < reusableLicense; i++) {
|
||
await createLicense(
|
||
source,
|
||
i + 1,
|
||
new Date(2037, 1, 1, 23, 59, 59),
|
||
accountId,
|
||
LICENSE_TYPE.NORMAL,
|
||
LICENSE_ALLOCATED_STATUS.REUSABLE,
|
||
null,
|
||
null,
|
||
null,
|
||
null,
|
||
);
|
||
}
|
||
|
||
const fileSize = 2 * 1000 * 1000 * 1000; // 2GB
|
||
// 3つの音声ファイルを事前作成+uploadFinishedで、合計8GB+1byteのストレージ使用量状態を作成
|
||
for (let i = 0; i < 3; i++) {
|
||
await createTask(
|
||
source,
|
||
accountId,
|
||
'url',
|
||
'test.zip',
|
||
'InProgress',
|
||
undefined,
|
||
authorAuthorId ?? '',
|
||
undefined,
|
||
fileSize,
|
||
(i + 1).toString().padStart(8, '0'),
|
||
);
|
||
}
|
||
|
||
// 最新のジョブナンバーでjob_numberテーブルを更新
|
||
await updateJobNumber(source, accountId, '00000003');
|
||
|
||
const service = module.get<FilesService>(FilesService);
|
||
// メール送信関数が呼ばれたかどうかで判定を行う。実際のメール送信は行わない。
|
||
const spy = jest
|
||
.spyOn(service['sendGridService'], 'sendMailWithU118')
|
||
.mockImplementation();
|
||
overrideAdB2cService(service, {
|
||
getUsers: async () => [],
|
||
});
|
||
const context = makeContext(`uuidv4`, 'xxx-xxx-xxx-xxx', 'requestId');
|
||
await service.uploadFinished(
|
||
context,
|
||
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',
|
||
fileSize + 1,
|
||
'01',
|
||
'DS2',
|
||
'comment',
|
||
'worktypeId',
|
||
optionItemList,
|
||
false,
|
||
);
|
||
|
||
expect(spy).toHaveBeenCalledTimes(1);
|
||
});
|
||
it('第五階層アカウントのストレージ使用量が上限と同値の場合、U-118メール送信が行われる', async () => {
|
||
if (!source) fail();
|
||
const module = await makeTestingModule(source);
|
||
if (!module) fail();
|
||
|
||
// アカウントを作成する
|
||
const { id: accountId } = (
|
||
await makeTestAccount(source, {
|
||
tier: 5,
|
||
company_name: 'company1',
|
||
})
|
||
).account;
|
||
|
||
// 音声ファイルの録音者のユーザー
|
||
const { external_id: authorExternalId, author_id: authorAuthorId } =
|
||
await makeTestUser(source, {
|
||
account_id: accountId,
|
||
external_id: 'author-user-external-id',
|
||
role: 'author',
|
||
author_id: 'AUTHOR_ID',
|
||
});
|
||
|
||
// ライセンスを作成する。ライセンスが2つのため、5GB * 2 = 10GBの上限値となる。
|
||
const reusableLicense = 2;
|
||
for (let i = 0; i < reusableLicense; i++) {
|
||
await createLicense(
|
||
source,
|
||
i + 1,
|
||
new Date(2037, 1, 1, 23, 59, 59),
|
||
accountId,
|
||
LICENSE_TYPE.NORMAL,
|
||
LICENSE_ALLOCATED_STATUS.REUSABLE,
|
||
null,
|
||
null,
|
||
null,
|
||
null,
|
||
);
|
||
}
|
||
|
||
const fileSize = 2 * 1000 * 1000 * 1000; // 2GB
|
||
// 4つの音声ファイルを事前作成+uploadFinishedで、合計10GBのストレージ使用量状態を作成
|
||
for (let i = 0; i < 4; i++) {
|
||
await createTask(
|
||
source,
|
||
accountId,
|
||
'url',
|
||
'test.zip',
|
||
'InProgress',
|
||
undefined,
|
||
authorAuthorId ?? '',
|
||
undefined,
|
||
fileSize,
|
||
(i + 1).toString().padStart(8, '0'),
|
||
);
|
||
}
|
||
|
||
// 最新のジョブナンバーでjob_numberテーブルを更新
|
||
await updateJobNumber(source, accountId, '00000004');
|
||
|
||
const service = module.get<FilesService>(FilesService);
|
||
// メール送信関数が呼ばれたかどうかで判定を行う。実際のメール送信は行わない。
|
||
const spy = jest
|
||
.spyOn(service['sendGridService'], 'sendMailWithU118')
|
||
.mockImplementation();
|
||
overrideAdB2cService(service, {
|
||
getUsers: async () => [],
|
||
});
|
||
const context = makeContext(`uuidv4`, 'xxx-xxx-xxx-xxx', 'requestId');
|
||
await service.uploadFinished(
|
||
context,
|
||
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',
|
||
fileSize,
|
||
'01',
|
||
'DS2',
|
||
'comment',
|
||
'worktypeId',
|
||
optionItemList,
|
||
false,
|
||
);
|
||
|
||
expect(spy).toHaveBeenCalledTimes(1);
|
||
});
|
||
it('第五階層アカウントのストレージ使用量が上限+1byteと同値の場合、U-119メール送信が行われる', async () => {
|
||
if (!source) fail();
|
||
const module = await makeTestingModule(source);
|
||
if (!module) fail();
|
||
|
||
// アカウントを作成する
|
||
const { id: accountId } = (
|
||
await makeTestAccount(source, {
|
||
tier: 5,
|
||
company_name: 'company1',
|
||
})
|
||
).account;
|
||
|
||
// 第一階層アカウントを作成する
|
||
await makeTestAccount(source, {
|
||
tier: 1,
|
||
});
|
||
|
||
// 音声ファイルの録音者のユーザー
|
||
const { external_id: authorExternalId, author_id: authorAuthorId } =
|
||
await makeTestUser(source, {
|
||
account_id: accountId,
|
||
external_id: 'author-user-external-id',
|
||
role: 'author',
|
||
author_id: 'AUTHOR_ID',
|
||
});
|
||
|
||
// ライセンスを作成する。ライセンスが2つのため、5GB * 2 = 10GBの上限値となる。
|
||
const reusableLicense = 2;
|
||
for (let i = 0; i < reusableLicense; i++) {
|
||
await createLicense(
|
||
source,
|
||
i + 1,
|
||
new Date(2037, 1, 1, 23, 59, 59),
|
||
accountId,
|
||
LICENSE_TYPE.NORMAL,
|
||
LICENSE_ALLOCATED_STATUS.REUSABLE,
|
||
null,
|
||
null,
|
||
null,
|
||
null,
|
||
);
|
||
}
|
||
|
||
const fileSize = 2 * 1000 * 1000 * 1000; // 2GB
|
||
// 4つの音声ファイルを事前作成+uploadFinishedで、合計10GB+1byteのストレージ使用量状態を作成
|
||
for (let i = 0; i < 4; i++) {
|
||
await createTask(
|
||
source,
|
||
accountId,
|
||
'url',
|
||
'test.zip',
|
||
'InProgress',
|
||
undefined,
|
||
authorAuthorId ?? '',
|
||
undefined,
|
||
fileSize,
|
||
(i + 1).toString().padStart(8, '0'),
|
||
);
|
||
}
|
||
|
||
// 最新のジョブナンバーでjob_numberテーブルを更新
|
||
await updateJobNumber(source, accountId, '00000004');
|
||
|
||
const service = module.get<FilesService>(FilesService);
|
||
// メール送信関数が呼ばれたかどうかで判定を行う。実際のメール送信は行わない。
|
||
const spy = jest
|
||
.spyOn(service['sendGridService'], 'sendMailWithU119')
|
||
.mockImplementation();
|
||
overrideAdB2cService(service, {
|
||
getUsers: async () => [],
|
||
});
|
||
const context = makeContext(`uuidv4`, 'xxx-xxx-xxx-xxx', 'requestId');
|
||
await service.uploadFinished(
|
||
context,
|
||
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',
|
||
fileSize + 1,
|
||
'01',
|
||
'DS2',
|
||
'comment',
|
||
'worktypeId',
|
||
optionItemList,
|
||
false,
|
||
);
|
||
|
||
expect(spy).toHaveBeenCalledTimes(1);
|
||
});
|
||
it('日付フォーマットが不正な場合、エラーを返却する', async () => {
|
||
if (!source) fail();
|
||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||
const { external_id: authorExternalId, author_id: authorAuthorId } =
|
||
await makeTestUser(source, {
|
||
account_id: accountId,
|
||
external_id: 'author-user-external-id',
|
||
role: 'author',
|
||
author_id: 'AUTHOR_ID',
|
||
});
|
||
const blobParam = makeBlobstorageServiceMockValue();
|
||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||
|
||
const module = await makeTestingModuleWithBlobAndNotification(
|
||
source,
|
||
blobParam,
|
||
notificationParam,
|
||
);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
|
||
await expect(
|
||
service.uploadFinished(
|
||
makeContext('trackingId', 'requestId'),
|
||
authorExternalId,
|
||
'http://blob/url/file.zip',
|
||
authorAuthorId ?? '',
|
||
'file.zip',
|
||
'11:22:33',
|
||
'yyyy-05-26T11:22:33.444',
|
||
'2023-05-26T11:22:33.444',
|
||
'2023-05-26T11:22:33.444',
|
||
256,
|
||
'01',
|
||
'DS2',
|
||
'comment',
|
||
'workTypeID',
|
||
optionItemList,
|
||
false,
|
||
),
|
||
).rejects.toEqual(
|
||
new HttpException(makeErrorResponse('E010001'), HttpStatus.BAD_REQUEST),
|
||
);
|
||
});
|
||
it('オプションアイテムが10個ない場合、エラーを返却する', async () => {
|
||
if (!source) fail();
|
||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||
const { external_id: authorExternalId, author_id: authorAuthorId } =
|
||
await makeTestUser(source, {
|
||
account_id: accountId,
|
||
external_id: 'author-user-external-id',
|
||
role: 'author',
|
||
author_id: 'AUTHOR_ID',
|
||
});
|
||
const blobParam = makeBlobstorageServiceMockValue();
|
||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||
|
||
const module = await makeTestingModuleWithBlobAndNotification(
|
||
source,
|
||
blobParam,
|
||
notificationParam,
|
||
);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
|
||
await expect(
|
||
service.uploadFinished(
|
||
makeContext('trackingId', 'requestId'),
|
||
authorExternalId,
|
||
'http://blob/url/file.zip',
|
||
authorAuthorId ?? '',
|
||
'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',
|
||
'workTypeID',
|
||
[
|
||
{
|
||
optionItemLabel: 'label_01',
|
||
optionItemValue: 'value_01',
|
||
},
|
||
],
|
||
false,
|
||
),
|
||
).rejects.toEqual(
|
||
new HttpException(makeErrorResponse('E010001'), HttpStatus.BAD_REQUEST),
|
||
);
|
||
});
|
||
it('タスク追加でユーザー情報の取得に失敗した場合、エラーを返却する', async () => {
|
||
if (!source) fail();
|
||
const blobParam = makeBlobstorageServiceMockValue();
|
||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||
|
||
const module = await makeTestingModuleWithBlobAndNotification(
|
||
source,
|
||
blobParam,
|
||
notificationParam,
|
||
);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
|
||
await expect(
|
||
service.uploadFinished(
|
||
makeContext('trackingId', 'requestId'),
|
||
'authorExternalId',
|
||
'http://blob/url/file.zip',
|
||
'authorAuthorId',
|
||
'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',
|
||
'workTypeID',
|
||
optionItemList,
|
||
false,
|
||
),
|
||
).rejects.toEqual(
|
||
new HttpException(
|
||
makeErrorResponse('E009999'),
|
||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||
),
|
||
);
|
||
});
|
||
it('タスクのDBへの追加に失敗した場合、エラーを返却する', async () => {
|
||
if (!source) fail();
|
||
const blobParam = makeBlobstorageServiceMockValue();
|
||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||
|
||
const module = await makeTestingModuleWithBlobAndNotification(
|
||
source,
|
||
blobParam,
|
||
notificationParam,
|
||
);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
const taskRepoService = module.get<TasksRepositoryService>(
|
||
TasksRepositoryService,
|
||
);
|
||
taskRepoService.create = jest.fn().mockRejectedValue(new Error(''));
|
||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||
const { external_id: authorExternalId, author_id: authorAuthorId } =
|
||
await makeTestUser(source, {
|
||
account_id: accountId,
|
||
external_id: 'author-user-external-id',
|
||
role: 'author',
|
||
author_id: 'AUTHOR_ID',
|
||
});
|
||
|
||
await expect(
|
||
service.uploadFinished(
|
||
makeContext('trackingId', 'requestId'),
|
||
authorExternalId,
|
||
'http://blob/url/file.zip',
|
||
authorAuthorId ?? '',
|
||
'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',
|
||
'workTypeID',
|
||
optionItemList,
|
||
false,
|
||
),
|
||
).rejects.toEqual(
|
||
new HttpException(
|
||
makeErrorResponse('E009999'),
|
||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||
),
|
||
);
|
||
});
|
||
|
||
it('タスク作成時に採番されるジョブナンバーが常に最新タスクのジョブナンバー + 1となる(最新タスクのジョブナンバーが有効でない場合)', async () => {
|
||
if (!source) fail();
|
||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||
const {
|
||
external_id: authorExternalId,
|
||
id: authorUserId,
|
||
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,
|
||
});
|
||
// ワークタイプを作成
|
||
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,
|
||
authorUserId,
|
||
worktypeId,
|
||
templateFileId,
|
||
);
|
||
// ワークフロータイピストを作成
|
||
await createWorkflowTypist(source, workflowId, typistUserId);
|
||
const blobParam = makeBlobstorageServiceMockValue();
|
||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||
|
||
// タスクを10件作成, ジョブナンバーは00000001から00000010まで
|
||
for (let i = 1; i <= 10; i++) {
|
||
await createTask(
|
||
source,
|
||
accountId,
|
||
`http://blob/url/file_${i}.zip`,
|
||
`file_${i}.zip`,
|
||
'Uploaded',
|
||
typistUserId,
|
||
authorAuthorId ?? '',
|
||
undefined,
|
||
undefined,
|
||
i.toString().padStart(8, '0'),
|
||
);
|
||
}
|
||
|
||
// 最新のジョブナンバーでタスクを取得
|
||
const latestTask = await getTaskFromJobNumber(source, '00000010');
|
||
|
||
// 最新のタスクのステータスとis_job_number_enabledを更新
|
||
await updateTaskStatusAndIsJobNumberEnabled(
|
||
source,
|
||
latestTask?.id ?? 0,
|
||
'Backup',
|
||
false,
|
||
);
|
||
|
||
// 最新のジョブナンバーでjob_numberテーブルを作成
|
||
await createJobNumber(source, accountId, '00000010');
|
||
|
||
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,
|
||
'http://blob/url/file.zip',
|
||
authorAuthorId ?? '',
|
||
'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('00000011');
|
||
// 通知処理が想定通りの引数で呼ばれているか確認
|
||
expect(notificationHubService.notify).toHaveBeenCalledWith(
|
||
makeContext('trackingId', 'requestId'),
|
||
`user_${typistUserId}`,
|
||
{
|
||
authorId: 'AUTHOR_ID',
|
||
filename: 'file',
|
||
id: '2',
|
||
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_id).toEqual(typistUserId);
|
||
});
|
||
|
||
it('タスク作成時に採番されるジョブナンバーが常に最新タスクのジョブナンバー + 1となる(最新タスクのジョブナンバー有効である場合)', async () => {
|
||
if (!source) fail();
|
||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||
const {
|
||
external_id: authorExternalId,
|
||
id: authorUserId,
|
||
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,
|
||
});
|
||
// ワークタイプを作成
|
||
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,
|
||
authorUserId,
|
||
worktypeId,
|
||
templateFileId,
|
||
);
|
||
// ワークフロータイピストを作成
|
||
await createWorkflowTypist(source, workflowId, typistUserId);
|
||
const blobParam = makeBlobstorageServiceMockValue();
|
||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||
|
||
// タスクを10件作成, ジョブナンバーは00000001から00000010まで
|
||
for (let i = 1; i <= 10; i++) {
|
||
await createTask(
|
||
source,
|
||
accountId,
|
||
`http://blob/url/file_${i}.zip`,
|
||
`file_${i}.zip`,
|
||
'Uploaded',
|
||
typistUserId,
|
||
authorAuthorId ?? '',
|
||
undefined,
|
||
undefined,
|
||
i.toString().padStart(8, '0'),
|
||
);
|
||
}
|
||
|
||
// 最新のジョブナンバーでjob_numberテーブルを作成
|
||
await createJobNumber(source, accountId, '00000010');
|
||
|
||
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,
|
||
'http://blob/url/file.zip',
|
||
authorAuthorId ?? '',
|
||
'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('00000011');
|
||
// 通知処理が想定通りの引数で呼ばれているか確認
|
||
expect(notificationHubService.notify).toHaveBeenCalledWith(
|
||
makeContext('trackingId', 'requestId'),
|
||
`user_${typistUserId}`,
|
||
{
|
||
authorId: 'AUTHOR_ID',
|
||
filename: 'file',
|
||
id: '2',
|
||
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_id).toEqual(typistUserId);
|
||
});
|
||
|
||
it('タスク作成時に採番されるジョブナンバーが常に最新タスクのジョブナンバー + 1となる(途中のタスクのジョブナンバーが有効でない場合)', async () => {
|
||
if (!source) fail();
|
||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||
const {
|
||
external_id: authorExternalId,
|
||
id: authorUserId,
|
||
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,
|
||
});
|
||
// ワークタイプを作成
|
||
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,
|
||
authorUserId,
|
||
worktypeId,
|
||
templateFileId,
|
||
);
|
||
// ワークフロータイピストを作成
|
||
await createWorkflowTypist(source, workflowId, typistUserId);
|
||
const blobParam = makeBlobstorageServiceMockValue();
|
||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||
|
||
// タスクを10件作成, ジョブナンバーは00000001から00000010まで
|
||
for (let i = 1; i <= 10; i++) {
|
||
await createTask(
|
||
source,
|
||
accountId,
|
||
`http://blob/url/file_${i}.zip`,
|
||
`file_${i}.zip`,
|
||
'01',
|
||
typistUserId,
|
||
authorAuthorId ?? '',
|
||
undefined,
|
||
undefined,
|
||
i.toString().padStart(8, '0'),
|
||
);
|
||
}
|
||
|
||
// ジョブナンバー00000005のタスクを取得
|
||
const middleTask = await getTaskFromJobNumber(source, '00000005');
|
||
|
||
// ジョブナンバー00000005のタスクのステータスとis_job_number_enabledを更新
|
||
await updateTaskStatusAndIsJobNumberEnabled(
|
||
source,
|
||
middleTask?.id ?? 0,
|
||
'Backup',
|
||
false,
|
||
);
|
||
// 最新のジョブナンバーでjob_numberテーブルを作成
|
||
await createJobNumber(source, accountId, '00000010');
|
||
|
||
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,
|
||
'http://blob/url/file.zip',
|
||
authorAuthorId ?? '',
|
||
'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('00000011');
|
||
// 通知処理が想定通りの引数で呼ばれているか確認
|
||
expect(notificationHubService.notify).toHaveBeenCalledWith(
|
||
makeContext('trackingId', 'requestId'),
|
||
`user_${typistUserId}`,
|
||
{
|
||
authorId: 'AUTHOR_ID',
|
||
filename: 'file',
|
||
id: '2',
|
||
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_id).toEqual(typistUserId);
|
||
});
|
||
|
||
it('タスク作成時に採番されるジョブナンバーが常に最新タスクのジョブナンバー + 1となる(最新タスクのジョブナンバーが99999999で有効でない場合)', async () => {
|
||
if (!source) fail();
|
||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||
const {
|
||
external_id: authorExternalId,
|
||
id: authorUserId,
|
||
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,
|
||
});
|
||
// ワークタイプを作成
|
||
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,
|
||
authorUserId,
|
||
worktypeId,
|
||
templateFileId,
|
||
);
|
||
// ワークフロータイピストを作成
|
||
await createWorkflowTypist(source, workflowId, typistUserId);
|
||
const blobParam = makeBlobstorageServiceMockValue();
|
||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||
|
||
// タスクを10件作成, ジョブナンバーは99999989から99999999まで
|
||
for (let i = 99999989; i <= 99999999; i++) {
|
||
await createTask(
|
||
source,
|
||
accountId,
|
||
`http://blob/url/file_${i}.zip`,
|
||
`file_${i}.zip`,
|
||
'01',
|
||
typistUserId,
|
||
authorAuthorId ?? '',
|
||
undefined,
|
||
undefined,
|
||
i.toString().padStart(8, '0'),
|
||
);
|
||
}
|
||
|
||
// 最新ジョブナンバーのタスクを取得
|
||
const latestTask = await getTaskFromJobNumber(source, '99999999');
|
||
|
||
// 最新のタスクのステータスとis_job_number_enabledを更新
|
||
await updateTaskStatusAndIsJobNumberEnabled(
|
||
source,
|
||
latestTask?.id ?? 0,
|
||
'Backup',
|
||
false,
|
||
);
|
||
// 最新のジョブナンバーでjob_numberテーブルを作成
|
||
await createJobNumber(source, accountId, '99999999');
|
||
|
||
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,
|
||
'http://blob/url/file.zip',
|
||
authorAuthorId ?? '',
|
||
'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',
|
||
id: '2',
|
||
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_id).toEqual(typistUserId);
|
||
});
|
||
|
||
it('タスク作成時に採番されるジョブナンバーが常に最新タスクのジョブナンバー + 1となる(最新タスクのジョブナンバーが99999999で有効な場合)', async () => {
|
||
if (!source) fail();
|
||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||
const {
|
||
external_id: authorExternalId,
|
||
id: authorUserId,
|
||
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,
|
||
});
|
||
// ワークタイプを作成
|
||
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,
|
||
authorUserId,
|
||
worktypeId,
|
||
templateFileId,
|
||
);
|
||
// ワークフロータイピストを作成
|
||
await createWorkflowTypist(source, workflowId, typistUserId);
|
||
|
||
// 最新のジョブナンバーでjob_numberテーブルを作成
|
||
await createJobNumber(source, accountId, '99999999');
|
||
|
||
const blobParam = makeBlobstorageServiceMockValue();
|
||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||
|
||
// タスクを10件作成, ジョブナンバーは99999989から99999999まで
|
||
for (let i = 99999989; i <= 99999999; i++) {
|
||
await createTask(
|
||
source,
|
||
accountId,
|
||
`http://blob/url/file_${i}.zip`,
|
||
`file_${i}.zip`,
|
||
'01',
|
||
typistUserId,
|
||
authorAuthorId ?? '',
|
||
undefined,
|
||
undefined,
|
||
i.toString().padStart(8, '0'),
|
||
);
|
||
}
|
||
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,
|
||
'http://blob/url/file.zip',
|
||
authorAuthorId ?? '',
|
||
'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',
|
||
id: '2',
|
||
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_id).toEqual(typistUserId);
|
||
});
|
||
|
||
it('タスク作成時に採番されるジョブナンバーが常に最新タスクのジョブナンバー + 1となる(最新タスクが削除されている場合)', async () => {
|
||
if (!source) fail();
|
||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||
const {
|
||
external_id: authorExternalId,
|
||
id: authorUserId,
|
||
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,
|
||
});
|
||
// ワークタイプを作成
|
||
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,
|
||
authorUserId,
|
||
worktypeId,
|
||
templateFileId,
|
||
);
|
||
// ワークフロータイピストを作成
|
||
await createWorkflowTypist(source, workflowId, typistUserId);
|
||
const blobParam = makeBlobstorageServiceMockValue();
|
||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||
|
||
// タスクを10件作成, ジョブナンバーは00000001から00000010まで
|
||
for (let i = 1; i <= 10; i++) {
|
||
await createTask(
|
||
source,
|
||
accountId,
|
||
`http://blob/url/file_${i}.zip`,
|
||
`file_${i}.zip`,
|
||
'Uploaded',
|
||
typistUserId,
|
||
authorAuthorId ?? '',
|
||
undefined,
|
||
undefined,
|
||
i.toString().padStart(8, '0'),
|
||
);
|
||
}
|
||
|
||
// 最新のジョブナンバーでjob_numberテーブルを作成
|
||
await createJobNumber(source, accountId, '00000010');
|
||
|
||
{
|
||
// 初期データ確認
|
||
const tasks = await getTasks(source, accountId);
|
||
expect(tasks.length).toEqual(10);
|
||
const jobNumber = await getJobNumber(source, accountId);
|
||
expect(jobNumber?.job_number).toEqual('00000010');
|
||
}
|
||
|
||
const module = await makeTestingModuleWithBlobAndNotification(
|
||
source,
|
||
blobParam,
|
||
notificationParam,
|
||
);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
const taskService = module.get<TasksService>(TasksService);
|
||
const notificationHubService = module.get<NotificationhubService>(
|
||
NotificationhubService,
|
||
);
|
||
|
||
// 最新のジョブナンバーのタスクを取得
|
||
const latestTask = await getTaskFromJobNumber(source, '00000010');
|
||
await taskService.deleteTask(
|
||
makeContext('trackingId', 'requestId'),
|
||
authorExternalId,
|
||
latestTask?.audio_file_id ?? 0, // 最新タスクのaudioFileId
|
||
);
|
||
|
||
{
|
||
// タスク削除確認
|
||
const tasks = await getTasks(source, accountId);
|
||
expect(tasks.length).toEqual(9);
|
||
// JobNumberが00000010のタスクが存在しないことを確認
|
||
expect(
|
||
tasks.find((task) => task.job_number === '00000010'),
|
||
).toBeUndefined();
|
||
}
|
||
|
||
const result = await service.uploadFinished(
|
||
makeContext('trackingId', 'requestId'),
|
||
authorExternalId,
|
||
'http://blob/url/file.zip',
|
||
authorAuthorId ?? '',
|
||
'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('00000011');
|
||
// job_numberテーブルが正しく更新されているか確認
|
||
const jobNumber = await getJobNumber(source, accountId);
|
||
expect(jobNumber?.job_number).toEqual('00000011');
|
||
|
||
// 通知処理が想定通りの引数で呼ばれているか確認
|
||
expect(notificationHubService.notify).toHaveBeenCalledWith(
|
||
makeContext('trackingId', 'requestId'),
|
||
`user_${typistUserId}`,
|
||
{
|
||
authorId: 'AUTHOR_ID',
|
||
filename: 'file',
|
||
id: '2',
|
||
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_id).toEqual(typistUserId);
|
||
});
|
||
it('タスク作成時に採番されるジョブナンバーが常に最新タスクのジョブナンバー + 1となる(途中のタスクが削除されている場合)', async () => {
|
||
if (!source) fail();
|
||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||
const {
|
||
external_id: authorExternalId,
|
||
id: authorUserId,
|
||
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,
|
||
});
|
||
// ワークタイプを作成
|
||
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,
|
||
authorUserId,
|
||
worktypeId,
|
||
templateFileId,
|
||
);
|
||
// ワークフロータイピストを作成
|
||
await createWorkflowTypist(source, workflowId, typistUserId);
|
||
const blobParam = makeBlobstorageServiceMockValue();
|
||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||
|
||
// タスクを10件作成, ジョブナンバーは00000001から00000010まで
|
||
for (let i = 1; i <= 10; i++) {
|
||
await createTask(
|
||
source,
|
||
accountId,
|
||
`http://blob/url/file_${i}.zip`,
|
||
`file_${i}.zip`,
|
||
'Uploaded',
|
||
typistUserId,
|
||
authorAuthorId ?? '',
|
||
undefined,
|
||
undefined,
|
||
i.toString().padStart(8, '0'),
|
||
);
|
||
}
|
||
|
||
// 最新のジョブナンバーでjob_numberテーブルを作成
|
||
await createJobNumber(source, accountId, '00000010');
|
||
|
||
{
|
||
// 初期データ確認
|
||
const tasks = await getTasks(source, accountId);
|
||
expect(tasks.length).toEqual(10);
|
||
const jobNumber = await getJobNumber(source, accountId);
|
||
expect(jobNumber?.job_number).toEqual('00000010');
|
||
}
|
||
|
||
const module = await makeTestingModuleWithBlobAndNotification(
|
||
source,
|
||
blobParam,
|
||
notificationParam,
|
||
);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
const taskService = module.get<TasksService>(TasksService);
|
||
const notificationHubService = module.get<NotificationhubService>(
|
||
NotificationhubService,
|
||
);
|
||
|
||
// 途中のジョブナンバーのタスクを取得
|
||
const latestTask = await getTaskFromJobNumber(source, '00000005');
|
||
await taskService.deleteTask(
|
||
makeContext('trackingId', 'requestId'),
|
||
authorExternalId,
|
||
latestTask?.audio_file_id ?? 0, // 最新タスクのaudioFileId
|
||
);
|
||
|
||
{
|
||
// タスク削除確認
|
||
const tasks = await getTasks(source, accountId);
|
||
expect(tasks.length).toEqual(9);
|
||
// JobNumberが00000005のタスクが存在しないことを確認
|
||
expect(
|
||
tasks.find((task) => task.job_number === '00000005'),
|
||
).toBeUndefined();
|
||
}
|
||
|
||
const result = await service.uploadFinished(
|
||
makeContext('trackingId', 'requestId'),
|
||
authorExternalId,
|
||
'http://blob/url/file.zip',
|
||
authorAuthorId ?? '',
|
||
'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('00000011');
|
||
// job_numberテーブルが正しく更新されているか確認
|
||
const jobNumber = await getJobNumber(source, accountId);
|
||
expect(jobNumber?.job_number).toEqual('00000011');
|
||
|
||
// 通知処理が想定通りの引数で呼ばれているか確認
|
||
expect(notificationHubService.notify).toHaveBeenCalledWith(
|
||
makeContext('trackingId', 'requestId'),
|
||
`user_${typistUserId}`,
|
||
{
|
||
authorId: 'AUTHOR_ID',
|
||
filename: 'file',
|
||
id: '2',
|
||
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_id).toEqual(typistUserId);
|
||
});
|
||
it('タスク作成時に採番されるジョブナンバーが常に最新タスクのジョブナンバー + 1となる(最新タスクのジョブナンバーが99999999で削除されている場合)', async () => {
|
||
if (!source) fail();
|
||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||
const {
|
||
external_id: authorExternalId,
|
||
id: authorUserId,
|
||
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,
|
||
});
|
||
// ワークタイプを作成
|
||
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,
|
||
authorUserId,
|
||
worktypeId,
|
||
templateFileId,
|
||
);
|
||
// ワークフロータイピストを作成
|
||
await createWorkflowTypist(source, workflowId, typistUserId);
|
||
const blobParam = makeBlobstorageServiceMockValue();
|
||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||
|
||
// タスクを10件作成, ジョブナンバーは99999989から99999999まで
|
||
for (let i = 99999989; i <= 99999999; i++) {
|
||
await createTask(
|
||
source,
|
||
accountId,
|
||
`http://blob/url/file_${i}.zip`,
|
||
`file_${i}.zip`,
|
||
'Uploaded',
|
||
typistUserId,
|
||
authorAuthorId ?? '',
|
||
undefined,
|
||
undefined,
|
||
i.toString().padStart(8, '0'),
|
||
);
|
||
}
|
||
|
||
// 最新のジョブナンバーでjob_numberテーブルを作成
|
||
await createJobNumber(source, accountId, '99999999');
|
||
|
||
{
|
||
// 初期データ確認
|
||
const tasks = await getTasks(source, accountId);
|
||
expect(tasks.length).toEqual(11);
|
||
const jobNumber = await getJobNumber(source, accountId);
|
||
expect(jobNumber?.job_number).toEqual('99999999');
|
||
}
|
||
|
||
const module = await makeTestingModuleWithBlobAndNotification(
|
||
source,
|
||
blobParam,
|
||
notificationParam,
|
||
);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
const taskService = module.get<TasksService>(TasksService);
|
||
const notificationHubService = module.get<NotificationhubService>(
|
||
NotificationhubService,
|
||
);
|
||
|
||
// 最新のジョブナンバーのタスクを取得
|
||
const latestTask = await getTaskFromJobNumber(source, '99999999');
|
||
await taskService.deleteTask(
|
||
makeContext('trackingId', 'requestId'),
|
||
authorExternalId,
|
||
latestTask?.audio_file_id ?? 0, // 最新タスクのaudioFileId
|
||
);
|
||
|
||
{
|
||
// タスク削除確認
|
||
const tasks = await getTasks(source, accountId);
|
||
expect(tasks.length).toEqual(10);
|
||
// JobNumberが99999999のタスクが存在しないことを確認
|
||
expect(
|
||
tasks.find((task) => task.job_number === '99999999'),
|
||
).toBeUndefined();
|
||
}
|
||
|
||
const result = await service.uploadFinished(
|
||
makeContext('trackingId', 'requestId'),
|
||
authorExternalId,
|
||
'http://blob/url/file.zip',
|
||
authorAuthorId ?? '',
|
||
'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');
|
||
// job_numberテーブルが正しく更新されているか確認
|
||
// 最新タスクのジョブナンバーが99999999の時、新規作成されたタスクのジョブナンバーは00000001になる
|
||
const jobNumber = await getJobNumber(source, accountId);
|
||
expect(jobNumber?.job_number).toEqual('00000001');
|
||
|
||
// 通知処理が想定通りの引数で呼ばれているか確認
|
||
expect(notificationHubService.notify).toHaveBeenCalledWith(
|
||
makeContext('trackingId', 'requestId'),
|
||
`user_${typistUserId}`,
|
||
{
|
||
authorId: 'AUTHOR_ID',
|
||
filename: 'file',
|
||
id: '2',
|
||
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_id).toEqual(typistUserId);
|
||
});
|
||
});
|
||
|
||
describe('音声ファイルダウンロードURL取得', () => {
|
||
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が行われるため注意
|
||
logger: new TestLogger('none'),
|
||
logging: true,
|
||
});
|
||
return await s.initialize();
|
||
})();
|
||
}
|
||
});
|
||
|
||
beforeEach(async () => {
|
||
if (source) {
|
||
await truncateAllTable(source);
|
||
}
|
||
});
|
||
|
||
afterAll(async () => {
|
||
await source?.destroy();
|
||
source = null;
|
||
});
|
||
|
||
it('ダウンロードSASトークンが乗っているURLを取得できる', async () => {
|
||
if (!source) fail();
|
||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||
const {
|
||
external_id: externalId,
|
||
id: userId,
|
||
author_id: authorId,
|
||
} = await makeTestUser(source, {
|
||
account_id: accountId,
|
||
external_id: 'author-user-external-id',
|
||
role: 'author',
|
||
author_id: 'AUTHOR_ID',
|
||
});
|
||
const url = `https://saodmsusdev.blob.core.windows.net/account-${accountId}/${userId}`;
|
||
|
||
const { audioFileId } = await createTask(
|
||
source,
|
||
accountId,
|
||
url,
|
||
'test.zip',
|
||
'InProgress',
|
||
undefined,
|
||
authorId ?? '',
|
||
);
|
||
|
||
const blobParam = makeBlobstorageServiceMockValue();
|
||
blobParam.publishDownloadSas = `${url}?sas-token`;
|
||
blobParam.fileExists = true;
|
||
|
||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||
const module = await makeTestingModuleWithBlobAndNotification(
|
||
source,
|
||
blobParam,
|
||
notificationParam,
|
||
);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
|
||
expect(
|
||
await service.publishAudioFileDownloadSas(
|
||
makeContext('trackingId', 'requestId'),
|
||
externalId,
|
||
audioFileId,
|
||
),
|
||
).toEqual(`${url}?sas-token`);
|
||
});
|
||
it('Typistの場合、タスクのステータスが[Inprogress,Pending]以外でエラー', async () => {
|
||
if (!source) fail();
|
||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||
const { external_id: externalId, id: userId } = await makeTestUser(source, {
|
||
account_id: accountId,
|
||
external_id: 'typist-user-external-id',
|
||
role: 'typist',
|
||
});
|
||
const { id: authorUserId } = await makeTestUser(source, {
|
||
account_id: accountId,
|
||
external_id: 'author-user-external-id',
|
||
role: 'author',
|
||
author_id: 'AUTHOR_ID',
|
||
});
|
||
|
||
const url = `https://saodmsusdev.blob.core.windows.net/account-${accountId}/${authorUserId}`;
|
||
|
||
const { audioFileId } = await createTask(
|
||
source,
|
||
accountId,
|
||
url,
|
||
'test.zip',
|
||
'Finished',
|
||
userId,
|
||
);
|
||
|
||
const blobParam = makeBlobstorageServiceMockValue();
|
||
blobParam.publishDownloadSas = `${url}?sas-token`;
|
||
blobParam.fileExists = true;
|
||
|
||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||
const module = await makeTestingModuleWithBlobAndNotification(
|
||
source,
|
||
blobParam,
|
||
notificationParam,
|
||
);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
|
||
await expect(
|
||
service.publishAudioFileDownloadSas(
|
||
makeContext('trackingId', 'requestId'),
|
||
externalId,
|
||
audioFileId,
|
||
),
|
||
).rejects.toEqual(
|
||
new HttpException(makeErrorResponse('E010603'), HttpStatus.BAD_REQUEST),
|
||
);
|
||
});
|
||
|
||
it('Typistの場合、自身が担当するタスクでない場合エラー', async () => {
|
||
if (!source) fail();
|
||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||
const { external_id: externalId } = await makeTestUser(source, {
|
||
account_id: accountId,
|
||
external_id: 'typist-user-external-id',
|
||
role: 'typist',
|
||
});
|
||
const { id: otherId } = await makeTestUser(source, {
|
||
account_id: accountId,
|
||
external_id: 'other-typist-user-external-id',
|
||
role: 'typist',
|
||
});
|
||
const { id: authorUserId } = await makeTestUser(source, {
|
||
account_id: accountId,
|
||
external_id: 'author-user-external-id',
|
||
role: 'author',
|
||
author_id: 'AUTHOR_ID',
|
||
});
|
||
const url = `https://saodmsusdev.blob.core.windows.net/account-${accountId}/${authorUserId}`;
|
||
|
||
const { audioFileId } = await createTask(
|
||
source,
|
||
accountId,
|
||
url,
|
||
'test.zip',
|
||
'InProgress',
|
||
otherId,
|
||
);
|
||
|
||
const blobParam = makeBlobstorageServiceMockValue();
|
||
blobParam.publishDownloadSas = `${url}?sas-token`;
|
||
blobParam.fileExists = true;
|
||
|
||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||
const module = await makeTestingModuleWithBlobAndNotification(
|
||
source,
|
||
blobParam,
|
||
notificationParam,
|
||
);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
|
||
await expect(
|
||
service.publishTemplateFileDownloadSas(
|
||
makeContext('tracking', 'requestId'),
|
||
externalId,
|
||
audioFileId,
|
||
),
|
||
).rejects.toEqual(
|
||
new HttpException(makeErrorResponse('E010603'), HttpStatus.BAD_REQUEST),
|
||
);
|
||
});
|
||
|
||
it('Authorの場合、自身が登録したタスクでない場合エラー', async () => {
|
||
if (!source) fail();
|
||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||
const { external_id: externalId, id: userId } = await makeTestUser(source, {
|
||
account_id: accountId,
|
||
external_id: 'author-user-external-id',
|
||
role: 'author',
|
||
author_id: 'AUTHOR_ID',
|
||
});
|
||
const url = `https://saodmsusdev.blob.core.windows.net/account-${accountId}/${userId}`;
|
||
|
||
const { audioFileId } = await createTask(
|
||
source,
|
||
accountId,
|
||
url,
|
||
'test.zip',
|
||
'InProgress',
|
||
undefined,
|
||
'OTHOR_ID',
|
||
);
|
||
|
||
const blobParam = makeBlobstorageServiceMockValue();
|
||
blobParam.publishDownloadSas = `${url}?sas-token`;
|
||
blobParam.fileExists = true;
|
||
|
||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||
const module = await makeTestingModuleWithBlobAndNotification(
|
||
source,
|
||
blobParam,
|
||
notificationParam,
|
||
);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
|
||
await expect(
|
||
service.publishAudioFileDownloadSas(
|
||
makeContext('trackingId', 'requestId'),
|
||
externalId,
|
||
audioFileId,
|
||
),
|
||
).rejects.toEqual(
|
||
new HttpException(makeErrorResponse('E010603'), HttpStatus.BAD_REQUEST),
|
||
);
|
||
});
|
||
|
||
it('Taskが存在しない場合はエラーとなる', async () => {
|
||
if (!source) fail();
|
||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||
const { external_id: externalId } = await makeTestUser(source, {
|
||
account_id: accountId,
|
||
external_id: 'author-user-external-id',
|
||
role: 'author',
|
||
author_id: 'AUTHOR_ID',
|
||
});
|
||
|
||
const blobParam = makeBlobstorageServiceMockValue();
|
||
|
||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||
const module = await makeTestingModuleWithBlobAndNotification(
|
||
source,
|
||
blobParam,
|
||
notificationParam,
|
||
);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
|
||
await expect(
|
||
service.publishAudioFileDownloadSas(
|
||
makeContext('trackingId', 'requestId'),
|
||
externalId,
|
||
1,
|
||
),
|
||
).rejects.toEqual(
|
||
new HttpException(makeErrorResponse('E010603'), HttpStatus.BAD_REQUEST),
|
||
);
|
||
});
|
||
|
||
it('blobストレージにファイルが存在しない場合はエラーとなる', async () => {
|
||
if (!source) fail();
|
||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||
const {
|
||
external_id: externalId,
|
||
id: userId,
|
||
author_id: authorId,
|
||
} = await makeTestUser(source, {
|
||
account_id: accountId,
|
||
external_id: 'author-user-external-id',
|
||
role: 'author',
|
||
author_id: 'AUTHOR_ID',
|
||
});
|
||
const url = `https://saodmsusdev.blob.core.windows.net/account-${accountId}/${userId}`;
|
||
|
||
const { audioFileId } = await createTask(
|
||
source,
|
||
accountId,
|
||
url,
|
||
'test.zip',
|
||
'InProgress',
|
||
undefined,
|
||
authorId ?? '',
|
||
);
|
||
|
||
const blobParam = makeBlobstorageServiceMockValue();
|
||
blobParam.publishDownloadSas = `${url}?sas-token`;
|
||
blobParam.fileExists = false;
|
||
|
||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||
const module = await makeTestingModuleWithBlobAndNotification(
|
||
source,
|
||
blobParam,
|
||
notificationParam,
|
||
);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
|
||
await expect(
|
||
service.publishAudioFileDownloadSas(
|
||
makeContext('trackingId', 'requestId'),
|
||
externalId,
|
||
audioFileId,
|
||
),
|
||
).rejects.toEqual(
|
||
new HttpException(makeErrorResponse('E010701'), HttpStatus.BAD_REQUEST),
|
||
);
|
||
});
|
||
});
|
||
|
||
describe('テンプレートファイルダウンロードURL取得', () => {
|
||
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が行われるため注意
|
||
logger: new TestLogger('none'),
|
||
logging: true,
|
||
});
|
||
return await s.initialize();
|
||
})();
|
||
}
|
||
});
|
||
|
||
beforeEach(async () => {
|
||
if (source) {
|
||
await truncateAllTable(source);
|
||
}
|
||
});
|
||
|
||
afterAll(async () => {
|
||
await source?.destroy();
|
||
source = null;
|
||
});
|
||
|
||
it('ダウンロードSASトークンが乗っているURLを取得できる', async () => {
|
||
if (!source) fail();
|
||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||
const { external_id: externalId, id: userId } = await makeTestUser(source, {
|
||
account_id: accountId,
|
||
external_id: 'typist-user-external-id',
|
||
role: USER_ROLES.TYPIST,
|
||
});
|
||
const url = `https://saodmsusdev.blob.core.windows.net/account-${accountId}/Templates`;
|
||
|
||
const { audioFileId } = await createTask(
|
||
source,
|
||
accountId,
|
||
url,
|
||
'test.zip',
|
||
TASK_STATUS.IN_PROGRESS,
|
||
userId,
|
||
'AUTHOR_ID',
|
||
);
|
||
|
||
const blobParam = makeBlobstorageServiceMockValue();
|
||
blobParam.publishDownloadSas = `${url}?sas-token`;
|
||
blobParam.fileExists = true;
|
||
|
||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||
const module = await makeTestingModuleWithBlobAndNotification(
|
||
source,
|
||
blobParam,
|
||
notificationParam,
|
||
);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
|
||
const resultUrl = await service.publishTemplateFileDownloadSas(
|
||
makeContext('tracking', 'requestId'),
|
||
externalId,
|
||
audioFileId,
|
||
);
|
||
expect(resultUrl).toBe(`${url}?sas-token`);
|
||
});
|
||
|
||
it('タスクのステータスが[Inprogress,Pending]以外でエラー', async () => {
|
||
if (!source) fail();
|
||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||
const { external_id: externalId, id: userId } = await makeTestUser(source, {
|
||
account_id: accountId,
|
||
external_id: 'typist-user-external-id',
|
||
role: USER_ROLES.TYPIST,
|
||
});
|
||
const url = `https://saodmsusdev.blob.core.windows.net/account-${accountId}/Templates`;
|
||
|
||
const { audioFileId } = await createTask(
|
||
source,
|
||
accountId,
|
||
url,
|
||
'test.zip',
|
||
TASK_STATUS.FINISHED,
|
||
userId,
|
||
);
|
||
|
||
const blobParam = makeBlobstorageServiceMockValue();
|
||
blobParam.publishDownloadSas = `${url}?sas-token`;
|
||
blobParam.fileExists = true;
|
||
|
||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||
const module = await makeTestingModuleWithBlobAndNotification(
|
||
source,
|
||
blobParam,
|
||
notificationParam,
|
||
);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
|
||
try {
|
||
await service.publishTemplateFileDownloadSas(
|
||
makeContext('tracking', 'requestId'),
|
||
externalId,
|
||
audioFileId,
|
||
);
|
||
fail();
|
||
} catch (e) {
|
||
if (e instanceof HttpException) {
|
||
expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST);
|
||
expect(e.getResponse()).toEqual(makeErrorResponse('E010603'));
|
||
} else {
|
||
fail();
|
||
}
|
||
}
|
||
});
|
||
|
||
it('自身が担当するタスクでない場合エラー', async () => {
|
||
if (!source) fail();
|
||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||
const { external_id: externalId } = await makeTestUser(source, {
|
||
account_id: accountId,
|
||
external_id: 'typist-user-external-id',
|
||
role: USER_ROLES.TYPIST,
|
||
});
|
||
const { id: otherId } = await makeTestUser(source, {
|
||
account_id: accountId,
|
||
external_id: 'other-typist-user-external-id',
|
||
role: USER_ROLES.TYPIST,
|
||
});
|
||
const url = `https://saodmsusdev.blob.core.windows.net/account-${accountId}/Templates`;
|
||
|
||
const { audioFileId } = await createTask(
|
||
source,
|
||
accountId,
|
||
url,
|
||
'test.zip',
|
||
TASK_STATUS.IN_PROGRESS,
|
||
otherId,
|
||
);
|
||
|
||
const blobParam = makeBlobstorageServiceMockValue();
|
||
blobParam.publishDownloadSas = `${url}?sas-token`;
|
||
blobParam.fileExists = true;
|
||
|
||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||
const module = await makeTestingModuleWithBlobAndNotification(
|
||
source,
|
||
blobParam,
|
||
notificationParam,
|
||
);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
|
||
try {
|
||
await service.publishTemplateFileDownloadSas(
|
||
makeContext('tracking', 'requestId'),
|
||
externalId,
|
||
audioFileId,
|
||
);
|
||
fail();
|
||
} catch (e) {
|
||
if (e instanceof HttpException) {
|
||
expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST);
|
||
expect(e.getResponse()).toEqual(makeErrorResponse('E010603'));
|
||
} else {
|
||
fail();
|
||
}
|
||
}
|
||
});
|
||
|
||
it('Taskが存在しない場合はエラーとなる', async () => {
|
||
if (!source) fail();
|
||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||
const { external_id: externalId } = await makeTestUser(source, {
|
||
account_id: accountId,
|
||
external_id: 'typist-user-external-id',
|
||
role: USER_ROLES.TYPIST,
|
||
});
|
||
|
||
const blobParam = makeBlobstorageServiceMockValue();
|
||
|
||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||
const module = await makeTestingModuleWithBlobAndNotification(
|
||
source,
|
||
blobParam,
|
||
notificationParam,
|
||
);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
|
||
try {
|
||
await service.publishTemplateFileDownloadSas(
|
||
makeContext('tracking', 'requestId'),
|
||
externalId,
|
||
1,
|
||
);
|
||
fail();
|
||
} catch (e) {
|
||
if (e instanceof HttpException) {
|
||
expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST);
|
||
expect(e.getResponse()).toEqual(makeErrorResponse('E010603'));
|
||
} else {
|
||
fail();
|
||
}
|
||
}
|
||
});
|
||
|
||
it('blobストレージにファイルが存在しない場合はエラーとなる', async () => {
|
||
if (!source) fail();
|
||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||
const { external_id: externalId, id: userId } = await makeTestUser(source, {
|
||
account_id: accountId,
|
||
external_id: 'typist-user-external-id',
|
||
role: USER_ROLES.TYPIST,
|
||
});
|
||
const url = `https://saodmsusdev.blob.core.windows.net/account-${accountId}/Templates`;
|
||
|
||
const { audioFileId } = await createTask(
|
||
source,
|
||
accountId,
|
||
url,
|
||
'test.zip',
|
||
TASK_STATUS.IN_PROGRESS,
|
||
userId,
|
||
'AUTHOR_ID',
|
||
);
|
||
|
||
const blobParam = makeBlobstorageServiceMockValue();
|
||
blobParam.publishDownloadSas = `${url}?sas-token`;
|
||
blobParam.fileExists = false;
|
||
|
||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||
const module = await makeTestingModuleWithBlobAndNotification(
|
||
source,
|
||
blobParam,
|
||
notificationParam,
|
||
);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
|
||
try {
|
||
await service.publishTemplateFileDownloadSas(
|
||
makeContext('tracking', 'requestId'),
|
||
externalId,
|
||
audioFileId,
|
||
);
|
||
fail();
|
||
} catch (e) {
|
||
if (e instanceof HttpException) {
|
||
expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST);
|
||
expect(e.getResponse()).toEqual(makeErrorResponse('E010701'));
|
||
} else {
|
||
fail();
|
||
}
|
||
}
|
||
});
|
||
});
|
||
|
||
describe('publishTemplateFileUploadSas', () => {
|
||
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が行われるため注意
|
||
logger: new TestLogger('none'),
|
||
logging: true,
|
||
});
|
||
return await s.initialize();
|
||
})();
|
||
}
|
||
});
|
||
|
||
beforeEach(async () => {
|
||
if (source) {
|
||
await truncateAllTable(source);
|
||
}
|
||
});
|
||
|
||
afterAll(async () => {
|
||
await source?.destroy();
|
||
source = null;
|
||
});
|
||
|
||
it('テンプレートファイルアップロードSASトークンが乗っているURLを取得できる', async () => {
|
||
if (!source) fail();
|
||
const module = await makeTestingModule(source);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
// 第五階層のアカウント作成
|
||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||
|
||
const context = makeContext(admin.external_id, 'requestId');
|
||
const baseUrl = `https://saodmsusdev.blob.core.windows.net/account-${account.id}/Templates`;
|
||
|
||
//SASトークンを返却する
|
||
overrideBlobstorageService(service, {
|
||
containerExists: async () => true,
|
||
publishTemplateUploadSas: async () => `${baseUrl}?sas-token`,
|
||
});
|
||
|
||
const url = await service.publishTemplateFileUploadSas(
|
||
context,
|
||
admin.external_id,
|
||
);
|
||
|
||
expect(url).toBe(`${baseUrl}?sas-token`);
|
||
});
|
||
|
||
it('blobストレージにコンテナが存在しない場合はエラーとなる', async () => {
|
||
if (!source) fail();
|
||
const module = await makeTestingModule(source);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
// 第五階層のアカウント作成
|
||
const { admin } = await makeTestAccount(source, { tier: 5 });
|
||
|
||
const context = makeContext(admin.external_id, 'requestId');
|
||
|
||
//Blobコンテナ存在チェックに失敗するようにする
|
||
overrideBlobstorageService(service, {
|
||
containerExists: async () => false,
|
||
publishTemplateUploadSas: async () => '',
|
||
});
|
||
|
||
try {
|
||
await service.publishTemplateFileUploadSas(context, admin.external_id);
|
||
} catch (e) {
|
||
if (e instanceof HttpException) {
|
||
expect(e.getStatus()).toBe(HttpStatus.INTERNAL_SERVER_ERROR);
|
||
expect(e.getResponse()).toEqual(makeErrorResponse('E009999'));
|
||
} else {
|
||
fail();
|
||
}
|
||
}
|
||
});
|
||
|
||
it('SASトークンの取得に失敗した場合はエラーとなる', async () => {
|
||
if (!source) fail();
|
||
const module = await makeTestingModule(source);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
// 第五階層のアカウント作成
|
||
const { admin } = await makeTestAccount(source, { tier: 5 });
|
||
|
||
const context = makeContext(admin.external_id, 'requestId');
|
||
|
||
//BlobのSASトークン生成に失敗するようにする
|
||
overrideBlobstorageService(service, {
|
||
containerExists: async () => true,
|
||
publishTemplateUploadSas: async () => {
|
||
throw new Error('blob failed');
|
||
},
|
||
});
|
||
|
||
try {
|
||
await service.publishTemplateFileUploadSas(context, admin.external_id);
|
||
} catch (e) {
|
||
if (e instanceof HttpException) {
|
||
expect(e.getStatus()).toBe(HttpStatus.INTERNAL_SERVER_ERROR);
|
||
expect(e.getResponse()).toEqual(makeErrorResponse('E009999'));
|
||
} else {
|
||
fail();
|
||
}
|
||
}
|
||
});
|
||
});
|
||
|
||
describe('templateUploadFinished', () => {
|
||
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が行われるため注意
|
||
logger: new TestLogger('none'),
|
||
logging: true,
|
||
});
|
||
return await s.initialize();
|
||
})();
|
||
}
|
||
});
|
||
|
||
beforeEach(async () => {
|
||
if (source) {
|
||
await truncateAllTable(source);
|
||
}
|
||
});
|
||
|
||
afterAll(async () => {
|
||
await source?.destroy();
|
||
source = null;
|
||
});
|
||
|
||
it('アップロード完了後のテンプレートファイル情報をDBに保存できる(新規追加)', async () => {
|
||
if (!source) fail();
|
||
const module = await makeTestingModule(source);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
// 第五階層のアカウント作成
|
||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||
const context = makeContext(admin.external_id, 'requestId');
|
||
|
||
const fileName = 'test.docs';
|
||
const url = `https://blob.url/account-${account.id}/Templates`;
|
||
|
||
// 事前にDBを確認
|
||
{
|
||
const templates = await getTemplateFiles(source, account.id);
|
||
expect(templates.length).toBe(0);
|
||
}
|
||
|
||
await service.templateUploadFinished(
|
||
context,
|
||
admin.external_id,
|
||
url,
|
||
fileName,
|
||
);
|
||
|
||
//実行結果を確認
|
||
{
|
||
const templates = await getTemplateFiles(source, account.id);
|
||
expect(templates.length).toBe(1);
|
||
expect(templates[0].file_name).toBe(fileName);
|
||
expect(templates[0].url).toBe(url);
|
||
}
|
||
});
|
||
|
||
it('アップロード完了後のテンプレートファイル情報をDBに保存できる(更新)', async () => {
|
||
if (!source) fail();
|
||
const module = await makeTestingModule(source);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
// 第五階層のアカウント作成
|
||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||
const context = makeContext(admin.external_id, 'requestId');
|
||
|
||
const fileName = 'test.docs';
|
||
const url = `https://blob.url/account-${account.id}/Templates`;
|
||
|
||
await createTemplateFile(source, account.id, fileName, url);
|
||
|
||
// 事前にDBを確認
|
||
{
|
||
const templates = await getTemplateFiles(source, account.id);
|
||
expect(templates.length).toBe(1);
|
||
expect(templates[0].file_name).toBe(fileName);
|
||
expect(templates[0].url).toBe(url);
|
||
}
|
||
|
||
const updateUrl = `https://blob.update.url/account-${account.id}/Templates`;
|
||
|
||
await service.templateUploadFinished(
|
||
context,
|
||
admin.external_id,
|
||
updateUrl,
|
||
fileName,
|
||
);
|
||
|
||
//実行結果を確認
|
||
{
|
||
const templates = await getTemplateFiles(source, account.id);
|
||
expect(templates.length).toBe(1);
|
||
expect(templates[0].file_name).toBe(fileName);
|
||
expect(templates[0].url).toBe(updateUrl);
|
||
}
|
||
});
|
||
|
||
it('DBへの保存に失敗した場合はエラーとなる', async () => {
|
||
if (!source) fail();
|
||
const module = await makeTestingModule(source);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
// 第五階層のアカウント作成
|
||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||
const context = makeContext(admin.external_id, 'requestId');
|
||
|
||
const fileName = 'test.docs';
|
||
const url = `https://blob.url/account-${account.id}/Templates`;
|
||
|
||
// 事前にDBを確認
|
||
{
|
||
const templates = await getTemplateFiles(source, account.id);
|
||
expect(templates.length).toBe(0);
|
||
}
|
||
|
||
//DBアクセスに失敗するようにする
|
||
const templatesService = module.get<TemplateFilesRepositoryService>(
|
||
TemplateFilesRepositoryService,
|
||
);
|
||
templatesService.upsertTemplateFile = jest
|
||
.fn()
|
||
.mockRejectedValue('DB failed');
|
||
|
||
try {
|
||
await service.templateUploadFinished(
|
||
context,
|
||
admin.external_id,
|
||
url,
|
||
fileName,
|
||
);
|
||
} catch (e) {
|
||
if (e instanceof HttpException) {
|
||
expect(e.getStatus()).toEqual(HttpStatus.INTERNAL_SERVER_ERROR);
|
||
expect(e.getResponse()).toEqual(makeErrorResponse('E009999'));
|
||
} else {
|
||
fail();
|
||
}
|
||
}
|
||
});
|
||
});
|
||
|
||
const optionItemList = [
|
||
{
|
||
optionItemLabel: 'label_01',
|
||
optionItemValue: 'value_01',
|
||
},
|
||
{
|
||
optionItemLabel: 'label_02',
|
||
optionItemValue: 'value_02',
|
||
},
|
||
{
|
||
optionItemLabel: 'label_03',
|
||
optionItemValue: 'value_03',
|
||
},
|
||
{
|
||
optionItemLabel: 'label_04',
|
||
optionItemValue: 'value_04',
|
||
},
|
||
{
|
||
optionItemLabel: 'label_05',
|
||
optionItemValue: 'value_05',
|
||
},
|
||
{
|
||
optionItemLabel: 'label_06',
|
||
optionItemValue: 'value_06',
|
||
},
|
||
{
|
||
optionItemLabel: 'label_07',
|
||
optionItemValue: 'value_07',
|
||
},
|
||
{
|
||
optionItemLabel: 'label_08',
|
||
optionItemValue: 'value_08',
|
||
},
|
||
{
|
||
optionItemLabel: 'label_09',
|
||
optionItemValue: 'value_09',
|
||
},
|
||
{
|
||
optionItemLabel: 'label_10',
|
||
optionItemValue: 'value_10',
|
||
},
|
||
];
|
||
|
||
describe('fileRename', () => {
|
||
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が行われるため注意
|
||
logger: new TestLogger('none'),
|
||
logging: true,
|
||
});
|
||
return await s.initialize();
|
||
})();
|
||
}
|
||
});
|
||
|
||
beforeEach(async () => {
|
||
if (source) {
|
||
await truncateAllTable(source);
|
||
}
|
||
});
|
||
|
||
afterAll(async () => {
|
||
await source?.destroy();
|
||
source = null;
|
||
});
|
||
|
||
it('ファイル名を変更できる(管理者)', async () => {
|
||
if (!source) fail();
|
||
const module = await makeTestingModule(source);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
// 第五階層のアカウント作成
|
||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||
const context = makeContext(admin.external_id, 'requestId');
|
||
|
||
const oldFileName = 'old.zip';
|
||
|
||
const task = await createTask(
|
||
source,
|
||
account.id,
|
||
'https://blob.url/account-1',
|
||
oldFileName,
|
||
TASK_STATUS.UPLOADED,
|
||
);
|
||
|
||
// 事前にDBを確認
|
||
{
|
||
const audioFile = await getAudioFile(source, task.audioFileId);
|
||
expect(audioFile?.file_name).toBe(oldFileName);
|
||
expect(audioFile?.raw_file_name).toBe(oldFileName);
|
||
}
|
||
|
||
const newFileName = 'new.zip';
|
||
|
||
await service.fileRename(
|
||
context,
|
||
admin.external_id,
|
||
task.audioFileId,
|
||
newFileName,
|
||
);
|
||
|
||
//実行結果を確認
|
||
{
|
||
const audioFile = await getAudioFile(source, task.audioFileId);
|
||
expect(audioFile?.file_name).toBe(newFileName);
|
||
expect(audioFile?.raw_file_name).toBe(oldFileName);
|
||
}
|
||
});
|
||
it('ファイル名を変更できる(Author)', async () => {
|
||
if (!source) fail();
|
||
const module = await makeTestingModule(source);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
// 第五階層のアカウント作成
|
||
const { account } = await makeTestAccount(source, { tier: 5 });
|
||
const { external_id: authorExternalId } = await makeTestUser(source, {
|
||
account_id: account.id,
|
||
external_id: 'author-user-external-id',
|
||
role: USER_ROLES.AUTHOR,
|
||
author_id: 'AUTHOR_ID',
|
||
});
|
||
|
||
const context = makeContext(authorExternalId, 'requestId');
|
||
|
||
const oldFileName = 'old.zip';
|
||
|
||
const task = await createTask(
|
||
source,
|
||
account.id,
|
||
'https://blob.url/account-1',
|
||
oldFileName,
|
||
TASK_STATUS.UPLOADED,
|
||
undefined,
|
||
'AUTHOR_ID',
|
||
);
|
||
|
||
// 事前にDBを確認
|
||
{
|
||
const audioFile = await getAudioFile(source, task.audioFileId);
|
||
expect(audioFile?.file_name).toBe(oldFileName);
|
||
expect(audioFile?.raw_file_name).toBe(oldFileName);
|
||
}
|
||
|
||
const newFileName = 'new.zip';
|
||
|
||
await service.fileRename(
|
||
context,
|
||
authorExternalId,
|
||
task.audioFileId,
|
||
newFileName,
|
||
);
|
||
|
||
//実行結果を確認
|
||
{
|
||
const audioFile = await getAudioFile(source, task.audioFileId);
|
||
expect(audioFile?.file_name).toBe(newFileName);
|
||
expect(audioFile?.raw_file_name).toBe(oldFileName);
|
||
}
|
||
});
|
||
it('ファイル名を変更できる(Typist)', async () => {
|
||
if (!source) fail();
|
||
const module = await makeTestingModule(source);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
// 第五階層のアカウント作成
|
||
const { account } = await makeTestAccount(source, { tier: 5 });
|
||
const { external_id: typistExternalId, id: typistId } = await makeTestUser(
|
||
source,
|
||
{
|
||
account_id: account.id,
|
||
external_id: 'typist-user-external-id',
|
||
role: USER_ROLES.TYPIST,
|
||
},
|
||
);
|
||
|
||
const context = makeContext(typistExternalId, 'requestId');
|
||
|
||
const oldFileName = 'old.zip';
|
||
|
||
const task = await createTask(
|
||
source,
|
||
account.id,
|
||
'https://blob.url/account-1',
|
||
oldFileName,
|
||
TASK_STATUS.UPLOADED,
|
||
);
|
||
|
||
await createCheckoutPermissions(source, task.taskId, typistId);
|
||
|
||
// 事前にDBを確認
|
||
{
|
||
const audioFile = await getAudioFile(source, task.audioFileId);
|
||
expect(audioFile?.file_name).toBe(oldFileName);
|
||
expect(audioFile?.raw_file_name).toBe(oldFileName);
|
||
}
|
||
|
||
const newFileName = 'new.zip';
|
||
|
||
await service.fileRename(
|
||
context,
|
||
typistExternalId,
|
||
task.audioFileId,
|
||
newFileName,
|
||
);
|
||
|
||
//実行結果を確認
|
||
{
|
||
const audioFile = await getAudioFile(source, task.audioFileId);
|
||
expect(audioFile?.file_name).toBe(newFileName);
|
||
expect(audioFile?.raw_file_name).toBe(oldFileName);
|
||
}
|
||
});
|
||
it('ユーザーが管理者でなくRoleがNoneの場合、エラーとなること', async () => {
|
||
if (!source) fail();
|
||
const module = await makeTestingModule(source);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
// 第五階層のアカウント作成
|
||
const { account } = await makeTestAccount(source, { tier: 5 });
|
||
const { external_id: noneExternalId } = await makeTestUser(source, {
|
||
account_id: account.id,
|
||
external_id: 'none-user-external-id',
|
||
role: USER_ROLES.NONE,
|
||
});
|
||
|
||
const context = makeContext(noneExternalId, 'requestId');
|
||
|
||
const oldFileName = 'old.zip';
|
||
|
||
const task = await createTask(
|
||
source,
|
||
account.id,
|
||
'https://blob.url/account-1',
|
||
oldFileName,
|
||
TASK_STATUS.UPLOADED,
|
||
);
|
||
|
||
// 事前にDBを確認
|
||
{
|
||
const audioFile = await getAudioFile(source, task.audioFileId);
|
||
expect(audioFile?.file_name).toBe(oldFileName);
|
||
expect(audioFile?.raw_file_name).toBe(oldFileName);
|
||
}
|
||
|
||
const newFileName = 'new.zip';
|
||
|
||
try {
|
||
await service.fileRename(
|
||
context,
|
||
noneExternalId,
|
||
task.audioFileId,
|
||
newFileName,
|
||
);
|
||
fail();
|
||
} catch (e) {
|
||
if (e instanceof HttpException) {
|
||
expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST);
|
||
expect(e.getResponse()).toEqual(makeErrorResponse('E021001'));
|
||
} else {
|
||
fail();
|
||
}
|
||
}
|
||
});
|
||
it('Authorがファイル名変更をするときユーザーのAuthorIDとタスクのAuthorIDが異なる場合、エラーとなること', async () => {
|
||
if (!source) fail();
|
||
const module = await makeTestingModule(source);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
// 第五階層のアカウント作成
|
||
const { account } = await makeTestAccount(source, { tier: 5 });
|
||
const { external_id: authorExternalId } = await makeTestUser(source, {
|
||
account_id: account.id,
|
||
external_id: 'author-user-external-id',
|
||
role: USER_ROLES.AUTHOR,
|
||
author_id: 'AUTHOR_ID',
|
||
});
|
||
|
||
const context = makeContext(authorExternalId, 'requestId');
|
||
|
||
const oldFileName = 'old.zip';
|
||
|
||
const task = await createTask(
|
||
source,
|
||
account.id,
|
||
'https://blob.url/account-1',
|
||
oldFileName,
|
||
TASK_STATUS.UPLOADED,
|
||
undefined,
|
||
'AUTHOR_ID_XXX',
|
||
);
|
||
|
||
// 事前にDBを確認
|
||
{
|
||
const audioFile = await getAudioFile(source, task.audioFileId);
|
||
expect(audioFile?.file_name).toBe(oldFileName);
|
||
expect(audioFile?.raw_file_name).toBe(oldFileName);
|
||
}
|
||
|
||
const newFileName = 'new.zip';
|
||
|
||
try {
|
||
await service.fileRename(
|
||
context,
|
||
authorExternalId,
|
||
task.audioFileId,
|
||
newFileName,
|
||
);
|
||
fail();
|
||
} catch (e) {
|
||
if (e instanceof HttpException) {
|
||
expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST);
|
||
expect(e.getResponse()).toEqual(makeErrorResponse('E021001'));
|
||
} else {
|
||
fail();
|
||
}
|
||
}
|
||
});
|
||
it('Typistがファイル名変更をするときユーザーがタスクのチェックアウト候補でない場合、エラーとなること', async () => {
|
||
if (!source) fail();
|
||
const module = await makeTestingModule(source);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
// 第五階層のアカウント作成
|
||
const { account } = await makeTestAccount(source, { tier: 5 });
|
||
const { external_id: typistExternalId } = await makeTestUser(source, {
|
||
account_id: account.id,
|
||
external_id: 'typist-user-external-id',
|
||
role: USER_ROLES.TYPIST,
|
||
});
|
||
|
||
const context = makeContext(typistExternalId, 'requestId');
|
||
|
||
const oldFileName = 'old.zip';
|
||
|
||
const task = await createTask(
|
||
source,
|
||
account.id,
|
||
'https://blob.url/account-1',
|
||
oldFileName,
|
||
TASK_STATUS.UPLOADED,
|
||
);
|
||
|
||
// 事前にDBを確認
|
||
{
|
||
const audioFile = await getAudioFile(source, task.audioFileId);
|
||
expect(audioFile?.file_name).toBe(oldFileName);
|
||
expect(audioFile?.raw_file_name).toBe(oldFileName);
|
||
}
|
||
|
||
const newFileName = 'new.zip';
|
||
|
||
try {
|
||
await service.fileRename(
|
||
context,
|
||
typistExternalId,
|
||
task.audioFileId,
|
||
newFileName,
|
||
);
|
||
fail();
|
||
} catch (e) {
|
||
if (e instanceof HttpException) {
|
||
expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST);
|
||
expect(e.getResponse()).toEqual(makeErrorResponse('E021001'));
|
||
} else {
|
||
fail();
|
||
}
|
||
}
|
||
});
|
||
it('変更するファイル名がすでに存在する場合、エラーとなること', async () => {
|
||
if (!source) fail();
|
||
const module = await makeTestingModule(source);
|
||
if (!module) fail();
|
||
const service = module.get<FilesService>(FilesService);
|
||
// 第五階層のアカウント作成
|
||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||
const context = makeContext(admin.external_id, 'requestId');
|
||
|
||
const oldFileName = 'old.zip';
|
||
|
||
const task = await createTask(
|
||
source,
|
||
account.id,
|
||
'https://blob.url/account-1',
|
||
oldFileName,
|
||
TASK_STATUS.UPLOADED,
|
||
undefined,
|
||
undefined,
|
||
undefined,
|
||
undefined,
|
||
'00000001',
|
||
);
|
||
|
||
const alreadyExistFileName = 'already.zip';
|
||
const alreadyExistTask = await createTask(
|
||
source,
|
||
account.id,
|
||
'https://blob.url/account-1',
|
||
alreadyExistFileName,
|
||
TASK_STATUS.UPLOADED,
|
||
undefined,
|
||
undefined,
|
||
undefined,
|
||
undefined,
|
||
'00000002',
|
||
);
|
||
|
||
// 事前にDBを確認
|
||
{
|
||
const audioFile = await getAudioFile(source, task.audioFileId);
|
||
expect(audioFile?.file_name).toBe(oldFileName);
|
||
expect(audioFile?.raw_file_name).toBe(oldFileName);
|
||
|
||
const alreadyExistAudioFile = await getAudioFile(
|
||
source,
|
||
alreadyExistTask.audioFileId,
|
||
);
|
||
expect(alreadyExistAudioFile?.file_name).toBe(alreadyExistFileName);
|
||
}
|
||
|
||
try {
|
||
await service.fileRename(
|
||
context,
|
||
admin.external_id,
|
||
task.audioFileId,
|
||
alreadyExistFileName,
|
||
);
|
||
fail();
|
||
} catch (e) {
|
||
if (e instanceof HttpException) {
|
||
expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST);
|
||
expect(e.getResponse()).toEqual(makeErrorResponse('E021002'));
|
||
} else {
|
||
fail();
|
||
}
|
||
}
|
||
});
|
||
});
|