Merge branch 'develop' into ccb
This commit is contained in:
commit
f00861702a
4
db/init/init_accounts_auto_increment.sql
Normal file
4
db/init/init_accounts_auto_increment.sql
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
-- [OMDS_IS-231] アカウントIDの開始番号調整 | 課題の表示 | Backlog 対応
|
||||||
|
-- IDからアカウント数が推測されるため、ユーザ指定の任意値を最初の番号とする
|
||||||
|
-- 一度しか実行しないため、migrate fileではなくDBの初期値として扱う。移行時の実行を想定
|
||||||
|
ALTER TABLE accounts AUTO_INCREMENT = 853211;
|
||||||
@ -62,6 +62,12 @@ export const orderLicenseAsync = createAsyncThunk<
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (error.code === "E010501") {
|
||||||
|
errorMessage = getTranslationID(
|
||||||
|
"licenseOrderPage.message.dealerNotFoundError"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
thunkApi.dispatch(
|
thunkApi.dispatch(
|
||||||
openSnackbar({
|
openSnackbar({
|
||||||
level: "error",
|
level: "error",
|
||||||
|
|||||||
@ -85,7 +85,7 @@ export const AddWorktypeIdPopup: React.FC<AddWorktypeIdPopupProps> = (
|
|||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
size={40}
|
size={40}
|
||||||
maxLength={255}
|
maxLength={16}
|
||||||
value={worktypeId ?? ""}
|
value={worktypeId ?? ""}
|
||||||
className={styles.formInput}
|
className={styles.formInput}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
|
|||||||
@ -84,7 +84,7 @@ export const EditWorktypeIdPopup: React.FC<EditWorktypeIdPopupProps> = (
|
|||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
size={40}
|
size={40}
|
||||||
maxLength={255}
|
maxLength={16}
|
||||||
value={worktypeId ?? ""}
|
value={worktypeId ?? ""}
|
||||||
className={styles.formInput}
|
className={styles.formInput}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
|
|||||||
@ -189,7 +189,8 @@
|
|||||||
"poNumberIncorrectError": "Das Format der Bestellnummer ist ungültig. Für die Bestellnummer können nur alphanumerische Zeichen eingegeben werden.",
|
"poNumberIncorrectError": "Das Format der Bestellnummer ist ungültig. Für die Bestellnummer können nur alphanumerische Zeichen eingegeben werden.",
|
||||||
"newOrderIncorrectError": "Bitte geben Sie für die neue Bestellung eine Zahl größer oder gleich 1 ein.",
|
"newOrderIncorrectError": "Bitte geben Sie für die neue Bestellung eine Zahl größer oder gleich 1 ein.",
|
||||||
"confirmOrder": "Möchten Sie eine Bestellung aufgeben?",
|
"confirmOrder": "Möchten Sie eine Bestellung aufgeben?",
|
||||||
"poNumberConflictError": "Die eingegebene Bestellnummer existiert bereits. Bitte geben Sie eine andere Bestellnummer ein."
|
"poNumberConflictError": "Die eingegebene Bestellnummer existiert bereits. Bitte geben Sie eine andere Bestellnummer ein.",
|
||||||
|
"dealerNotFoundError": "(de)ディーラーが設定されていないため、ライセンスを注文できません。アカウント画面でディーラーを指定してください。"
|
||||||
},
|
},
|
||||||
"label": {
|
"label": {
|
||||||
"title": "Lizenz bestellen",
|
"title": "Lizenz bestellen",
|
||||||
|
|||||||
@ -190,7 +190,8 @@
|
|||||||
"poNumberIncorrectError": "PO Number format is not valid. Only alphanumeric characters can be entered for the PO Number.",
|
"poNumberIncorrectError": "PO Number format is not valid. Only alphanumeric characters can be entered for the PO Number.",
|
||||||
"newOrderIncorrectError": "Please enter a number greater than or equal to 1 for the New Order.",
|
"newOrderIncorrectError": "Please enter a number greater than or equal to 1 for the New Order.",
|
||||||
"confirmOrder": "Would you like to place an order?",
|
"confirmOrder": "Would you like to place an order?",
|
||||||
"poNumberConflictError": "PO Number entered already exists. Please enter a different PO Number."
|
"poNumberConflictError": "PO Number entered already exists. Please enter a different PO Number.",
|
||||||
|
"dealerNotFoundError": "ディーラーが設定されていないため、ライセンスを注文できません。アカウント画面でディーラーを指定してください。"
|
||||||
},
|
},
|
||||||
"label": {
|
"label": {
|
||||||
"title": "Order License",
|
"title": "Order License",
|
||||||
|
|||||||
@ -190,7 +190,8 @@
|
|||||||
"poNumberIncorrectError": "El formato del número de orden de compra no es válido. Sólo se pueden ingresar caracteres alfanuméricos para el número de orden de compra.",
|
"poNumberIncorrectError": "El formato del número de orden de compra no es válido. Sólo se pueden ingresar caracteres alfanuméricos para el número de orden de compra.",
|
||||||
"newOrderIncorrectError": "Ingrese un número mayor o igual a 1 para el Nuevo Pedido.",
|
"newOrderIncorrectError": "Ingrese un número mayor o igual a 1 para el Nuevo Pedido.",
|
||||||
"confirmOrder": "¿Quieres hacer un pedido?",
|
"confirmOrder": "¿Quieres hacer un pedido?",
|
||||||
"poNumberConflictError": "El número de orden de compra ingresado ya existe. Ingrese un número de orden de compra diferente."
|
"poNumberConflictError": "El número de orden de compra ingresado ya existe. Ingrese un número de orden de compra diferente.",
|
||||||
|
"dealerNotFoundError": "(es)ディーラーが設定されていないため、ライセンスを注文できません。アカウント画面でディーラーを指定してください。"
|
||||||
},
|
},
|
||||||
"label": {
|
"label": {
|
||||||
"title": "Licencia de pedido",
|
"title": "Licencia de pedido",
|
||||||
|
|||||||
@ -190,7 +190,8 @@
|
|||||||
"poNumberIncorrectError": "Le format du numéro de bon de commande n'est pas valide. Seuls des caractères alphanumériques peuvent être saisis pour le numéro de bon de commande.",
|
"poNumberIncorrectError": "Le format du numéro de bon de commande n'est pas valide. Seuls des caractères alphanumériques peuvent être saisis pour le numéro de bon de commande.",
|
||||||
"newOrderIncorrectError": "Veuillez saisir un nombre supérieur ou égal à 1 pour la nouvelle commande.",
|
"newOrderIncorrectError": "Veuillez saisir un nombre supérieur ou égal à 1 pour la nouvelle commande.",
|
||||||
"confirmOrder": "Voulez-vous passer commande?",
|
"confirmOrder": "Voulez-vous passer commande?",
|
||||||
"poNumberConflictError": "Le numéro de bon de commande saisi existe déjà. Veuillez saisir un autre numéro de bon de commande."
|
"poNumberConflictError": "Le numéro de bon de commande saisi existe déjà. Veuillez saisir un autre numéro de bon de commande.",
|
||||||
|
"dealerNotFoundError": "(fr)ディーラーが設定されていないため、ライセンスを注文できません。アカウント画面でディーラーを指定してください。"
|
||||||
},
|
},
|
||||||
"label": {
|
"label": {
|
||||||
"title": "Commander licence",
|
"title": "Commander licence",
|
||||||
|
|||||||
@ -16,7 +16,7 @@ MAIL_FROM=xxxxx@xxxxx.xxxx
|
|||||||
NOTIFICATION_HUB_NAME=ntf-odms-dev
|
NOTIFICATION_HUB_NAME=ntf-odms-dev
|
||||||
NOTIFICATION_HUB_CONNECT_STRING=XXXXXXXXXXXXXXXXXX
|
NOTIFICATION_HUB_CONNECT_STRING=XXXXXXXXXXXXXXXXXX
|
||||||
APP_DOMAIN=http://localhost:8081/
|
APP_DOMAIN=http://localhost:8081/
|
||||||
STORAGE_TOKEN_EXPIRE_TIME=30
|
STORAGE_TOKEN_EXPIRE_TIME=2
|
||||||
STORAGE_ACCOUNT_NAME_US=saodmsusdev
|
STORAGE_ACCOUNT_NAME_US=saodmsusdev
|
||||||
STORAGE_ACCOUNT_NAME_AU=saodmsaudev
|
STORAGE_ACCOUNT_NAME_AU=saodmsaudev
|
||||||
STORAGE_ACCOUNT_NAME_EU=saodmseudev
|
STORAGE_ACCOUNT_NAME_EU=saodmseudev
|
||||||
@ -26,10 +26,10 @@ STORAGE_ACCOUNT_KEY_EU=XXXXXXXXXXXXXXXXXXXXXXX
|
|||||||
STORAGE_ACCOUNT_ENDPOINT_US=https://AAAAAAAAAAAAA
|
STORAGE_ACCOUNT_ENDPOINT_US=https://AAAAAAAAAAAAA
|
||||||
STORAGE_ACCOUNT_ENDPOINT_AU=https://AAAAAAAAAAAAA
|
STORAGE_ACCOUNT_ENDPOINT_AU=https://AAAAAAAAAAAAA
|
||||||
STORAGE_ACCOUNT_ENDPOINT_EU=https://AAAAAAAAAAAAA
|
STORAGE_ACCOUNT_ENDPOINT_EU=https://AAAAAAAAAAAAA
|
||||||
ACCESS_TOKEN_LIFETIME_WEB=7200000
|
ACCESS_TOKEN_LIFETIME_WEB=7200
|
||||||
REFRESH_TOKEN_LIFETIME_WEB=86400000
|
REFRESH_TOKEN_LIFETIME_WEB=86400
|
||||||
REFRESH_TOKEN_LIFETIME_DEFAULT=2592000000
|
REFRESH_TOKEN_LIFETIME_DEFAULT=2592000
|
||||||
EMAIL_CONFIRM_LIFETIME=86400000
|
EMAIL_CONFIRM_LIFETIME=86400
|
||||||
REDIS_HOST=redis-cache
|
REDIS_HOST=redis-cache
|
||||||
REDIS_PORT=6379
|
REDIS_PORT=6379
|
||||||
REDIS_PASSWORD=omdsredispass
|
REDIS_PASSWORD=omdsredispass
|
||||||
|
|||||||
@ -0,0 +1,19 @@
|
|||||||
|
-- +migrate Up
|
||||||
|
ALTER TABLE `accounts` ADD INDEX `idx_accounts_tier` (tier);
|
||||||
|
ALTER TABLE `accounts` ADD INDEX `idx_accounts_parent_account_id` (parent_account_id);
|
||||||
|
ALTER TABLE `users` ADD INDEX `idx_users_external_id` (external_id);
|
||||||
|
ALTER TABLE `users` ADD INDEX `idx_users_email_verified` (email_verified);
|
||||||
|
ALTER TABLE `licenses` ADD INDEX `idx_licenses_order_id` (order_id);
|
||||||
|
ALTER TABLE `licenses` ADD INDEX `idx_licenses_status` (status);
|
||||||
|
ALTER TABLE `template_files` ADD INDEX `idx_template_files_account_id` (account_id);
|
||||||
|
ALTER TABLE `template_files` ADD INDEX `idx_template_files_file_name` (file_name(500));
|
||||||
|
|
||||||
|
-- +migrate Down
|
||||||
|
ALTER TABLE `accounts` DROP INDEX `idx_accounts_tier`;
|
||||||
|
ALTER TABLE `accounts` DROP INDEX `idx_accounts_parent_account_id`;
|
||||||
|
ALTER TABLE `users` DROP INDEX `idx_users_external_id`;
|
||||||
|
ALTER TABLE `users` DROP INDEX `idx_users_email_verified`;
|
||||||
|
ALTER TABLE `licenses` DROP INDEX `idx_licenses_order_id`;
|
||||||
|
ALTER TABLE `licenses` DROP INDEX `idx_licenses_status`;
|
||||||
|
ALTER TABLE `template_files` DROP INDEX `idx_template_files_account_id`;
|
||||||
|
ALTER TABLE `template_files` DROP INDEX `idx_template_files_file_name`;
|
||||||
@ -219,9 +219,9 @@ export const PNS = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ユーザーのライセンス状態
|
* ユーザーのライセンスの有効期限の状態
|
||||||
*/
|
*/
|
||||||
export const USER_LICENSE_STATUS = {
|
export const USER_LICENSE_EXPIRY_STATUS = {
|
||||||
NORMAL: 'Normal',
|
NORMAL: 'Normal',
|
||||||
NO_LICENSE: 'NoLicense',
|
NO_LICENSE: 'NoLicense',
|
||||||
ALERT: 'Alert',
|
ALERT: 'Alert',
|
||||||
@ -311,3 +311,13 @@ export const USER_AUDIO_FORMAT = 'DS2(QP)';
|
|||||||
* @const {string[]}
|
* @const {string[]}
|
||||||
*/
|
*/
|
||||||
export const NODE_ENV_TEST = 'test';
|
export const NODE_ENV_TEST = 'test';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ユーザに対するライセンスの状態
|
||||||
|
* @const {string[]}
|
||||||
|
*/
|
||||||
|
export const USER_LICENSE_STATUS = {
|
||||||
|
UNALLOCATED: 'unallocated',
|
||||||
|
ALLOCATED: 'allocated',
|
||||||
|
EXPIRED: 'expired',
|
||||||
|
} as const;
|
||||||
|
|||||||
@ -198,7 +198,7 @@ export class CancelIssueRequest {
|
|||||||
export class CreateWorktypesRequest {
|
export class CreateWorktypesRequest {
|
||||||
@ApiProperty({ minLength: 1, maxLength: 255, description: 'WorktypeID' })
|
@ApiProperty({ minLength: 1, maxLength: 255, description: 'WorktypeID' })
|
||||||
@MinLength(1)
|
@MinLength(1)
|
||||||
@MaxLength(255)
|
@MaxLength(16)
|
||||||
@IsRecorderAllowed()
|
@IsRecorderAllowed()
|
||||||
worktypeId: string;
|
worktypeId: string;
|
||||||
@ApiProperty({ description: 'Worktypeの説明', required: false })
|
@ApiProperty({ description: 'Worktypeの説明', required: false })
|
||||||
@ -210,7 +210,7 @@ export class CreateWorktypesRequest {
|
|||||||
export class UpdateWorktypesRequest {
|
export class UpdateWorktypesRequest {
|
||||||
@ApiProperty({ minLength: 1, description: 'WorktypeID' })
|
@ApiProperty({ minLength: 1, description: 'WorktypeID' })
|
||||||
@MinLength(1)
|
@MinLength(1)
|
||||||
@MaxLength(255)
|
@MaxLength(16)
|
||||||
@IsRecorderAllowed()
|
@IsRecorderAllowed()
|
||||||
worktypeId: string;
|
worktypeId: string;
|
||||||
@ApiProperty({ description: 'Worktypeの説明', required: false })
|
@ApiProperty({ description: 'Worktypeの説明', required: false })
|
||||||
|
|||||||
@ -235,67 +235,6 @@ describe('publishUploadSas', () => {
|
|||||||
new HttpException(makeErrorResponse('E010812'), HttpStatus.BAD_REQUEST),
|
new HttpException(makeErrorResponse('E010812'), HttpStatus.BAD_REQUEST),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
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,
|
|
||||||
author_id: authorId,
|
|
||||||
} = await makeTestUser(source, {
|
|
||||||
account_id: tier5Accounts.account.id,
|
|
||||||
external_id: 'author-user-external-id',
|
|
||||||
role: 'author',
|
|
||||||
author_id: 'AUTHOR_ID',
|
|
||||||
});
|
|
||||||
// 昨日の日付を作成
|
|
||||||
let yesterday = new Date();
|
|
||||||
yesterday.setDate(yesterday.getDate() - 1);
|
|
||||||
yesterday = new DateWithZeroTime(yesterday);
|
|
||||||
// 期限切れのライセンスを作成して紐づける
|
|
||||||
await createLicense(
|
|
||||||
source,
|
|
||||||
1,
|
|
||||||
yesterday,
|
|
||||||
tier5Accounts.account.id,
|
|
||||||
LICENSE_TYPE.NORMAL,
|
|
||||||
LICENSE_ALLOCATED_STATUS.ALLOCATED,
|
|
||||||
userId,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
);
|
|
||||||
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('E010805'), HttpStatus.BAD_REQUEST),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('タスク作成から自動ルーティング(DB使用)', () => {
|
describe('タスク作成から自動ルーティング(DB使用)', () => {
|
||||||
@ -1097,76 +1036,6 @@ describe('音声ファイルダウンロードURL取得', () => {
|
|||||||
),
|
),
|
||||||
).toEqual(`${url}?sas-token`);
|
).toEqual(`${url}?sas-token`);
|
||||||
});
|
});
|
||||||
it('ダウンロードSASトークンが乗っているURLを取得できる(第五階層の場合ライセンスのチェックを行う)', 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,
|
|
||||||
author_id: authorId,
|
|
||||||
} = await makeTestUser(source, {
|
|
||||||
account_id: tier5Accounts.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,
|
|
||||||
tier5Accounts.account.id,
|
|
||||||
LICENSE_TYPE.NORMAL,
|
|
||||||
LICENSE_ALLOCATED_STATUS.ALLOCATED,
|
|
||||||
userId,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
);
|
|
||||||
const url = `https://saodmsusdev.blob.core.windows.net/account-${tier5Accounts.account.id}/${userId}`;
|
|
||||||
|
|
||||||
const { audioFileId } = await createTask(
|
|
||||||
source,
|
|
||||||
tier5Accounts.account.id,
|
|
||||||
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 () => {
|
it('Typistの場合、タスクのステータスが[Inprogress,Pending]以外でエラー', async () => {
|
||||||
if (!source) fail();
|
if (!source) fail();
|
||||||
const { id: accountId } = await makeTestSimpleAccount(source);
|
const { id: accountId } = await makeTestSimpleAccount(source);
|
||||||
@ -1396,133 +1265,6 @@ describe('音声ファイルダウンロードURL取得', () => {
|
|||||||
new HttpException(makeErrorResponse('E010701'), HttpStatus.BAD_REQUEST),
|
new HttpException(makeErrorResponse('E010701'), HttpStatus.BAD_REQUEST),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
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,
|
|
||||||
author_id: authorId,
|
|
||||||
} = 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 { audioFileId } = await createTask(
|
|
||||||
source,
|
|
||||||
tier5Accounts.account.id,
|
|
||||||
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('E010812'), HttpStatus.BAD_REQUEST),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
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,
|
|
||||||
author_id: authorId,
|
|
||||||
} = await makeTestUser(source, {
|
|
||||||
account_id: tier5Accounts.account.id,
|
|
||||||
external_id: 'author-user-external-id',
|
|
||||||
role: 'author',
|
|
||||||
author_id: 'AUTHOR_ID',
|
|
||||||
});
|
|
||||||
// 昨日の日付を作成
|
|
||||||
let yesterday = new Date();
|
|
||||||
yesterday.setDate(yesterday.getDate() - 1);
|
|
||||||
yesterday = new DateWithZeroTime(yesterday);
|
|
||||||
// 期限切れのライセンスを作成して紐づける
|
|
||||||
await createLicense(
|
|
||||||
source,
|
|
||||||
1,
|
|
||||||
yesterday,
|
|
||||||
tier5Accounts.account.id,
|
|
||||||
LICENSE_TYPE.NORMAL,
|
|
||||||
LICENSE_ALLOCATED_STATUS.ALLOCATED,
|
|
||||||
userId,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
);
|
|
||||||
const url = `https://saodmsusdev.blob.core.windows.net/account-${tier5Accounts.account.id}/${userId}`;
|
|
||||||
|
|
||||||
const { audioFileId } = await createTask(
|
|
||||||
source,
|
|
||||||
tier5Accounts.account.id,
|
|
||||||
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('E010805'), HttpStatus.BAD_REQUEST),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('テンプレートファイルダウンロードURL取得', () => {
|
describe('テンプレートファイルダウンロードURL取得', () => {
|
||||||
@ -1596,70 +1338,7 @@ describe('テンプレートファイルダウンロードURL取得', () => {
|
|||||||
);
|
);
|
||||||
expect(resultUrl).toBe(`${url}?sas-token`);
|
expect(resultUrl).toBe(`${url}?sas-token`);
|
||||||
});
|
});
|
||||||
it('ダウンロードSASトークンが乗っているURLを取得できる(第五階層の場合ライセンスのチェックを行う)', 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: 'typist-user-external-id',
|
|
||||||
role: USER_ROLES.TYPIST,
|
|
||||||
});
|
|
||||||
// 本日の日付を作成
|
|
||||||
let yesterday = new Date();
|
|
||||||
yesterday.setDate(yesterday.getDate());
|
|
||||||
yesterday = new DateWithZeroTime(yesterday);
|
|
||||||
// 有効期限内のライセンスを作成して紐づける
|
|
||||||
await createLicense(
|
|
||||||
source,
|
|
||||||
1,
|
|
||||||
yesterday,
|
|
||||||
tier5Accounts.account.id,
|
|
||||||
LICENSE_TYPE.NORMAL,
|
|
||||||
LICENSE_ALLOCATED_STATUS.ALLOCATED,
|
|
||||||
userId,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
);
|
|
||||||
const url = `https://saodmsusdev.blob.core.windows.net/account-${tier5Accounts.account.id}/${userId}`;
|
|
||||||
|
|
||||||
const { audioFileId } = await createTask(
|
|
||||||
source,
|
|
||||||
tier5Accounts.account.id,
|
|
||||||
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('trackingId', 'requestId'),
|
|
||||||
externalId,
|
|
||||||
audioFileId,
|
|
||||||
);
|
|
||||||
expect(resultUrl).toBe(`${url}?sas-token`);
|
|
||||||
});
|
|
||||||
it('タスクのステータスが[Inprogress,Pending]以外でエラー', async () => {
|
it('タスクのステータスが[Inprogress,Pending]以外でエラー', async () => {
|
||||||
if (!source) fail();
|
if (!source) fail();
|
||||||
const { id: accountId } = await makeTestSimpleAccount(source);
|
const { id: accountId } = await makeTestSimpleAccount(source);
|
||||||
@ -1849,135 +1528,6 @@ describe('テンプレートファイルダウンロードURL取得', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
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: 'typist-user-external-id',
|
|
||||||
role: USER_ROLES.TYPIST,
|
|
||||||
});
|
|
||||||
const url = `https://saodmsusdev.blob.core.windows.net/account-${tier5Accounts.account.id}/${userId}`;
|
|
||||||
|
|
||||||
const { audioFileId } = await createTask(
|
|
||||||
source,
|
|
||||||
tier5Accounts.account.id,
|
|
||||||
url,
|
|
||||||
'test.zip',
|
|
||||||
TASK_STATUS.IN_PROGRESS,
|
|
||||||
undefined,
|
|
||||||
'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('trackingId', 'requestId'),
|
|
||||||
externalId,
|
|
||||||
audioFileId,
|
|
||||||
);
|
|
||||||
fail();
|
|
||||||
} catch (e) {
|
|
||||||
if (e instanceof HttpException) {
|
|
||||||
expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST);
|
|
||||||
expect(e.getResponse()).toEqual(makeErrorResponse('E010812'));
|
|
||||||
} 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: 'typist-user-external-id',
|
|
||||||
role: USER_ROLES.TYPIST,
|
|
||||||
});
|
|
||||||
// 昨日の日付を作成
|
|
||||||
let yesterday = new Date();
|
|
||||||
yesterday.setDate(yesterday.getDate() - 1);
|
|
||||||
yesterday = new DateWithZeroTime(yesterday);
|
|
||||||
// 期限切れのライセンスを作成して紐づける
|
|
||||||
await createLicense(
|
|
||||||
source,
|
|
||||||
1,
|
|
||||||
yesterday,
|
|
||||||
tier5Accounts.account.id,
|
|
||||||
LICENSE_TYPE.NORMAL,
|
|
||||||
LICENSE_ALLOCATED_STATUS.ALLOCATED,
|
|
||||||
userId,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
);
|
|
||||||
const url = `https://saodmsusdev.blob.core.windows.net/account-${tier5Accounts.account.id}/${userId}`;
|
|
||||||
|
|
||||||
const { audioFileId } = await createTask(
|
|
||||||
source,
|
|
||||||
tier5Accounts.account.id,
|
|
||||||
url,
|
|
||||||
'test.zip',
|
|
||||||
TASK_STATUS.IN_PROGRESS,
|
|
||||||
undefined,
|
|
||||||
'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('trackingId', 'requestId'),
|
|
||||||
externalId,
|
|
||||||
audioFileId,
|
|
||||||
),
|
|
||||||
fail();
|
|
||||||
} catch (e) {
|
|
||||||
if (e instanceof HttpException) {
|
|
||||||
expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST);
|
|
||||||
expect(e.getResponse()).toEqual(makeErrorResponse('E010805'));
|
|
||||||
} else {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('publishTemplateFileUploadSas', () => {
|
describe('publishTemplateFileUploadSas', () => {
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import {
|
|||||||
OPTION_ITEM_NUM,
|
OPTION_ITEM_NUM,
|
||||||
TASK_STATUS,
|
TASK_STATUS,
|
||||||
TIERS,
|
TIERS,
|
||||||
|
USER_LICENSE_STATUS,
|
||||||
USER_ROLES,
|
USER_ROLES,
|
||||||
} from '../../constants/index';
|
} from '../../constants/index';
|
||||||
import { User } from '../../repositories/users/entity/user.entity';
|
import { User } from '../../repositories/users/entity/user.entity';
|
||||||
@ -308,10 +309,10 @@ export class FilesService {
|
|||||||
context,
|
context,
|
||||||
user.id,
|
user.id,
|
||||||
);
|
);
|
||||||
if (state === 'expired') {
|
if (state === USER_LICENSE_STATUS.EXPIRED) {
|
||||||
throw new LicenseExpiredError('license is expired.');
|
throw new LicenseExpiredError('license is expired.');
|
||||||
}
|
}
|
||||||
if (state === 'inallocated') {
|
if (state === USER_LICENSE_STATUS.UNALLOCATED) {
|
||||||
throw new LicenseNotAllocatedError('license is not allocated.');
|
throw new LicenseNotAllocatedError('license is not allocated.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -392,20 +393,6 @@ export class FilesService {
|
|||||||
if (!user.account) {
|
if (!user.account) {
|
||||||
throw new AccountNotFoundError('account not found.');
|
throw new AccountNotFoundError('account not found.');
|
||||||
}
|
}
|
||||||
// 第五階層のみチェック
|
|
||||||
if (user.account.tier === TIERS.TIER5) {
|
|
||||||
// ライセンスが有効でない場合、エラー
|
|
||||||
const { state } = await this.licensesRepository.getLicenseState(
|
|
||||||
context,
|
|
||||||
user.id,
|
|
||||||
);
|
|
||||||
if (state === 'expired') {
|
|
||||||
throw new LicenseExpiredError('license is expired.');
|
|
||||||
}
|
|
||||||
if (state === 'inallocated') {
|
|
||||||
throw new LicenseNotAllocatedError('license is not allocated.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
accountId = user.account.id;
|
accountId = user.account.id;
|
||||||
userId = user.id;
|
userId = user.id;
|
||||||
country = user.account.country;
|
country = user.account.country;
|
||||||
@ -422,16 +409,6 @@ export class FilesService {
|
|||||||
}`,
|
}`,
|
||||||
);
|
);
|
||||||
switch (e.constructor) {
|
switch (e.constructor) {
|
||||||
case LicenseExpiredError:
|
|
||||||
throw new HttpException(
|
|
||||||
makeErrorResponse('E010805'),
|
|
||||||
HttpStatus.BAD_REQUEST,
|
|
||||||
);
|
|
||||||
case LicenseNotAllocatedError:
|
|
||||||
throw new HttpException(
|
|
||||||
makeErrorResponse('E010812'),
|
|
||||||
HttpStatus.BAD_REQUEST,
|
|
||||||
);
|
|
||||||
default:
|
default:
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
makeErrorResponse('E009999'),
|
makeErrorResponse('E009999'),
|
||||||
@ -571,20 +548,6 @@ export class FilesService {
|
|||||||
if (!user.account) {
|
if (!user.account) {
|
||||||
throw new AccountNotFoundError('account not found.');
|
throw new AccountNotFoundError('account not found.');
|
||||||
}
|
}
|
||||||
// 第五階層のみチェック
|
|
||||||
if (user.account.tier === TIERS.TIER5) {
|
|
||||||
// ライセンスが有効でない場合、エラー
|
|
||||||
const { state } = await this.licensesRepository.getLicenseState(
|
|
||||||
context,
|
|
||||||
user.id,
|
|
||||||
);
|
|
||||||
if (state === 'expired') {
|
|
||||||
throw new LicenseExpiredError('license is expired.');
|
|
||||||
}
|
|
||||||
if (state === 'inallocated') {
|
|
||||||
throw new LicenseNotAllocatedError('license is not allocated.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
accountId = user.account_id;
|
accountId = user.account_id;
|
||||||
userId = user.id;
|
userId = user.id;
|
||||||
country = user.account.country;
|
country = user.account.country;
|
||||||
@ -596,16 +559,6 @@ export class FilesService {
|
|||||||
}`,
|
}`,
|
||||||
);
|
);
|
||||||
switch (e.constructor) {
|
switch (e.constructor) {
|
||||||
case LicenseExpiredError:
|
|
||||||
throw new HttpException(
|
|
||||||
makeErrorResponse('E010805'),
|
|
||||||
HttpStatus.BAD_REQUEST,
|
|
||||||
);
|
|
||||||
case LicenseNotAllocatedError:
|
|
||||||
throw new HttpException(
|
|
||||||
makeErrorResponse('E010812'),
|
|
||||||
HttpStatus.BAD_REQUEST,
|
|
||||||
);
|
|
||||||
default:
|
default:
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
makeErrorResponse('E009999'),
|
makeErrorResponse('E009999'),
|
||||||
|
|||||||
@ -192,8 +192,8 @@ describe('ライセンス注文', () => {
|
|||||||
await service.licenseOrders(context, externalId, poNumber, orderCount);
|
await service.licenseOrders(context, externalId, poNumber, orderCount);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof HttpException) {
|
if (e instanceof HttpException) {
|
||||||
expect(e.getStatus()).toEqual(HttpStatus.INTERNAL_SERVER_ERROR);
|
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
|
||||||
expect(e.getResponse()).toEqual(makeErrorResponse('E009999'));
|
expect(e.getResponse()).toEqual(makeErrorResponse('E010501'));
|
||||||
} else {
|
} else {
|
||||||
fail();
|
fail();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -80,7 +80,9 @@ export class LicensesService {
|
|||||||
.parent_account_id ?? undefined;
|
.parent_account_id ?? undefined;
|
||||||
// 親アカウントIDが取得できない場合はエラー
|
// 親アカウントIDが取得できない場合はエラー
|
||||||
if (parentAccountId === undefined) {
|
if (parentAccountId === undefined) {
|
||||||
throw new Error('parent account id is undefined');
|
throw new AccountNotFoundError(
|
||||||
|
`parent account id is not found. myAccountId: ${myAccountId}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||||
@ -147,6 +149,7 @@ export class LicensesService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async issueCardLicenseKeys(
|
async issueCardLicenseKeys(
|
||||||
context: Context,
|
context: Context,
|
||||||
externalId: string,
|
externalId: string,
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import { NotificationhubModule } from '../../gateways/notificationhub/notificati
|
|||||||
import { SendGridModule } from '../../gateways/sendgrid/sendgrid.module';
|
import { SendGridModule } from '../../gateways/sendgrid/sendgrid.module';
|
||||||
import { AccountsRepositoryModule } from '../../repositories/accounts/accounts.repository.module';
|
import { AccountsRepositoryModule } from '../../repositories/accounts/accounts.repository.module';
|
||||||
import { BlobstorageModule } from '../../gateways/blobstorage/blobstorage.module';
|
import { BlobstorageModule } from '../../gateways/blobstorage/blobstorage.module';
|
||||||
|
import { LicensesRepositoryModule } from '../../repositories/licenses/licenses.repository.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@ -20,6 +21,7 @@ import { BlobstorageModule } from '../../gateways/blobstorage/blobstorage.module
|
|||||||
NotificationhubModule,
|
NotificationhubModule,
|
||||||
SendGridModule,
|
SendGridModule,
|
||||||
BlobstorageModule,
|
BlobstorageModule,
|
||||||
|
LicensesRepositoryModule,
|
||||||
],
|
],
|
||||||
providers: [TasksService],
|
providers: [TasksService],
|
||||||
controllers: [TasksController],
|
controllers: [TasksController],
|
||||||
|
|||||||
@ -27,7 +27,13 @@ import {
|
|||||||
makeTestSimpleAccount,
|
makeTestSimpleAccount,
|
||||||
makeTestUser,
|
makeTestUser,
|
||||||
} from '../../common/test/utility';
|
} from '../../common/test/utility';
|
||||||
import { ADMIN_ROLES, TASK_STATUS, USER_ROLES } from '../../constants';
|
import {
|
||||||
|
ADMIN_ROLES,
|
||||||
|
LICENSE_ALLOCATED_STATUS,
|
||||||
|
LICENSE_TYPE,
|
||||||
|
TASK_STATUS,
|
||||||
|
USER_ROLES,
|
||||||
|
} from '../../constants';
|
||||||
import { makeTestingModule } from '../../common/test/modules';
|
import { makeTestingModule } from '../../common/test/modules';
|
||||||
import { createSortCriteria } from '../users/test/utility';
|
import { createSortCriteria } from '../users/test/utility';
|
||||||
import { createWorktype } from '../accounts/test/utility';
|
import { createWorktype } from '../accounts/test/utility';
|
||||||
@ -42,6 +48,9 @@ import { TasksRepositoryService } from '../../repositories/tasks/tasks.repositor
|
|||||||
import { overrideBlobstorageService } from '../../common/test/overrides';
|
import { overrideBlobstorageService } from '../../common/test/overrides';
|
||||||
import { BlobstorageService } from '../../gateways/blobstorage/blobstorage.service';
|
import { BlobstorageService } from '../../gateways/blobstorage/blobstorage.service';
|
||||||
import { truncateAllTable } from '../../common/test/init';
|
import { truncateAllTable } from '../../common/test/init';
|
||||||
|
import { makeDefaultLicensesRepositoryMockValue } from '../accounts/test/accounts.service.mock';
|
||||||
|
import { DateWithZeroTime } from '../licenses/types/types';
|
||||||
|
import { createLicense } from '../licenses/test/utility';
|
||||||
|
|
||||||
describe('TasksService', () => {
|
describe('TasksService', () => {
|
||||||
it('タスク一覧を取得できる(admin)', async () => {
|
it('タスク一覧を取得できる(admin)', async () => {
|
||||||
@ -52,12 +61,15 @@ describe('TasksService', () => {
|
|||||||
const adb2cServiceMockValue = makeDefaultAdb2cServiceMockValue();
|
const adb2cServiceMockValue = makeDefaultAdb2cServiceMockValue();
|
||||||
const notificationhubServiceMockValue =
|
const notificationhubServiceMockValue =
|
||||||
makeDefaultNotificationhubServiceMockValue();
|
makeDefaultNotificationhubServiceMockValue();
|
||||||
|
const licensesRepositoryMockValue =
|
||||||
|
makeDefaultLicensesRepositoryMockValue();
|
||||||
const service = await makeTasksServiceMock(
|
const service = await makeTasksServiceMock(
|
||||||
tasksRepositoryMockValue,
|
tasksRepositoryMockValue,
|
||||||
usersRepositoryMockValue,
|
usersRepositoryMockValue,
|
||||||
userGroupsRepositoryMockValue,
|
userGroupsRepositoryMockValue,
|
||||||
adb2cServiceMockValue,
|
adb2cServiceMockValue,
|
||||||
notificationhubServiceMockValue,
|
notificationhubServiceMockValue,
|
||||||
|
licensesRepositoryMockValue,
|
||||||
);
|
);
|
||||||
|
|
||||||
const userId = 'userId';
|
const userId = 'userId';
|
||||||
@ -126,6 +138,8 @@ describe('TasksService', () => {
|
|||||||
const adb2cServiceMockValue = makeDefaultAdb2cServiceMockValue();
|
const adb2cServiceMockValue = makeDefaultAdb2cServiceMockValue();
|
||||||
const notificationhubServiceMockValue =
|
const notificationhubServiceMockValue =
|
||||||
makeDefaultNotificationhubServiceMockValue();
|
makeDefaultNotificationhubServiceMockValue();
|
||||||
|
const licensesRepositoryMockValue =
|
||||||
|
makeDefaultLicensesRepositoryMockValue();
|
||||||
usersRepositoryMockValue.findUserByExternalId = new Error('DB failed');
|
usersRepositoryMockValue.findUserByExternalId = new Error('DB failed');
|
||||||
const service = await makeTasksServiceMock(
|
const service = await makeTasksServiceMock(
|
||||||
tasksRepositoryMockValue,
|
tasksRepositoryMockValue,
|
||||||
@ -133,6 +147,7 @@ describe('TasksService', () => {
|
|||||||
userGroupsRepositoryMockValue,
|
userGroupsRepositoryMockValue,
|
||||||
adb2cServiceMockValue,
|
adb2cServiceMockValue,
|
||||||
notificationhubServiceMockValue,
|
notificationhubServiceMockValue,
|
||||||
|
licensesRepositoryMockValue,
|
||||||
);
|
);
|
||||||
|
|
||||||
const userId = 'userId';
|
const userId = 'userId';
|
||||||
@ -168,6 +183,8 @@ describe('TasksService', () => {
|
|||||||
const adb2cServiceMockValue = makeDefaultAdb2cServiceMockValue();
|
const adb2cServiceMockValue = makeDefaultAdb2cServiceMockValue();
|
||||||
const notificationhubServiceMockValue =
|
const notificationhubServiceMockValue =
|
||||||
makeDefaultNotificationhubServiceMockValue();
|
makeDefaultNotificationhubServiceMockValue();
|
||||||
|
const licensesRepositoryMockValue =
|
||||||
|
makeDefaultLicensesRepositoryMockValue();
|
||||||
tasksRepositoryMockValue.getTasksFromAccountId = new Error('DB failed');
|
tasksRepositoryMockValue.getTasksFromAccountId = new Error('DB failed');
|
||||||
const service = await makeTasksServiceMock(
|
const service = await makeTasksServiceMock(
|
||||||
tasksRepositoryMockValue,
|
tasksRepositoryMockValue,
|
||||||
@ -175,6 +192,7 @@ describe('TasksService', () => {
|
|||||||
userGroupsRepositoryMockValue,
|
userGroupsRepositoryMockValue,
|
||||||
adb2cServiceMockValue,
|
adb2cServiceMockValue,
|
||||||
notificationhubServiceMockValue,
|
notificationhubServiceMockValue,
|
||||||
|
licensesRepositoryMockValue,
|
||||||
);
|
);
|
||||||
|
|
||||||
const userId = 'userId';
|
const userId = 'userId';
|
||||||
@ -256,12 +274,15 @@ describe('TasksService', () => {
|
|||||||
const adb2cServiceMockValue = makeDefaultAdb2cServiceMockValue();
|
const adb2cServiceMockValue = makeDefaultAdb2cServiceMockValue();
|
||||||
const notificationhubServiceMockValue =
|
const notificationhubServiceMockValue =
|
||||||
makeDefaultNotificationhubServiceMockValue();
|
makeDefaultNotificationhubServiceMockValue();
|
||||||
|
const licensesRepositoryMockValue =
|
||||||
|
makeDefaultLicensesRepositoryMockValue();
|
||||||
const service = await makeTasksServiceMock(
|
const service = await makeTasksServiceMock(
|
||||||
tasksRepositoryMockValue,
|
tasksRepositoryMockValue,
|
||||||
usersRepositoryMockValue,
|
usersRepositoryMockValue,
|
||||||
userGroupsRepositoryMockValue,
|
userGroupsRepositoryMockValue,
|
||||||
adb2cServiceMockValue,
|
adb2cServiceMockValue,
|
||||||
notificationhubServiceMockValue,
|
notificationhubServiceMockValue,
|
||||||
|
licensesRepositoryMockValue,
|
||||||
);
|
);
|
||||||
const userId = 'userId';
|
const userId = 'userId';
|
||||||
const offset = 0;
|
const offset = 0;
|
||||||
@ -296,6 +317,8 @@ describe('TasksService', () => {
|
|||||||
const adb2cServiceMockValue = makeDefaultAdb2cServiceMockValue();
|
const adb2cServiceMockValue = makeDefaultAdb2cServiceMockValue();
|
||||||
const notificationhubServiceMockValue =
|
const notificationhubServiceMockValue =
|
||||||
makeDefaultNotificationhubServiceMockValue();
|
makeDefaultNotificationhubServiceMockValue();
|
||||||
|
const licensesRepositoryMockValue =
|
||||||
|
makeDefaultLicensesRepositoryMockValue();
|
||||||
if (usersRepositoryMockValue.findUserByExternalId instanceof Error) {
|
if (usersRepositoryMockValue.findUserByExternalId instanceof Error) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -306,6 +329,7 @@ describe('TasksService', () => {
|
|||||||
userGroupsRepositoryMockValue,
|
userGroupsRepositoryMockValue,
|
||||||
adb2cServiceMockValue,
|
adb2cServiceMockValue,
|
||||||
notificationhubServiceMockValue,
|
notificationhubServiceMockValue,
|
||||||
|
licensesRepositoryMockValue,
|
||||||
);
|
);
|
||||||
|
|
||||||
const userId = 'userId';
|
const userId = 'userId';
|
||||||
@ -380,6 +404,8 @@ describe('TasksService', () => {
|
|||||||
const adb2cServiceMockValue = makeDefaultAdb2cServiceMockValue();
|
const adb2cServiceMockValue = makeDefaultAdb2cServiceMockValue();
|
||||||
const notificationhubServiceMockValue =
|
const notificationhubServiceMockValue =
|
||||||
makeDefaultNotificationhubServiceMockValue();
|
makeDefaultNotificationhubServiceMockValue();
|
||||||
|
const licensesRepositoryMockValue =
|
||||||
|
makeDefaultLicensesRepositoryMockValue();
|
||||||
tasksRepositoryMockValue.getTasksFromAuthorIdAndAccountId = new Error(
|
tasksRepositoryMockValue.getTasksFromAuthorIdAndAccountId = new Error(
|
||||||
'DB failed',
|
'DB failed',
|
||||||
);
|
);
|
||||||
@ -389,6 +415,7 @@ describe('TasksService', () => {
|
|||||||
userGroupsRepositoryMockValue,
|
userGroupsRepositoryMockValue,
|
||||||
adb2cServiceMockValue,
|
adb2cServiceMockValue,
|
||||||
notificationhubServiceMockValue,
|
notificationhubServiceMockValue,
|
||||||
|
licensesRepositoryMockValue,
|
||||||
);
|
);
|
||||||
|
|
||||||
const userId = 'userId';
|
const userId = 'userId';
|
||||||
@ -424,6 +451,8 @@ describe('TasksService', () => {
|
|||||||
const adb2cServiceMockValue = makeDefaultAdb2cServiceMockValue();
|
const adb2cServiceMockValue = makeDefaultAdb2cServiceMockValue();
|
||||||
const notificationhubServiceMockValue =
|
const notificationhubServiceMockValue =
|
||||||
makeDefaultNotificationhubServiceMockValue();
|
makeDefaultNotificationhubServiceMockValue();
|
||||||
|
const licensesRepositoryMockValue =
|
||||||
|
makeDefaultLicensesRepositoryMockValue();
|
||||||
if (usersRepositoryMockValue.findUserByExternalId instanceof Error) {
|
if (usersRepositoryMockValue.findUserByExternalId instanceof Error) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -435,6 +464,7 @@ describe('TasksService', () => {
|
|||||||
userGroupsRepositoryMockValue,
|
userGroupsRepositoryMockValue,
|
||||||
adb2cServiceMockValue,
|
adb2cServiceMockValue,
|
||||||
notificationhubServiceMockValue,
|
notificationhubServiceMockValue,
|
||||||
|
licensesRepositoryMockValue,
|
||||||
);
|
);
|
||||||
|
|
||||||
const userId = 'userId';
|
const userId = 'userId';
|
||||||
@ -512,12 +542,15 @@ describe('TasksService', () => {
|
|||||||
tasksRepositoryMockValue.getTasksFromTypistRelations = new Error(
|
tasksRepositoryMockValue.getTasksFromTypistRelations = new Error(
|
||||||
'DB failed',
|
'DB failed',
|
||||||
);
|
);
|
||||||
|
const licensesRepositoryMockValue =
|
||||||
|
makeDefaultLicensesRepositoryMockValue();
|
||||||
const service = await makeTasksServiceMock(
|
const service = await makeTasksServiceMock(
|
||||||
tasksRepositoryMockValue,
|
tasksRepositoryMockValue,
|
||||||
usersRepositoryMockValue,
|
usersRepositoryMockValue,
|
||||||
userGroupsRepositoryMockValue,
|
userGroupsRepositoryMockValue,
|
||||||
adb2cServiceMockValue,
|
adb2cServiceMockValue,
|
||||||
notificationhubServiceMockValue,
|
notificationhubServiceMockValue,
|
||||||
|
licensesRepositoryMockValue,
|
||||||
);
|
);
|
||||||
|
|
||||||
const userId = 'userId';
|
const userId = 'userId';
|
||||||
@ -553,6 +586,8 @@ describe('TasksService', () => {
|
|||||||
const adb2cServiceMockValue = makeDefaultAdb2cServiceMockValue();
|
const adb2cServiceMockValue = makeDefaultAdb2cServiceMockValue();
|
||||||
const notificationhubServiceMockValue =
|
const notificationhubServiceMockValue =
|
||||||
makeDefaultNotificationhubServiceMockValue();
|
makeDefaultNotificationhubServiceMockValue();
|
||||||
|
const licensesRepositoryMockValue =
|
||||||
|
makeDefaultLicensesRepositoryMockValue();
|
||||||
adb2cServiceMockValue.getUsers = new Adb2cTooManyRequestsError();
|
adb2cServiceMockValue.getUsers = new Adb2cTooManyRequestsError();
|
||||||
const service = await makeTasksServiceMock(
|
const service = await makeTasksServiceMock(
|
||||||
tasksRepositoryMockValue,
|
tasksRepositoryMockValue,
|
||||||
@ -560,6 +595,7 @@ describe('TasksService', () => {
|
|||||||
userGroupsRepositoryMockValue,
|
userGroupsRepositoryMockValue,
|
||||||
adb2cServiceMockValue,
|
adb2cServiceMockValue,
|
||||||
notificationhubServiceMockValue,
|
notificationhubServiceMockValue,
|
||||||
|
licensesRepositoryMockValue,
|
||||||
);
|
);
|
||||||
|
|
||||||
const userId = 'userId';
|
const userId = 'userId';
|
||||||
@ -1636,7 +1672,75 @@ describe('checkout', () => {
|
|||||||
user_group_id: null,
|
user_group_id: null,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it('第五階層のアカウントの場合、有効なライセンスが割当されている場合チェックアウトできる', async () => {
|
||||||
|
if (!source) fail();
|
||||||
|
const module = await makeTestingModule(source);
|
||||||
|
if (!module) fail();
|
||||||
|
// 第五階層のアカウントを作成
|
||||||
|
const { id: accountId } = await makeTestSimpleAccount(source, { tier: 5 });
|
||||||
|
const { id: typistUserId } = 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: 'MY_AUTHOR_ID',
|
||||||
|
});
|
||||||
|
// 本日の日付を作成
|
||||||
|
const today = new Date();
|
||||||
|
// 有効なライセンスを作成して紐づける
|
||||||
|
await createLicense(
|
||||||
|
source,
|
||||||
|
1,
|
||||||
|
today,
|
||||||
|
accountId,
|
||||||
|
LICENSE_TYPE.NORMAL,
|
||||||
|
LICENSE_ALLOCATED_STATUS.ALLOCATED,
|
||||||
|
typistUserId,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
const { taskId } = await createTask(
|
||||||
|
source,
|
||||||
|
accountId,
|
||||||
|
authorUserId,
|
||||||
|
'MY_AUTHOR_ID',
|
||||||
|
'',
|
||||||
|
'01',
|
||||||
|
'00000001',
|
||||||
|
'Pending',
|
||||||
|
);
|
||||||
|
await createCheckoutPermissions(source, taskId, typistUserId);
|
||||||
|
|
||||||
|
const service = module.get<TasksService>(TasksService);
|
||||||
|
|
||||||
|
const initTask = await getTask(source, taskId);
|
||||||
|
|
||||||
|
await service.checkout(
|
||||||
|
makeContext('trackingId', 'requestId'),
|
||||||
|
1,
|
||||||
|
['typist'],
|
||||||
|
'typist-user-external-id',
|
||||||
|
);
|
||||||
|
const resultTask = await getTask(source, taskId);
|
||||||
|
const permisions = await getCheckoutPermissions(source, taskId);
|
||||||
|
|
||||||
|
expect(resultTask?.status).toEqual('InProgress');
|
||||||
|
expect(resultTask?.typist_user_id).toEqual(typistUserId);
|
||||||
|
//タスクの元々のステータスがPending,Inprogressの場合、文字起こし開始時刻は更新されない
|
||||||
|
expect(resultTask?.started_at).toEqual(initTask?.started_at);
|
||||||
|
expect(permisions.length).toEqual(1);
|
||||||
|
expect(permisions[0]).toEqual({
|
||||||
|
id: 2,
|
||||||
|
task_id: 1,
|
||||||
|
user_id: 1,
|
||||||
|
user_group_id: null,
|
||||||
|
});
|
||||||
|
});
|
||||||
it('ユーザーのRoleがTypistで、対象のタスクのStatus[Uploaded,Inprogress,Pending]以外の時、タスクをチェックアウトできない', async () => {
|
it('ユーザーのRoleがTypistで、対象のタスクのStatus[Uploaded,Inprogress,Pending]以外の時、タスクをチェックアウトできない', async () => {
|
||||||
if (!source) fail();
|
if (!source) fail();
|
||||||
const module = await makeTestingModule(source);
|
const module = await makeTestingModule(source);
|
||||||
@ -1682,7 +1786,116 @@ describe('checkout', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
it('第五階層のアカウントの場合、ライセンスが未割当の場合チェックアウトできない', async () => {
|
||||||
|
if (!source) fail();
|
||||||
|
const module = await makeTestingModule(source);
|
||||||
|
if (!module) fail();
|
||||||
|
// 第五階層のアカウントを作成
|
||||||
|
const { id: accountId } = await makeTestSimpleAccount(source, { tier: 5 });
|
||||||
|
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: 'MY_AUTHOR_ID',
|
||||||
|
});
|
||||||
|
await createTask(
|
||||||
|
source,
|
||||||
|
accountId,
|
||||||
|
authorUserId,
|
||||||
|
'MY_AUTHOR_ID',
|
||||||
|
'',
|
||||||
|
'01',
|
||||||
|
'00000001',
|
||||||
|
'Backup',
|
||||||
|
);
|
||||||
|
|
||||||
|
const service = module.get<TasksService>(TasksService);
|
||||||
|
try {
|
||||||
|
await service.checkout(
|
||||||
|
makeContext('trackingId', 'requestId'),
|
||||||
|
1,
|
||||||
|
['typist'],
|
||||||
|
'typist-user-external-id',
|
||||||
|
);
|
||||||
|
fail();
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof HttpException) {
|
||||||
|
expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST);
|
||||||
|
expect(e.getResponse()).toEqual(makeErrorResponse('E010812'));
|
||||||
|
} else {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
it('第五階層のアカウントの場合、ライセンスが有効期限切れの場合チェックアウトできない', async () => {
|
||||||
|
if (!source) fail();
|
||||||
|
const module = await makeTestingModule(source);
|
||||||
|
if (!module) fail();
|
||||||
|
// 第五階層のアカウントを作成
|
||||||
|
const { id: accountId } = await makeTestSimpleAccount(source, { tier: 5 });
|
||||||
|
const { id: typistUserId } = 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: 'MY_AUTHOR_ID',
|
||||||
|
});
|
||||||
|
// 昨日の日付を作成
|
||||||
|
let yesterday = new Date();
|
||||||
|
yesterday.setDate(yesterday.getDate() - 1);
|
||||||
|
yesterday = new DateWithZeroTime(yesterday);
|
||||||
|
// 期限切れのライセンスを作成して紐づける
|
||||||
|
await createLicense(
|
||||||
|
source,
|
||||||
|
1,
|
||||||
|
yesterday,
|
||||||
|
accountId,
|
||||||
|
LICENSE_TYPE.NORMAL,
|
||||||
|
LICENSE_ALLOCATED_STATUS.ALLOCATED,
|
||||||
|
typistUserId,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
|
await createTask(
|
||||||
|
source,
|
||||||
|
accountId,
|
||||||
|
authorUserId,
|
||||||
|
'MY_AUTHOR_ID',
|
||||||
|
'',
|
||||||
|
'01',
|
||||||
|
'00000001',
|
||||||
|
'Backup',
|
||||||
|
);
|
||||||
|
|
||||||
|
const service = module.get<TasksService>(TasksService);
|
||||||
|
try {
|
||||||
|
await service.checkout(
|
||||||
|
makeContext('trackingId', 'requestId'),
|
||||||
|
1,
|
||||||
|
['typist'],
|
||||||
|
'typist-user-external-id',
|
||||||
|
);
|
||||||
|
fail();
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof HttpException) {
|
||||||
|
expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST);
|
||||||
|
expect(e.getResponse()).toEqual(makeErrorResponse('E010805'));
|
||||||
|
} else {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
it('ユーザーのRoleがTypistで、チェックアウト権限が存在しない時、タスクをチェックアウトできない', async () => {
|
it('ユーザーのRoleがTypistで、チェックアウト権限が存在しない時、タスクをチェックアウトできない', async () => {
|
||||||
if (!source) fail();
|
if (!source) fail();
|
||||||
const module = await makeTestingModule(source);
|
const module = await makeTestingModule(source);
|
||||||
|
|||||||
@ -13,6 +13,8 @@ import {
|
|||||||
ADMIN_ROLES,
|
ADMIN_ROLES,
|
||||||
MANUAL_RECOVERY_REQUIRED,
|
MANUAL_RECOVERY_REQUIRED,
|
||||||
TASK_STATUS,
|
TASK_STATUS,
|
||||||
|
TIERS,
|
||||||
|
USER_LICENSE_STATUS,
|
||||||
USER_ROLES,
|
USER_ROLES,
|
||||||
} from '../../constants';
|
} from '../../constants';
|
||||||
import {
|
import {
|
||||||
@ -42,6 +44,12 @@ import { SendGridService } from '../../gateways/sendgrid/sendgrid.service';
|
|||||||
import { getUserNameAndMailAddress } from '../../gateways/adb2c/utils/utils';
|
import { getUserNameAndMailAddress } from '../../gateways/adb2c/utils/utils';
|
||||||
import { AccountsRepositoryService } from '../../repositories/accounts/accounts.repository.service';
|
import { AccountsRepositoryService } from '../../repositories/accounts/accounts.repository.service';
|
||||||
import { BlobstorageService } from '../../gateways/blobstorage/blobstorage.service';
|
import { BlobstorageService } from '../../gateways/blobstorage/blobstorage.service';
|
||||||
|
import { AccountNotFoundError } from '../../repositories/accounts/errors/types';
|
||||||
|
import {
|
||||||
|
LicenseExpiredError,
|
||||||
|
LicenseNotAllocatedError,
|
||||||
|
} from '../../repositories/licenses/errors/types';
|
||||||
|
import { LicensesRepositoryService } from '../../repositories/licenses/licenses.repository.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TasksService {
|
export class TasksService {
|
||||||
@ -55,6 +63,7 @@ export class TasksService {
|
|||||||
private readonly sendgridService: SendGridService,
|
private readonly sendgridService: SendGridService,
|
||||||
private readonly notificationhubService: NotificationhubService,
|
private readonly notificationhubService: NotificationhubService,
|
||||||
private readonly blobStorageService: BlobstorageService,
|
private readonly blobStorageService: BlobstorageService,
|
||||||
|
private readonly licensesRepository: LicensesRepositoryService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async getTasks(
|
async getTasks(
|
||||||
@ -283,9 +292,26 @@ export class TasksService {
|
|||||||
} | params: { audioFileId: ${audioFileId}, roles: ${roles}, externalId: ${externalId} };`,
|
} | params: { audioFileId: ${audioFileId}, roles: ${roles}, externalId: ${externalId} };`,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { id, account_id, author_id } =
|
const { id, account_id, author_id, account } =
|
||||||
await this.usersRepository.findUserByExternalId(context, externalId);
|
await this.usersRepository.findUserByExternalId(context, externalId);
|
||||||
|
|
||||||
|
if (!account) {
|
||||||
|
throw new AccountNotFoundError('account not found.');
|
||||||
|
}
|
||||||
|
// 第五階層のみチェック
|
||||||
|
if (account.tier === TIERS.TIER5) {
|
||||||
|
// ライセンスが有効でない場合、エラー
|
||||||
|
const { state } = await this.licensesRepository.getLicenseState(
|
||||||
|
context,
|
||||||
|
id,
|
||||||
|
);
|
||||||
|
if (state === USER_LICENSE_STATUS.EXPIRED) {
|
||||||
|
throw new LicenseExpiredError('license is expired.');
|
||||||
|
}
|
||||||
|
if (state === USER_LICENSE_STATUS.UNALLOCATED) {
|
||||||
|
throw new LicenseNotAllocatedError('license is not allocated.');
|
||||||
|
}
|
||||||
|
}
|
||||||
if (roles.includes(USER_ROLES.AUTHOR)) {
|
if (roles.includes(USER_ROLES.AUTHOR)) {
|
||||||
// API実行者がAuthorで、AuthorIDが存在しないことは想定外のため、エラーとする
|
// API実行者がAuthorで、AuthorIDが存在しないことは想定外のため、エラーとする
|
||||||
if (!author_id) {
|
if (!author_id) {
|
||||||
@ -315,6 +341,16 @@ export class TasksService {
|
|||||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||||
if (e instanceof Error) {
|
if (e instanceof Error) {
|
||||||
switch (e.constructor) {
|
switch (e.constructor) {
|
||||||
|
case LicenseExpiredError:
|
||||||
|
throw new HttpException(
|
||||||
|
makeErrorResponse('E010805'),
|
||||||
|
HttpStatus.BAD_REQUEST,
|
||||||
|
);
|
||||||
|
case LicenseNotAllocatedError:
|
||||||
|
throw new HttpException(
|
||||||
|
makeErrorResponse('E010812'),
|
||||||
|
HttpStatus.BAD_REQUEST,
|
||||||
|
);
|
||||||
case CheckoutPermissionNotFoundError:
|
case CheckoutPermissionNotFoundError:
|
||||||
case TaskAuthorIdNotMatchError:
|
case TaskAuthorIdNotMatchError:
|
||||||
case InvalidRoleError:
|
case InvalidRoleError:
|
||||||
|
|||||||
@ -18,6 +18,11 @@ import { UserGroupsRepositoryService } from '../../../repositories/user_groups/u
|
|||||||
import { AccountsRepositoryService } from '../../../repositories/accounts/accounts.repository.service';
|
import { AccountsRepositoryService } from '../../../repositories/accounts/accounts.repository.service';
|
||||||
import { SendGridService } from '../../../gateways/sendgrid/sendgrid.service';
|
import { SendGridService } from '../../../gateways/sendgrid/sendgrid.service';
|
||||||
import { BlobstorageService } from '../../../gateways/blobstorage/blobstorage.service';
|
import { BlobstorageService } from '../../../gateways/blobstorage/blobstorage.service';
|
||||||
|
import {
|
||||||
|
LicensesRepositoryMockValue,
|
||||||
|
makeLicensesRepositoryMock,
|
||||||
|
} from '../../accounts/test/accounts.service.mock';
|
||||||
|
import { LicensesRepositoryService } from '../../../repositories/licenses/licenses.repository.service';
|
||||||
|
|
||||||
export type TasksRepositoryMockValue = {
|
export type TasksRepositoryMockValue = {
|
||||||
getTasksFromAccountId:
|
getTasksFromAccountId:
|
||||||
@ -66,6 +71,7 @@ export const makeTasksServiceMock = async (
|
|||||||
userGroupsRepositoryMockValue: UserGroupsRepositoryMockValue,
|
userGroupsRepositoryMockValue: UserGroupsRepositoryMockValue,
|
||||||
adB2CServiceMockValue: AdB2CServiceMockValue,
|
adB2CServiceMockValue: AdB2CServiceMockValue,
|
||||||
notificationhubServiceMockValue: NotificationhubServiceMockValue,
|
notificationhubServiceMockValue: NotificationhubServiceMockValue,
|
||||||
|
licensesRepositoryMockValue: LicensesRepositoryMockValue,
|
||||||
): Promise<{
|
): Promise<{
|
||||||
tasksService: TasksService;
|
tasksService: TasksService;
|
||||||
taskRepoService: TasksRepositoryService;
|
taskRepoService: TasksRepositoryService;
|
||||||
@ -95,6 +101,8 @@ export const makeTasksServiceMock = async (
|
|||||||
return {};
|
return {};
|
||||||
case BlobstorageService:
|
case BlobstorageService:
|
||||||
return {};
|
return {};
|
||||||
|
case LicensesRepositoryService:
|
||||||
|
return makeLicensesRepositoryMock(licensesRepositoryMockValue);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.compile();
|
.compile();
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import {
|
|||||||
} from 'class-validator';
|
} from 'class-validator';
|
||||||
import {
|
import {
|
||||||
TASK_LIST_SORTABLE_ATTRIBUTES,
|
TASK_LIST_SORTABLE_ATTRIBUTES,
|
||||||
USER_LICENSE_STATUS,
|
USER_LICENSE_EXPIRY_STATUS,
|
||||||
} from '../../../constants';
|
} from '../../../constants';
|
||||||
import { USER_ROLES } from '../../../constants';
|
import { USER_ROLES } from '../../../constants';
|
||||||
import {
|
import {
|
||||||
@ -67,9 +67,9 @@ export class User {
|
|||||||
remaining?: number;
|
remaining?: number;
|
||||||
|
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
description: `${Object.values(USER_LICENSE_STATUS).join('/')}`,
|
description: `${Object.values(USER_LICENSE_EXPIRY_STATUS).join('/')}`,
|
||||||
})
|
})
|
||||||
@IsIn(Object.values(USER_LICENSE_STATUS), {
|
@IsIn(Object.values(USER_LICENSE_EXPIRY_STATUS), {
|
||||||
message: 'invalid license status',
|
message: 'invalid license status',
|
||||||
})
|
})
|
||||||
licenseStatus: string;
|
licenseStatus: string;
|
||||||
|
|||||||
@ -22,7 +22,7 @@ import {
|
|||||||
LICENSE_EXPIRATION_THRESHOLD_DAYS,
|
LICENSE_EXPIRATION_THRESHOLD_DAYS,
|
||||||
LICENSE_TYPE,
|
LICENSE_TYPE,
|
||||||
USER_AUDIO_FORMAT,
|
USER_AUDIO_FORMAT,
|
||||||
USER_LICENSE_STATUS,
|
USER_LICENSE_EXPIRY_STATUS,
|
||||||
USER_ROLES,
|
USER_ROLES,
|
||||||
} from '../../constants';
|
} from '../../constants';
|
||||||
import { makeTestingModule } from '../../common/test/modules';
|
import { makeTestingModule } from '../../common/test/modules';
|
||||||
@ -1479,7 +1479,7 @@ describe('UsersService.getUsers', () => {
|
|||||||
prompt: false,
|
prompt: false,
|
||||||
expiration: undefined,
|
expiration: undefined,
|
||||||
remaining: undefined,
|
remaining: undefined,
|
||||||
licenseStatus: USER_LICENSE_STATUS.NO_LICENSE,
|
licenseStatus: USER_LICENSE_EXPIRY_STATUS.NO_LICENSE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: typistUserId,
|
id: typistUserId,
|
||||||
@ -1495,7 +1495,7 @@ describe('UsersService.getUsers', () => {
|
|||||||
prompt: false,
|
prompt: false,
|
||||||
expiration: undefined,
|
expiration: undefined,
|
||||||
remaining: undefined,
|
remaining: undefined,
|
||||||
licenseStatus: USER_LICENSE_STATUS.NO_LICENSE,
|
licenseStatus: USER_LICENSE_EXPIRY_STATUS.NO_LICENSE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: noneUserId,
|
id: noneUserId,
|
||||||
@ -1511,7 +1511,7 @@ describe('UsersService.getUsers', () => {
|
|||||||
prompt: false,
|
prompt: false,
|
||||||
expiration: undefined,
|
expiration: undefined,
|
||||||
remaining: undefined,
|
remaining: undefined,
|
||||||
licenseStatus: USER_LICENSE_STATUS.NO_LICENSE,
|
licenseStatus: USER_LICENSE_EXPIRY_STATUS.NO_LICENSE,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -1591,7 +1591,7 @@ describe('UsersService.getUsers', () => {
|
|||||||
date1.getMonth() + 1
|
date1.getMonth() + 1
|
||||||
}/${date1.getDate()}`,
|
}/${date1.getDate()}`,
|
||||||
remaining: LICENSE_EXPIRATION_THRESHOLD_DAYS + 1,
|
remaining: LICENSE_EXPIRATION_THRESHOLD_DAYS + 1,
|
||||||
licenseStatus: USER_LICENSE_STATUS.NORMAL,
|
licenseStatus: USER_LICENSE_EXPIRY_STATUS.NORMAL,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: user2,
|
id: user2,
|
||||||
@ -1609,7 +1609,7 @@ describe('UsersService.getUsers', () => {
|
|||||||
date2.getMonth() + 1
|
date2.getMonth() + 1
|
||||||
}/${date2.getDate()}`,
|
}/${date2.getDate()}`,
|
||||||
remaining: LICENSE_EXPIRATION_THRESHOLD_DAYS,
|
remaining: LICENSE_EXPIRATION_THRESHOLD_DAYS,
|
||||||
licenseStatus: USER_LICENSE_STATUS.RENEW,
|
licenseStatus: USER_LICENSE_EXPIRY_STATUS.RENEW,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: user3,
|
id: user3,
|
||||||
@ -1627,7 +1627,7 @@ describe('UsersService.getUsers', () => {
|
|||||||
date3.getMonth() + 1
|
date3.getMonth() + 1
|
||||||
}/${date3.getDate()}`,
|
}/${date3.getDate()}`,
|
||||||
remaining: LICENSE_EXPIRATION_THRESHOLD_DAYS - 1,
|
remaining: LICENSE_EXPIRATION_THRESHOLD_DAYS - 1,
|
||||||
licenseStatus: USER_LICENSE_STATUS.ALERT,
|
licenseStatus: USER_LICENSE_EXPIRY_STATUS.ALERT,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@ -37,7 +37,7 @@ import {
|
|||||||
MANUAL_RECOVERY_REQUIRED,
|
MANUAL_RECOVERY_REQUIRED,
|
||||||
OPTION_ITEM_VALUE_TYPE_NUMBER,
|
OPTION_ITEM_VALUE_TYPE_NUMBER,
|
||||||
USER_AUDIO_FORMAT,
|
USER_AUDIO_FORMAT,
|
||||||
USER_LICENSE_STATUS,
|
USER_LICENSE_EXPIRY_STATUS,
|
||||||
USER_ROLES,
|
USER_ROLES,
|
||||||
} from '../../constants';
|
} from '../../constants';
|
||||||
import { DateWithZeroTime } from '../licenses/types/types';
|
import { DateWithZeroTime } from '../licenses/types/types';
|
||||||
@ -617,7 +617,7 @@ export class UsersService {
|
|||||||
throw new Error('mail not found.');
|
throw new Error('mail not found.');
|
||||||
}
|
}
|
||||||
|
|
||||||
let status = USER_LICENSE_STATUS.NORMAL;
|
let status = USER_LICENSE_EXPIRY_STATUS.NORMAL;
|
||||||
|
|
||||||
// ライセンスの有効期限と残日数は、ライセンスが存在する場合のみ算出する
|
// ライセンスの有効期限と残日数は、ライセンスが存在する場合のみ算出する
|
||||||
// ライセンスが存在しない場合は、undefinedのままとする
|
// ライセンスが存在しない場合は、undefinedのままとする
|
||||||
@ -648,11 +648,11 @@ export class UsersService {
|
|||||||
remaining <= LICENSE_EXPIRATION_THRESHOLD_DAYS
|
remaining <= LICENSE_EXPIRATION_THRESHOLD_DAYS
|
||||||
) {
|
) {
|
||||||
status = dbUser.auto_renew
|
status = dbUser.auto_renew
|
||||||
? USER_LICENSE_STATUS.RENEW
|
? USER_LICENSE_EXPIRY_STATUS.RENEW
|
||||||
: USER_LICENSE_STATUS.ALERT;
|
: USER_LICENSE_EXPIRY_STATUS.ALERT;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
status = USER_LICENSE_STATUS.NO_LICENSE;
|
status = USER_LICENSE_EXPIRY_STATUS.NO_LICENSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -821,6 +821,7 @@ export class AccountsRepositoryService {
|
|||||||
status: Not(LICENSE_ALLOCATED_STATUS.UNALLOCATED),
|
status: Not(LICENSE_ALLOCATED_STATUS.UNALLOCATED),
|
||||||
},
|
},
|
||||||
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
|
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
|
||||||
|
lock: { mode: 'pessimistic_write' },
|
||||||
});
|
});
|
||||||
|
|
||||||
// 存在した場合エラー
|
// 存在した場合エラー
|
||||||
@ -1023,6 +1024,7 @@ export class AccountsRepositoryService {
|
|||||||
email_verified: true,
|
email_verified: true,
|
||||||
},
|
},
|
||||||
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
|
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
|
||||||
|
lock: { mode: 'pessimistic_write' },
|
||||||
});
|
});
|
||||||
if (!primaryAdminUser) {
|
if (!primaryAdminUser) {
|
||||||
throw new AdminUserNotFoundError(
|
throw new AdminUserNotFoundError(
|
||||||
@ -1040,6 +1042,7 @@ export class AccountsRepositoryService {
|
|||||||
email_verified: true,
|
email_verified: true,
|
||||||
},
|
},
|
||||||
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
|
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
|
||||||
|
lock: { mode: 'pessimistic_write' },
|
||||||
});
|
});
|
||||||
if (!secondryAdminUser) {
|
if (!secondryAdminUser) {
|
||||||
throw new AdminUserNotFoundError(
|
throw new AdminUserNotFoundError(
|
||||||
|
|||||||
@ -12,9 +12,9 @@ import {
|
|||||||
LICENSE_ALLOCATED_STATUS,
|
LICENSE_ALLOCATED_STATUS,
|
||||||
LICENSE_ISSUE_STATUS,
|
LICENSE_ISSUE_STATUS,
|
||||||
LICENSE_TYPE,
|
LICENSE_TYPE,
|
||||||
NODE_ENV_TEST,
|
|
||||||
SWITCH_FROM_TYPE,
|
SWITCH_FROM_TYPE,
|
||||||
TIERS,
|
TIERS,
|
||||||
|
USER_LICENSE_STATUS,
|
||||||
} from '../../constants';
|
} from '../../constants';
|
||||||
import {
|
import {
|
||||||
PoNumberAlreadyExistError,
|
PoNumberAlreadyExistError,
|
||||||
@ -422,10 +422,7 @@ export class LicensesRepositoryService {
|
|||||||
po_number: poNumber,
|
po_number: poNumber,
|
||||||
},
|
},
|
||||||
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
|
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
|
||||||
// テスト環境の場合はロックを行わない(sqliteがlockに対応していないため)
|
lock: { mode: 'pessimistic_write' },
|
||||||
...(process.env.NODE_ENV !== NODE_ENV_TEST
|
|
||||||
? { lock: { mode: 'pessimistic_write' } }
|
|
||||||
: {}),
|
|
||||||
});
|
});
|
||||||
if (!issuingOrder) {
|
if (!issuingOrder) {
|
||||||
// 注文が存在しない場合、エラー
|
// 注文が存在しない場合、エラー
|
||||||
@ -569,6 +566,7 @@ export class LicensesRepositoryService {
|
|||||||
id: newLicenseId,
|
id: newLicenseId,
|
||||||
},
|
},
|
||||||
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
|
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
|
||||||
|
lock: { mode: 'pessimistic_write' },
|
||||||
});
|
});
|
||||||
|
|
||||||
// ライセンスが存在しない場合はエラー
|
// ライセンスが存在しない場合はエラー
|
||||||
@ -806,12 +804,17 @@ export class LicensesRepositoryService {
|
|||||||
* ライセンスの割当状態を取得します
|
* ライセンスの割当状態を取得します
|
||||||
* @param userId ユーザーID
|
* @param userId ユーザーID
|
||||||
* @error { Error } DBアクセス失敗時の例外
|
* @error { Error } DBアクセス失敗時の例外
|
||||||
* @returns Promise<{ state: 'allocated' | 'inallocated' | 'expired' }>
|
* @returns Promise<{ state: 'allocated' | 'unallocated' | 'expired' }>
|
||||||
*/
|
*/
|
||||||
async getLicenseState(
|
async getLicenseState(
|
||||||
context: Context,
|
context: Context,
|
||||||
userId: number,
|
userId: number,
|
||||||
): Promise<{ state: 'allocated' | 'inallocated' | 'expired' }> {
|
): Promise<{
|
||||||
|
state:
|
||||||
|
| typeof USER_LICENSE_STATUS.ALLOCATED
|
||||||
|
| typeof USER_LICENSE_STATUS.UNALLOCATED
|
||||||
|
| typeof USER_LICENSE_STATUS.EXPIRED;
|
||||||
|
}> {
|
||||||
const allocatedLicense = await this.dataSource
|
const allocatedLicense = await this.dataSource
|
||||||
.getRepository(License)
|
.getRepository(License)
|
||||||
.findOne({
|
.findOne({
|
||||||
@ -824,7 +827,7 @@ export class LicensesRepositoryService {
|
|||||||
|
|
||||||
// ライセンスが割り当てられていない場合は未割当状態
|
// ライセンスが割り当てられていない場合は未割当状態
|
||||||
if (allocatedLicense == null) {
|
if (allocatedLicense == null) {
|
||||||
return { state: 'inallocated' };
|
return { state: USER_LICENSE_STATUS.UNALLOCATED };
|
||||||
}
|
}
|
||||||
|
|
||||||
// ライセンスの有効期限が過ぎている場合は期限切れ状態
|
// ライセンスの有効期限が過ぎている場合は期限切れ状態
|
||||||
@ -833,9 +836,9 @@ export class LicensesRepositoryService {
|
|||||||
allocatedLicense.expiry_date &&
|
allocatedLicense.expiry_date &&
|
||||||
allocatedLicense.expiry_date < currentDate
|
allocatedLicense.expiry_date < currentDate
|
||||||
) {
|
) {
|
||||||
return { state: 'expired' };
|
return { state: USER_LICENSE_STATUS.EXPIRED };
|
||||||
}
|
}
|
||||||
|
|
||||||
return { state: 'allocated' };
|
return { state: USER_LICENSE_STATUS.ALLOCATED };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -52,6 +52,7 @@ export class TemplateFilesRepositoryService {
|
|||||||
const template = await templateFilesRepo.findOne({
|
const template = await templateFilesRepo.findOne({
|
||||||
where: { account_id: accountId, file_name: fileName },
|
where: { account_id: accountId, file_name: fileName },
|
||||||
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
|
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
|
||||||
|
lock: { mode: 'pessimistic_write' },
|
||||||
});
|
});
|
||||||
|
|
||||||
// 同名ファイルは同じものとして扱うため、すでにファイルがあれば更新(更新日時の履歴を残しておきたい)
|
// 同名ファイルは同じものとして扱うため、すでにファイルがあれば更新(更新日時の履歴を残しておきたい)
|
||||||
|
|||||||
@ -289,6 +289,7 @@ export class UsersRepositoryService {
|
|||||||
const targetUser = await repo.findOne({
|
const targetUser = await repo.findOne({
|
||||||
where: { id: id, account_id: accountId },
|
where: { id: id, account_id: accountId },
|
||||||
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
|
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
|
||||||
|
lock: { mode: 'pessimistic_write' },
|
||||||
});
|
});
|
||||||
|
|
||||||
// 運用上ユーザがいないことはあり得ないが、プログラム上発生しうるのでエラーとして処理
|
// 運用上ユーザがいないことはあり得ないが、プログラム上発生しうるのでエラーとして処理
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user