From 446b9365f209661fff000809fd83ae8df95b2f32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B0=B4=E6=9C=AC=20=E7=A5=90=E5=B8=8C?= Date: Mon, 20 Nov 2023 00:49:00 +0000 Subject: [PATCH 1/6] =?UTF-8?q?Merged=20PR=20584:=20=E3=82=A8=E3=83=A9?= =?UTF-8?q?=E3=83=BC=E3=83=AD=E3=82=B0=E3=81=8C=E6=84=8F=E5=9B=B3=E3=81=97?= =?UTF-8?q?=E3=81=9F=E9=80=9A=E3=82=8A=E3=81=AB=E5=87=BA=E3=81=A6=E3=81=84?= =?UTF-8?q?=E3=81=AA=E3=81=84=E3=81=A8=E3=81=93=E3=82=8D=E3=81=8C=E3=81=82?= =?UTF-8?q?=E3=82=8A=E3=81=9D=E3=81=86=E3=81=AA=E5=95=8F=E9=A1=8C=E3=82=92?= =?UTF-8?q?=E8=A7=A3=E6=B6=88=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 概要 [Task2934: エラーログが意図した通りに出ていないところがありそうな問題を解消する](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2934) - 何をどう変更したか、追加したライブラリなど error=Errorのログ表示をerror=××Error(エラーの原因)となるように実装 ## レビューポイント - 特にレビューしてほしい箇所 特になし ## 動作確認状況 - ユニットテスト ## 相談(必須レビュアーの方に) 今回の実装のみではまだ解消できていない箇所がいくつかみられました。 以下にその解消できなかったログをいくつかピックアップします。 ERROR [TasksService] error=Error: There is no AuthorId for the API executor. ERROR [FilesService] error=Error: blob failed ERROR [FilesService] error=Error: container not found. ERROR [UsersService] error=Error: ADB2C error ERROR [UsersService] error=Error: user not found ERROR [UsersService] error=Error: sort criteria not found ERROR [UsersService] error=Error: sort criteria not found ERROR [UsersService] error=Error: The value stored in the DB is invalid. 原因としては、throw new ××Errorではなく、throw new Errorで実装されていました。 interface Error { name: string; message: string; stack?: string; } interface ErrorConstructor { new(message?: string): Error; (message?: string): Error; readonly prototype: Error; } 上記の実装により返却されるメッセージがErrorになっているため解消されていないと考えています。 以上の事象について対応するかしないかということと、対応する場合は、どのように対応していくかをご意見いただきたいです。 本タスクで対応というよりも別タスクとして対応とMISOは想定しています。 --- .../src/features/auth/errors/types.ts | 21 +++- .../src/features/files/errors/types.ts | 42 ++++++-- .../licenses/licenses.service.spec.ts | 11 ++- .../src/features/tasks/errors/types.ts | 7 +- .../src/features/users/users.service.spec.ts | 5 +- .../src/gateways/redis/redis.service.ts | 16 ++- .../accounts/accounts.repository.service.ts | 6 +- .../src/repositories/accounts/errors/types.ts | 28 +++++- .../src/repositories/licenses/errors/types.ts | 98 ++++++++++++++++--- .../licenses/licenses.repository.service.ts | 8 +- .../sort_criteria.repository.service.ts | 4 +- .../src/repositories/tasks/errors/types.ts | 63 ++++++++++-- .../tasks/tasks.repository.service.ts | 4 +- .../template_files/errors/types.ts | 7 +- .../repositories/user_groups/errors/types.ts | 14 ++- .../src/repositories/users/errors/types.ts | 56 +++++++++-- .../users/users.repository.service.ts | 16 +-- .../repositories/workflows/errors/types.ts | 14 ++- .../workflows/workflows.repository.service.ts | 6 +- .../repositories/worktypes/errors/types.ts | 28 +++++- .../worktypes/worktypes.repository.service.ts | 2 +- 21 files changed, 369 insertions(+), 87 deletions(-) diff --git a/dictation_server/src/features/auth/errors/types.ts b/dictation_server/src/features/auth/errors/types.ts index 969d13a..9b8c164 100644 --- a/dictation_server/src/features/auth/errors/types.ts +++ b/dictation_server/src/features/auth/errors/types.ts @@ -1,6 +1,21 @@ // Role文字列想定外エラー -export class RoleUnexpectedError extends Error {} +export class RoleUnexpectedError extends Error { + constructor(message: string) { + super(message); + this.name = 'RoleUnexpectedError'; + } +} // Tier範囲想定外エラー -export class TierUnexpectedError extends Error {} +export class TierUnexpectedError extends Error { + constructor(message: string) { + super(message); + this.name = 'TierUnexpectedError'; + } +} // トークン形式不正エラー -export class InvalidTokenFormatError extends Error {} +export class InvalidTokenFormatError extends Error { + constructor(message: string) { + super(message); + this.name = 'InvalidTokenFormatError'; + } +} diff --git a/dictation_server/src/features/files/errors/types.ts b/dictation_server/src/features/files/errors/types.ts index 735e11c..f4ea092 100644 --- a/dictation_server/src/features/files/errors/types.ts +++ b/dictation_server/src/features/files/errors/types.ts @@ -1,12 +1,42 @@ // 音声ファイル不在エラー -export class AudioFileNotFoundError extends Error {} +export class AudioFileNotFoundError extends Error { + constructor(message: string) { + super(message); + this.name = 'AudioFileNotFoundError'; + } +} // テンプレートファイル不在エラー -export class TemplateFileNotFoundError extends Error {} +export class TemplateFileNotFoundError extends Error { + constructor(message: string) { + super(message); + this.name = 'TemplateFileNotFoundError'; + } +} // Account不一致エラー -export class AccountNotMatchError extends Error {} +export class AccountNotMatchError extends Error { + constructor(message: string) { + super(message); + this.name = 'AccountNotMatchError'; + } +} // Status不一致エラー -export class StatusNotMatchError extends Error {} +export class StatusNotMatchError extends Error { + constructor(message: string) { + super(message); + this.name = 'StatusNotMatchError'; + } +} // Author不一致エラー -export class AuthorUserNotMatchError extends Error {} +export class AuthorUserNotMatchError extends Error { + constructor(message: string) { + super(message); + this.name = 'AuthorUserNotMatchError'; + } +} // TypistUser不一致エラー -export class TypistUserNotMatchError extends Error {} +export class TypistUserNotMatchError extends Error { + constructor(message: string) { + super(message); + this.name = 'TypistUserNotMatchError'; + } +} diff --git a/dictation_server/src/features/licenses/licenses.service.spec.ts b/dictation_server/src/features/licenses/licenses.service.spec.ts index 27a2458..7804d71 100644 --- a/dictation_server/src/features/licenses/licenses.service.spec.ts +++ b/dictation_server/src/features/licenses/licenses.service.spec.ts @@ -128,7 +128,9 @@ describe('LicensesService', () => { it('POナンバー重複時、エラーとなる', async () => { const lisencesRepositoryMockValue = makeDefaultLicensesRepositoryMockValue(); - lisencesRepositoryMockValue.order = new PoNumberAlreadyExistError(); + lisencesRepositoryMockValue.order = new PoNumberAlreadyExistError( + `This PoNumber already used`, + ); const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue(); const accountsRepositoryMockValue = makeDefaultAccountsRepositoryMockValue(); @@ -260,8 +262,9 @@ describe('LicensesService', () => { it('カードライセンス取り込みに失敗した場合、エラーになる(ライセンスが存在しないエラー)', async () => { const lisencesRepositoryMockValue = makeDefaultLicensesRepositoryMockValue(); - lisencesRepositoryMockValue.activateCardLicense = - new LicenseNotExistError(); + lisencesRepositoryMockValue.activateCardLicense = new LicenseNotExistError( + `License not exist`, + ); const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue(); const accountsRepositoryMockValue = makeDefaultAccountsRepositoryMockValue(); @@ -284,7 +287,7 @@ describe('LicensesService', () => { const lisencesRepositoryMockValue = makeDefaultLicensesRepositoryMockValue(); lisencesRepositoryMockValue.activateCardLicense = - new LicenseKeyAlreadyActivatedError(); + new LicenseKeyAlreadyActivatedError(`License already activated`); const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue(); const accountsRepositoryMockValue = makeDefaultAccountsRepositoryMockValue(); diff --git a/dictation_server/src/features/tasks/errors/types.ts b/dictation_server/src/features/tasks/errors/types.ts index a9faba0..ad6b3d9 100644 --- a/dictation_server/src/features/tasks/errors/types.ts +++ b/dictation_server/src/features/tasks/errors/types.ts @@ -1,2 +1,7 @@ // ロール不正エラー -export class InvalidRoleError extends Error {} +export class InvalidRoleError extends Error { + constructor(message: string) { + super(message); + this.name = 'InvalidRoleError'; + } +} diff --git a/dictation_server/src/features/users/users.service.spec.ts b/dictation_server/src/features/users/users.service.spec.ts index 0ede204..83894ee 100644 --- a/dictation_server/src/features/users/users.service.spec.ts +++ b/dictation_server/src/features/users/users.service.spec.ts @@ -330,8 +330,9 @@ describe('UsersService.confirmUserAndInitPassword', () => { const configMockValue = makeDefaultConfigValue(); const sortCriteriaRepositoryMockValue = makeDefaultSortCriteriaRepositoryMockValue(); - usersRepositoryMockValue.updateUserVerified = - new EmailAlreadyVerifiedError(); + usersRepositoryMockValue.updateUserVerified = new EmailAlreadyVerifiedError( + `Email already verified user`, + ); const service = await makeUsersServiceMock( usersRepositoryMockValue, diff --git a/dictation_server/src/gateways/redis/redis.service.ts b/dictation_server/src/gateways/redis/redis.service.ts index 10653d0..1d0e402 100644 --- a/dictation_server/src/gateways/redis/redis.service.ts +++ b/dictation_server/src/gateways/redis/redis.service.ts @@ -22,8 +22,7 @@ export class RedisService { ): Promise { this.logger.log( `[IN] [${context.getTrackingId()}] ${this.set.name} | params: { ` + - `ttl: ${ttl} - };`, + `ttl: ${ttl} };`, ); try { @@ -34,6 +33,8 @@ export class RedisService { await this.cacheManager.set(key, value, { ttl: ttl } as any); } catch (error) { this.logger.error(`[${context.getTrackingId()}] ${error}`); + } finally { + this.logger.log(`[OUT] [${context.getTrackingId()}] ${this.set.name}`); } } @@ -50,8 +51,7 @@ export class RedisService { ): Promise { this.logger.log( `[IN] [${context.getTrackingId()}] ${this.mset.name} | params: { ` + - `ttl: ${ttl} - };`, + `ttl: ${ttl} };`, ); try { @@ -62,6 +62,8 @@ export class RedisService { } } catch (error) { this.logger.error(`[${context.getTrackingId()}] ${error}`); + } finally { + this.logger.log(`[OUT] [${context.getTrackingId()}] ${this.mset.name}`); } } @@ -80,6 +82,8 @@ export class RedisService { } catch (error) { this.logger.error(`[${context.getTrackingId()}] ${error}`); return undefined; + } finally { + this.logger.log(`[OUT] [${context.getTrackingId()}] ${this.get.name}`); } } @@ -109,6 +113,8 @@ export class RedisService { } catch (error) { this.logger.error(`[${context.getTrackingId()}] ${error}`); return []; + } finally { + this.logger.log(`[OUT] [${context.getTrackingId()}] ${this.mget.name}`); } } @@ -123,6 +129,8 @@ export class RedisService { await this.cacheManager.del(key); } catch (error) { this.logger.error(`[${context.getTrackingId()}] ${error}`); + } finally { + this.logger.log(`[OUT] [${context.getTrackingId()}] ${this.del.name}`); } } } diff --git a/dictation_server/src/repositories/accounts/accounts.repository.service.ts b/dictation_server/src/repositories/accounts/accounts.repository.service.ts index 8380461..1df7d13 100644 --- a/dictation_server/src/repositories/accounts/accounts.repository.service.ts +++ b/dictation_server/src/repositories/accounts/accounts.repository.service.ts @@ -216,7 +216,7 @@ export class AccountsRepositoryService { }); if (!account) { - throw new AccountNotFoundError(); + throw new AccountNotFoundError(`Account is Not Found.`); } return account; } @@ -525,7 +525,7 @@ export class AccountsRepositoryService { }, }); if (!ownAccount) { - throw new AccountNotFoundError(); + throw new AccountNotFoundError(`Account is Not Found.`); } // 自アカウントのライセンス注文状況を取得する @@ -947,7 +947,7 @@ export class AccountsRepositoryService { // ワークタイプが存在しない場合はエラー if (!worktype) { - throw new WorktypeIdNotFoundError('Worktype is not found. id: ${id}'); + throw new WorktypeIdNotFoundError(`Worktype is not found. id: ${id}`); } } diff --git a/dictation_server/src/repositories/accounts/errors/types.ts b/dictation_server/src/repositories/accounts/errors/types.ts index d35f16f..826700c 100644 --- a/dictation_server/src/repositories/accounts/errors/types.ts +++ b/dictation_server/src/repositories/accounts/errors/types.ts @@ -1,8 +1,28 @@ // アカウント未発見エラー -export class AccountNotFoundError extends Error {} +export class AccountNotFoundError extends Error { + constructor(message: string) { + super(message); + this.name = 'AccountNotFoundError'; + } +} // ディーラーアカウント未存在エラー -export class DealerAccountNotFoundError extends Error {} +export class DealerAccountNotFoundError extends Error { + constructor(message: string) { + super(message); + this.name = 'DealerAccountNotFoundError'; + } +} // 管理者ユーザ未存在エラー -export class AdminUserNotFoundError extends Error {} +export class AdminUserNotFoundError extends Error { + constructor(message: string) { + super(message); + this.name = 'AdminUserNotFoundError'; + } +} // アカウントロックエラー -export class AccountLockedError extends Error {} +export class AccountLockedError extends Error { + constructor(message: string) { + super(message); + this.name = 'AccountLockedError'; + } +} diff --git a/dictation_server/src/repositories/licenses/errors/types.ts b/dictation_server/src/repositories/licenses/errors/types.ts index 331ece1..12b34d1 100644 --- a/dictation_server/src/repositories/licenses/errors/types.ts +++ b/dictation_server/src/repositories/licenses/errors/types.ts @@ -1,38 +1,108 @@ // POナンバーがすでに存在するエラー -export class PoNumberAlreadyExistError extends Error {} +export class PoNumberAlreadyExistError extends Error { + constructor(message: string) { + super(message); + this.name = 'PoNumberAlreadyExistError'; + } +} // 取り込むカードライセンスが存在しないエラー -export class LicenseNotExistError extends Error {} +export class LicenseNotExistError extends Error { + constructor(message: string) { + super(message); + this.name = 'LicenseNotExistError'; + } +} // 取り込むライセンスが既に取り込み済みのエラー -export class LicenseKeyAlreadyActivatedError extends Error {} +export class LicenseKeyAlreadyActivatedError extends Error { + constructor(message: string) { + super(message); + this.name = 'LicenseKeyAlreadyActivatedError'; + } +} // 注文不在エラー -export class OrderNotFoundError extends Error {} +export class OrderNotFoundError extends Error { + constructor(message: string) { + super(message); + this.name = 'OrderNotFoundError'; + } +} // 注文発行済エラー -export class AlreadyIssuedError extends Error {} +export class AlreadyIssuedError extends Error { + constructor(message: string) { + super(message); + this.name = 'AlreadyIssuedError'; + } +} // ライセンス不足エラー -export class LicensesShortageError extends Error {} +export class LicensesShortageError extends Error { + constructor(message: string) { + super(message); + this.name = 'LicensesShortageError'; + } +} // ライセンス有効期限切れエラー -export class LicenseExpiredError extends Error {} +export class LicenseExpiredError extends Error { + constructor(message: string) { + super(message); + this.name = 'LicenseExpiredError'; + } +} // ライセンス割り当て不可エラー -export class LicenseUnavailableError extends Error {} +export class LicenseUnavailableError extends Error { + constructor(message: string) { + super(message); + this.name = 'LicenseUnavailableError'; + } +} // ライセンス割り当て解除済みエラー -export class LicenseAlreadyDeallocatedError extends Error {} +export class LicenseAlreadyDeallocatedError extends Error { + constructor(message: string) { + super(message); + this.name = 'LicenseAlreadyDeallocatedError'; + } +} // 注文キャンセル失敗エラー -export class CancelOrderFailedError extends Error {} +export class CancelOrderFailedError extends Error { + constructor(message: string) { + super(message); + this.name = 'CancelOrderFailedError'; + } +} // ライセンス発行キャンセル不可エラー(ステータスが変えられている場合) -export class AlreadyLicenseStatusChangedError extends Error {} +export class AlreadyLicenseStatusChangedError extends Error { + constructor(message: string) { + super(message); + this.name = 'AlreadyLicenseStatusChangedError'; + } +} // ライセンス発行キャンセル不可エラー(発行から一定期間経過した場合) -export class CancellationPeriodExpiredError extends Error {} +export class CancellationPeriodExpiredError extends Error { + constructor(message: string) { + super(message); + this.name = 'CancellationPeriodExpiredError'; + } +} // ライセンス発行キャンセル不可エラー(発行したライセンスが割り当てされている場合) -export class AlreadyLicenseAllocatedError extends Error {} +export class AlreadyLicenseAllocatedError extends Error { + constructor(message: string) { + super(message); + this.name = 'AlreadyLicenseAllocatedError'; + } +} // ライセンス未割当エラー -export class LicenseNotAllocatedError extends Error {} +export class LicenseNotAllocatedError extends Error { + constructor(message: string) { + super(message); + this.name = 'LicenseNotAllocatedError'; + } +} diff --git a/dictation_server/src/repositories/licenses/licenses.repository.service.ts b/dictation_server/src/repositories/licenses/licenses.repository.service.ts index c43fa47..6f107fc 100644 --- a/dictation_server/src/repositories/licenses/licenses.repository.service.ts +++ b/dictation_server/src/repositories/licenses/licenses.repository.service.ts @@ -73,7 +73,7 @@ export class LicensesRepositoryService { }); // 重複があった場合はエラーを返却する if (isPoNumberDuplicated) { - throw new PoNumberAlreadyExistError(); + throw new PoNumberAlreadyExistError(`This PoNumber already used.`); } const repo = entityManager.getRepository(LicenseOrder); @@ -239,14 +239,14 @@ export class LicensesRepositoryService { this.logger.error( `card license key not exist. card_licence_key: ${licenseKey}`, ); - throw new LicenseNotExistError(); + throw new LicenseNotExistError(`License not exist.`); } // 既に取り込み済みならエラー if (targetCardLicense.activated_at) { this.logger.error( `card license already activated. card_licence_key: ${licenseKey}`, ); - throw new LicenseKeyAlreadyActivatedError(); + throw new LicenseKeyAlreadyActivatedError(`License already activated.`); } const licensesRepo = entityManager.getRepository(License); @@ -262,7 +262,7 @@ export class LicensesRepositoryService { this.logger.error( `license not exist. licence_id: ${targetCardLicense.license_id}`, ); - throw new LicenseNotExistError(); + throw new LicenseNotExistError(`License not exist.`); } // ライセンステーブルを更新する diff --git a/dictation_server/src/repositories/sort_criteria/sort_criteria.repository.service.ts b/dictation_server/src/repositories/sort_criteria/sort_criteria.repository.service.ts index c1dc4fb..fb3252d 100644 --- a/dictation_server/src/repositories/sort_criteria/sort_criteria.repository.service.ts +++ b/dictation_server/src/repositories/sort_criteria/sort_criteria.repository.service.ts @@ -34,7 +34,7 @@ export class SortCriteriaRepositoryService { }); // 運用上はあり得ないが、プログラム上発生しうるのでエラーとして処理 if (!targetSortCriteria) { - throw new Error('sort criteria not found '); + throw new Error('sort criteria not found.'); } targetSortCriteria.parameter = parameter; @@ -60,7 +60,7 @@ export class SortCriteriaRepositoryService { }); // 運用上はあり得ないが、プログラム上発生しうるのでエラーとして処理 if (!sortCriteria) { - throw new Error('sort criteria not found '); + throw new Error('sort criteria not found.'); } return sortCriteria; diff --git a/dictation_server/src/repositories/tasks/errors/types.ts b/dictation_server/src/repositories/tasks/errors/types.ts index b82c3ed..7b4aa78 100644 --- a/dictation_server/src/repositories/tasks/errors/types.ts +++ b/dictation_server/src/repositories/tasks/errors/types.ts @@ -1,18 +1,63 @@ // タイピストグループ未発見エラー -export class TypistUserGroupNotFoundError extends Error {} +export class TypistUserGroupNotFoundError extends Error { + constructor(message: string) { + super(message); + this.name = 'TypistUserGroupNotFoundError'; + } +} // タイピストユーザー未発見エラー -export class TypistUserNotFoundError extends Error {} +export class TypistUserNotFoundError extends Error { + constructor(message: string) { + super(message); + this.name = 'TypistUserNotFoundError'; + } +} // タスク未発見エラー -export class TasksNotFoundError extends Error {} +export class TasksNotFoundError extends Error { + constructor(message: string) { + super(message); + this.name = 'TasksNotFoundError'; + } +} // タスクAuthorID不一致エラー -export class TaskAuthorIdNotMatchError extends Error {} +export class TaskAuthorIdNotMatchError extends Error { + constructor(message: string) { + super(message); + this.name = 'TaskAuthorIdNotMatchError'; + } +} // チェックアウト権限未発見エラー -export class CheckoutPermissionNotFoundError extends Error {} +export class CheckoutPermissionNotFoundError extends Error { + constructor(message: string) { + super(message); + this.name = 'CheckoutPermissionNotFoundError'; + } +} // Status不一致エラー -export class StatusNotMatchError extends Error {} +export class StatusNotMatchError extends Error { + constructor(message: string) { + super(message); + this.name = 'StatusNotMatchError'; + } +} // TypistUser不一致エラー -export class TypistUserNotMatchError extends Error {} +export class TypistUserNotMatchError extends Error { + constructor(message: string) { + super(message); + this.name = 'TypistUserNotMatchError'; + } +} // Account不一致エラー -export class AccountNotMatchError extends Error {} +export class AccountNotMatchError extends Error { + constructor(message: string) { + super(message); + this.name = 'AccountNotMatchError'; + } +} // タスクチェックアウト済みエラー -export class AlreadyHasInProgressTaskError extends Error {} +export class AlreadyHasInProgressTaskError extends Error { + constructor(message: string) { + super(message); + this.name = 'AlreadyHasInProgressTaskError'; + } +} diff --git a/dictation_server/src/repositories/tasks/tasks.repository.service.ts b/dictation_server/src/repositories/tasks/tasks.repository.service.ts index 784dcec..3e6fd6f 100644 --- a/dictation_server/src/repositories/tasks/tasks.repository.service.ts +++ b/dictation_server/src/repositories/tasks/tasks.repository.service.ts @@ -190,7 +190,7 @@ export class TasksRepositoryService { ); } if (!isTaskStatus(task.status)) { - throw new Error('invalid task status'); + throw new Error('invalid task status.'); } // ステータスチェック if (!permittedSourceStatus.includes(task.status)) { @@ -340,7 +340,7 @@ export class TasksRepositoryService { ); } if (!isTaskStatus(task.status)) { - throw new Error('invalid task status'); + throw new Error('invalid task status.'); } // ステータスチェック if (!permittedSourceStatus.includes(task.status)) { diff --git a/dictation_server/src/repositories/template_files/errors/types.ts b/dictation_server/src/repositories/template_files/errors/types.ts index 52896de..d1db4d7 100644 --- a/dictation_server/src/repositories/template_files/errors/types.ts +++ b/dictation_server/src/repositories/template_files/errors/types.ts @@ -1,2 +1,7 @@ // テンプレートファイルが存在しないエラー -export class TemplateFileNotExistError extends Error {} +export class TemplateFileNotExistError extends Error { + constructor(message: string) { + super(message); + this.name = 'TemplateFileNotExistError'; + } +} diff --git a/dictation_server/src/repositories/user_groups/errors/types.ts b/dictation_server/src/repositories/user_groups/errors/types.ts index a41ff78..57aabbb 100644 --- a/dictation_server/src/repositories/user_groups/errors/types.ts +++ b/dictation_server/src/repositories/user_groups/errors/types.ts @@ -1,4 +1,14 @@ // タイピストグループが存在しないエラー -export class TypistGroupNotExistError extends Error {} +export class TypistGroupNotExistError extends Error { + constructor(message: string) { + super(message); + this.name = 'TypistGroupNotExistError'; + } +} // typistIdが不正な場合のエラー -export class TypistIdInvalidError extends Error {} +export class TypistIdInvalidError extends Error { + constructor(message: string) { + super(message); + this.name = 'TypistIdInvalidError'; + } +} diff --git a/dictation_server/src/repositories/users/errors/types.ts b/dictation_server/src/repositories/users/errors/types.ts index 32c1af0..6f90ede 100644 --- a/dictation_server/src/repositories/users/errors/types.ts +++ b/dictation_server/src/repositories/users/errors/types.ts @@ -1,16 +1,56 @@ // Email検証済みエラー -export class EmailAlreadyVerifiedError extends Error {} +export class EmailAlreadyVerifiedError extends Error { + constructor(message: string) { + super(message); + this.name = 'EmailAlreadyVerifiedError'; + } +} // ユーザー未発見エラー -export class UserNotFoundError extends Error {} +export class UserNotFoundError extends Error { + constructor(message: string) { + super(message); + this.name = 'UserNotFoundError'; + } +} // AuthorID重複エラー -export class AuthorIdAlreadyExistsError extends Error {} +export class AuthorIdAlreadyExistsError extends Error { + constructor(message: string) { + super(message); + this.name = 'AuthorIdAlreadyExistsError'; + } +} // 不正なRole変更エラー -export class InvalidRoleChangeError extends Error {} +export class InvalidRoleChangeError extends Error { + constructor(message: string) { + super(message); + this.name = 'InvalidRoleChangeError'; + } +} // 暗号化パスワード不足エラー -export class EncryptionPasswordNeedError extends Error {} +export class EncryptionPasswordNeedError extends Error { + constructor(message: string) { + super(message); + this.name = 'EncryptionPasswordNeedError'; + } +} // 利用規約バージョン情報不在エラー -export class TermInfoNotFoundError extends Error {} +export class TermInfoNotFoundError extends Error { + constructor(message: string) { + super(message); + this.name = 'TermInfoNotFoundError'; + } +} // 利用規約バージョンパラメータ不在エラー -export class UpdateTermsVersionNotSetError extends Error {} +export class UpdateTermsVersionNotSetError extends Error { + constructor(message: string) { + super(message); + this.name = 'UpdateTermsVersionNotSetError'; + } +} // 代行操作不許可エラー -export class DelegationNotAllowedError extends Error {} +export class DelegationNotAllowedError extends Error { + constructor(message: string) { + super(message); + this.name = 'DelegationNotAllowedError'; + } +} diff --git a/dictation_server/src/repositories/users/users.repository.service.ts b/dictation_server/src/repositories/users/users.repository.service.ts index ed202a5..97787de 100644 --- a/dictation_server/src/repositories/users/users.repository.service.ts +++ b/dictation_server/src/repositories/users/users.repository.service.ts @@ -136,7 +136,7 @@ export class UsersRepositoryService { }); if (!user) { - throw new UserNotFoundError(); + throw new UserNotFoundError(`User not Found.`); } return user; } @@ -189,7 +189,7 @@ export class UsersRepositoryService { // 運用上ユーザがいないことはあり得ないが、プログラム上発生しうるのでエラーとして処理 if (!targetUser) { - throw new UserNotFoundError(); + throw new UserNotFoundError(`User not Found.`); } // ユーザーのロールがNoneの場合以外はロールを変更できない @@ -267,11 +267,11 @@ export class UsersRepositoryService { // 運用上ユーザがいないことはあり得ないが、プログラム上発生しうるのでエラーとして処理 if (!targetUser) { - throw new UserNotFoundError(); + throw new UserNotFoundError(`User not Found.`); } if (targetUser.email_verified) { - throw new EmailAlreadyVerifiedError(); + throw new EmailAlreadyVerifiedError(`Email already verified user.`); } targetUser.email_verified = true; @@ -299,11 +299,11 @@ export class UsersRepositoryService { // 運用上ユーザがいないことはあり得ないが、プログラム上発生しうるのでエラーとして処理 if (!targetUser) { - throw new UserNotFoundError(); + throw new UserNotFoundError(`User not Found.`); } if (targetUser.email_verified) { - throw new EmailAlreadyVerifiedError(); + throw new EmailAlreadyVerifiedError(`Email already verified user.`); } targetUser.email_verified = true; @@ -382,7 +382,7 @@ export class UsersRepositoryService { // 運用上ユーザがいないことはあり得ないが、プログラム上発生しうるのでエラーとして処理 if (!user) { - throw new UserNotFoundError(); + throw new UserNotFoundError(`User not Found.`); } const typists = await repo.find({ @@ -456,7 +456,7 @@ export class UsersRepositoryService { }); if (!user) { - throw new UserNotFoundError(); + throw new UserNotFoundError(`User not Found.`); } if (!user.account) { throw new AccountNotFoundError('Account is Not Found.'); diff --git a/dictation_server/src/repositories/workflows/errors/types.ts b/dictation_server/src/repositories/workflows/errors/types.ts index 633bc00..1ffa5aa 100644 --- a/dictation_server/src/repositories/workflows/errors/types.ts +++ b/dictation_server/src/repositories/workflows/errors/types.ts @@ -1,4 +1,14 @@ // AuthorIDとWorktypeIDのペア重複エラー -export class AuthorIdAndWorktypeIdPairAlreadyExistsError extends Error {} +export class AuthorIdAndWorktypeIdPairAlreadyExistsError extends Error { + constructor(message: string) { + super(message); + this.name = 'AuthorIdAndWorktypeIdPairAlreadyExistsError'; + } +} // Workflow存在エラー -export class WorkflowNotFoundError extends Error {} +export class WorkflowNotFoundError extends Error { + constructor(message: string) { + super(message); + this.name = 'WorkflowNotFoundError'; + } +} diff --git a/dictation_server/src/repositories/workflows/workflows.repository.service.ts b/dictation_server/src/repositories/workflows/workflows.repository.service.ts index fb9cb9b..a1ea660 100644 --- a/dictation_server/src/repositories/workflows/workflows.repository.service.ts +++ b/dictation_server/src/repositories/workflows/workflows.repository.service.ts @@ -97,7 +97,7 @@ export class WorkflowsRepositoryService { where: { account_id: accountId, id: templateId }, }); if (!template) { - throw new TemplateFileNotExistError('template not found'); + throw new TemplateFileNotExistError('template not found.'); } } @@ -144,7 +144,7 @@ export class WorkflowsRepositoryService { }); if (workflow.length !== 0) { throw new AuthorIdAndWorktypeIdPairAlreadyExistsError( - 'workflow already exists', + 'workflow already exists.', ); } @@ -288,7 +288,7 @@ export class WorkflowsRepositoryService { }); if (duplicateWorkflow.length !== 0) { throw new AuthorIdAndWorktypeIdPairAlreadyExistsError( - 'workflow already exists', + 'workflow already exists.', ); } } diff --git a/dictation_server/src/repositories/worktypes/errors/types.ts b/dictation_server/src/repositories/worktypes/errors/types.ts index 6fe60c1..fb5db2d 100644 --- a/dictation_server/src/repositories/worktypes/errors/types.ts +++ b/dictation_server/src/repositories/worktypes/errors/types.ts @@ -1,8 +1,28 @@ // WorktypeID重複エラー -export class WorktypeIdAlreadyExistsError extends Error {} +export class WorktypeIdAlreadyExistsError extends Error { + constructor(message: string) { + super(message); + this.name = 'WorktypeIdAlreadyExistsError'; + } +} // WorktypeID登録上限エラー -export class WorktypeIdMaxCountError extends Error {} +export class WorktypeIdMaxCountError extends Error { + constructor(message: string) { + super(message); + this.name = 'WorktypeIdMaxCountError'; + } +} // WorktypeID不在エラー -export class WorktypeIdNotFoundError extends Error {} +export class WorktypeIdNotFoundError extends Error { + constructor(message: string) { + super(message); + this.name = 'WorktypeIdNotFoundError'; + } +} // WorktypeID使用中エラー -export class WorktypeIdInUseError extends Error {} +export class WorktypeIdInUseError extends Error { + constructor(message: string) { + super(message); + this.name = 'WorktypeIdInUseError'; + } +} diff --git a/dictation_server/src/repositories/worktypes/worktypes.repository.service.ts b/dictation_server/src/repositories/worktypes/worktypes.repository.service.ts index 616f9e0..38016c1 100644 --- a/dictation_server/src/repositories/worktypes/worktypes.repository.service.ts +++ b/dictation_server/src/repositories/worktypes/worktypes.repository.service.ts @@ -39,7 +39,7 @@ export class WorktypesRepositoryService { // 運用上アカウントがいないことはあり得ないが、プログラム上発生しうるのでエラーとして処理 if (!account) { - throw new AccountNotFoundError(); + throw new AccountNotFoundError('Account is Not Found.'); } const worktypes = await WorktypeRepo.find({ From 87dd0f6d6bfe5e1a215e3daa613e32004b4be4d0 Mon Sep 17 00:00:00 2001 From: "saito.k" Date: Mon, 20 Nov 2023 06:32:20 +0000 Subject: [PATCH 2/6] =?UTF-8?q?Merged=20PR=20582:=20=E3=83=A6=E3=83=BC?= =?UTF-8?q?=E3=82=B6=E3=83=BC=E4=B8=80=E8=A6=A7=E5=8F=96=E5=BE=97=E3=81=8C?= =?UTF-8?q?=E7=95=B0=E5=B8=B8=E3=81=AB=E9=81=85=E3=81=84=E5=95=8F=E9=A1=8C?= =?UTF-8?q?=E3=82=92=E8=AA=BF=E6=9F=BB=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 概要 [Task2996: ユーザー一覧取得が異常に遅い問題を調査する](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2996) - ユーザー一覧取得に関連するテーブルにインデックスを追加 - 3秒→18ミリ秒 ## レビューポイント - 特になし ## UIの変更 - Before/Afterのスクショなど - スクショ置き場 ## 動作確認状況 - develop環境に適用して確認 ## 補足 - インデックス追加後のログ - UsersServiceのIN・OUTまで ``` 2023-11-20T05:52:04.027057549Z [Nest] 1 - 11/20/2023, 5:52:04 AM  LOG [UsersService] [IN] [c7e9f495-caa2-43d8-9e6e-3bb6dc192646] getUsers 2023-11-20T05:52:04.058189825Z [Nest] 1 - 11/20/2023, 5:52:04 AM  LOG [AdB2cService] [IN] [c7e9f495-caa2-43d8-9e6e-3bb6dc192646] getUsers | params: { externalIds:[c7e9f495-caa2-43d8-9e6e-3bb6dc192646,34938cf0-6a8d-41a7-89a1-d7025172ab66,91807c29-5a77-4bc2-b85b-529839cc131d,a3e8167b-8967-4e19-9ad6-8ded12d8ea1c] }; 2023-11-20T05:52:04.058698126Z [Nest] 1 - 11/20/2023, 5:52:04 AM  LOG [RedisService] [IN] [c7e9f495-caa2-43d8-9e6e-3bb6dc192646] mget; 2023-11-20T05:52:04.067994949Z [Nest] 1 - 11/20/2023, 5:52:04 AM  LOG [RedisService] [OUT] [c7e9f495-caa2-43d8-9e6e-3bb6dc192646] mget 2023-11-20T05:52:04.068313050Z [Nest] 1 - 11/20/2023, 5:52:04 AM  LOG [AdB2cService] [c7e9f495-caa2-43d8-9e6e-3bb6dc192646] [CACHE HIT] ids: c7e9f495-caa2-43d8-9e6e-3bb6dc192646,34938cf0-6a8d-41a7-89a1-d7025172ab66,91807c29-5a77-4bc2-b85b-529839cc131d,a3e8167b-8967-4e19-9ad6-8ded12d8ea1c 2023-11-20T05:52:04.068993451Z [Nest] 1 - 11/20/2023, 5:52:04 AM  LOG [AdB2cService] [OUT] [c7e9f495-caa2-43d8-9e6e-3bb6dc192646] getUsers 2023-11-20T05:52:04.069013351Z [Nest] 1 - 11/20/2023, 5:52:04 AM  LOG [UsersService] [OUT] [c7e9f495-caa2-43d8-9e6e-3bb6dc192646] getUsers ``` --- .../db/migrations/048-add-index-licenses.sql | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 dictation_server/db/migrations/048-add-index-licenses.sql diff --git a/dictation_server/db/migrations/048-add-index-licenses.sql b/dictation_server/db/migrations/048-add-index-licenses.sql new file mode 100644 index 0000000..4613363 --- /dev/null +++ b/dictation_server/db/migrations/048-add-index-licenses.sql @@ -0,0 +1,11 @@ +-- +migrate Up +ALTER TABLE `licenses` ADD INDEX `idx_allocated_user_id` (allocated_user_id); +ALTER TABLE `user_group_member` ADD INDEX `idx_user_id` (user_id); +ALTER TABLE `user_group_member` ADD INDEX `idx_user_group_id` (user_group_id); +ALTER TABLE `users` ADD INDEX `idx_account_id` (account_id); + +-- +migrate Down +ALTER TABLE `licenses` DROP INDEX `idx_allocated_user_id`; +ALTER TABLE `user_group_member` DROP INDEX `idx_user_id`; +ALTER TABLE `user_group_member` DROP INDEX `idx_user_group_id`; +ALTER TABLE `users` DROP INDEX `idx_account_id`; From 99ac6be9fdd0d850d87000a2adda3aed58245b1b Mon Sep 17 00:00:00 2001 From: "makabe.t" Date: Mon, 20 Nov 2023 07:52:43 +0000 Subject: [PATCH 3/6] =?UTF-8?q?Merged=20PR=20585:=20=E7=94=BB=E9=9D=A2?= =?UTF-8?q?=E5=AE=9F=E8=A3=85=EF=BC=88=E3=83=9D=E3=83=83=E3=83=97=E3=82=A2?= =?UTF-8?q?=E3=83=83=E3=83=97=E8=A1=A8=E7=A4=BA=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 概要 [Task3120: 画面実装(ポップアップ表示)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/3120) - ディクテーション画面から開くバックアップポップアップを実装しました。 - ポップアップを開いて、対象タスクが表示されるところまでの実装です。 - バックアップボタンの挙動は対象外です。 ## レビューポイント - チェックボックスの挙動は適切でしょうか? - SharePointの挙動を参考にしています。 - デザインの適用で不自然な点はないでしょうか? ## UIの変更 - [Task3120](https://ndstokyo.sharepoint.com/:f:/r/sites/Piranha/Shared%20Documents/General/OMDS/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88/Task3120?csf=1&web=1&e=KxCeU4) ## 動作確認状況 - ローカルで確認 --- .../src/assets/images/open_in_new.svg | 11 + .../src/features/dictation/constants.ts | 4 + .../src/features/dictation/dictationSlice.ts | 50 ++++ .../src/features/dictation/index.ts | 1 + .../src/features/dictation/operations.ts | 52 ++++ .../src/features/dictation/selectors.ts | 27 +++ .../src/features/dictation/state.ts | 9 + .../src/features/dictation/types.ts | 5 + .../src/pages/DictationPage/backupPopup.tsx | 224 ++++++++++++++++++ .../src/pages/DictationPage/index.tsx | 41 ++++ dictation_client/src/styles/app.module.scss | 51 +++- .../src/styles/app.module.scss.d.ts | 7 +- dictation_client/src/translation/de.json | 4 +- dictation_client/src/translation/en.json | 4 +- dictation_client/src/translation/es.json | 4 +- dictation_client/src/translation/fr.json | 4 +- 16 files changed, 485 insertions(+), 13 deletions(-) create mode 100644 dictation_client/src/assets/images/open_in_new.svg create mode 100644 dictation_client/src/features/dictation/types.ts create mode 100644 dictation_client/src/pages/DictationPage/backupPopup.tsx diff --git a/dictation_client/src/assets/images/open_in_new.svg b/dictation_client/src/assets/images/open_in_new.svg new file mode 100644 index 0000000..669e721 --- /dev/null +++ b/dictation_client/src/assets/images/open_in_new.svg @@ -0,0 +1,11 @@ + + + + + + diff --git a/dictation_client/src/features/dictation/constants.ts b/dictation_client/src/features/dictation/constants.ts index 0fc83e7..d699a54 100644 --- a/dictation_client/src/features/dictation/constants.ts +++ b/dictation_client/src/features/dictation/constants.ts @@ -95,3 +95,7 @@ export const INIT_DISPLAY_INFO: DisplayInfoType = { OptionItem9: false, OptionItem10: false, } as const; + +export const BACKUP_POPUP_LIST_SIZE = 10; + +export const BACKUP_POPUP_LIST_STATUS = [STATUS.FINISHED, STATUS.BACKUP]; diff --git a/dictation_client/src/features/dictation/dictationSlice.ts b/dictation_client/src/features/dictation/dictationSlice.ts index fe97dff..0775825 100644 --- a/dictation_client/src/features/dictation/dictationSlice.ts +++ b/dictation_client/src/features/dictation/dictationSlice.ts @@ -3,6 +3,7 @@ import { Assignee, Task } from "api/api"; import { DictationState } from "./state"; import { getSortColumnAsync, + listBackupPopupTasksAsync, listTasksAsync, listTypistGroupsAsync, listTypistsAsync, @@ -27,6 +28,11 @@ const initialState: DictationState = { tasks: [], typists: [], typistGroups: [], + backup: { + tasks: [], + offset: 0, + total: 0, + }, }, apps: { displayInfo: INIT_DISPLAY_INFO, @@ -38,6 +44,7 @@ const initialState: DictationState = { pool: [], }, isLoading: true, + isBackupListLoading: false, }, }; @@ -97,6 +104,30 @@ export const dictationSlice = createSlice({ state.apps.assignee.selected = selected; state.apps.assignee.pool = pool; }, + changeBackupTaskChecked: ( + state, + action: PayloadAction<{ audioFileId: number; checked: boolean }> + ) => { + const { audioFileId, checked } = action.payload; + const tasks = state.domain.backup.tasks.map((task) => { + if (task.audioFileId === audioFileId) { + task.checked = checked; + } + return task; + }); + state.domain.backup.tasks = tasks; + }, + changeBackupTaskAllCheched: ( + state, + action: PayloadAction<{ checked: boolean }> + ) => { + const { checked } = action.payload; + const tasks = state.domain.backup.tasks.map((task) => { + task.checked = checked; + return task; + }); + state.domain.backup.tasks = tasks; + }, }, extraReducers: (builder) => { builder.addCase(listTasksAsync.pending, (state) => { @@ -145,6 +176,23 @@ export const dictationSlice = createSlice({ builder.addCase(playbackAsync.rejected, (state) => { state.apps.isLoading = false; }); + builder.addCase(listBackupPopupTasksAsync.pending, (state) => { + state.apps.isBackupListLoading = true; + }); + builder.addCase(listBackupPopupTasksAsync.fulfilled, (state, action) => { + const { offset, total, tasks } = action.payload; + state.domain.backup.tasks = tasks.map((task) => ({ + ...task, + checked: true, + })); + state.domain.backup.offset = offset; + state.domain.backup.total = total; + + state.apps.isBackupListLoading = false; + }); + builder.addCase(listBackupPopupTasksAsync.rejected, (state) => { + state.apps.isBackupListLoading = false; + }); }, }); @@ -154,6 +202,8 @@ export const { changeParamName, changeSelectedTask, changeAssignee, + changeBackupTaskChecked, + changeBackupTaskAllCheched, } = dictationSlice.actions; export default dictationSlice.reducer; diff --git a/dictation_client/src/features/dictation/index.ts b/dictation_client/src/features/dictation/index.ts index eb04fc5..0682113 100644 --- a/dictation_client/src/features/dictation/index.ts +++ b/dictation_client/src/features/dictation/index.ts @@ -3,3 +3,4 @@ export * from "./constants"; export * from "./selectors"; export * from "./dictationSlice"; export * from "./operations"; +export * from "./types"; diff --git a/dictation_client/src/features/dictation/operations.ts b/dictation_client/src/features/dictation/operations.ts index 111c513..e7ff81d 100644 --- a/dictation_client/src/features/dictation/operations.ts +++ b/dictation_client/src/features/dictation/operations.ts @@ -15,6 +15,8 @@ import { import { Configuration } from "../../api/configuration"; import { ErrorObject, createErrorObject } from "../../common/errors"; import { + BACKUP_POPUP_LIST_SIZE, + BACKUP_POPUP_LIST_STATUS, DIRECTION, DirectionType, SORTABLE_COLUMN, @@ -352,3 +354,53 @@ export const playbackAsync = createAsyncThunk< return thunkApi.rejectWithValue({ error }); } }); + +export const listBackupPopupTasksAsync = createAsyncThunk< + TasksResponse, + { + // パラメータ + offset: number; + }, + { + // rejectした時の返却値の型 + rejectValue: { + error: ErrorObject; + }; + } +>("dictations/listBackupPopupTasksAsync", async (args, thunkApi) => { + const { offset } = args; + + // apiのConfigurationを取得する + const { getState } = thunkApi; + const state = getState() as RootState; + const { configuration } = state.auth; + const accessToken = getAccessToken(state.auth); + const config = new Configuration(configuration); + const tasksApi = new TasksApi(config); + + try { + const res = await tasksApi.getTasks( + BACKUP_POPUP_LIST_SIZE, + offset, + BACKUP_POPUP_LIST_STATUS.join(","), // ステータスはFinished,Backupのみ + DIRECTION.ASC, + SORTABLE_COLUMN.Status, + { + headers: { authorization: `Bearer ${accessToken}` }, + } + ); + + return res.data; + } catch (e) { + // e ⇒ errorObjectに変換" + const error = createErrorObject(e); + thunkApi.dispatch( + openSnackbar({ + level: "error", + message: getTranslationID("common.message.internalServerError"), + }) + ); + + return thunkApi.rejectWithValue({ error }); + } +}); diff --git a/dictation_client/src/features/dictation/selectors.ts b/dictation_client/src/features/dictation/selectors.ts index 6461175..bd61ca4 100644 --- a/dictation_client/src/features/dictation/selectors.ts +++ b/dictation_client/src/features/dictation/selectors.ts @@ -1,5 +1,6 @@ import { RootState } from "app/store"; import { ceil, floor } from "lodash"; +import { BACKUP_POPUP_LIST_SIZE } from "./constants"; export const selectTasks = (state: RootState) => state.dictation.domain.tasks; @@ -41,3 +42,29 @@ export const selectPoolTranscriptionists = (state: RootState) => export const selectIsLoading = (state: RootState) => state.dictation.apps.isLoading; + +export const selectBackupTasks = (state: RootState) => + state.dictation.domain.backup.tasks; + +export const selectTotalBackupPage = (state: RootState) => { + const { total } = state.dictation.domain.backup; + const page = ceil(total / BACKUP_POPUP_LIST_SIZE); + return page; +}; + +export const selectCurrentBackupPage = (state: RootState) => { + const { offset } = state.dictation.domain.backup; + const page = floor(offset / BACKUP_POPUP_LIST_SIZE) + 1; + return page; +}; + +export const selectBackupTotal = (state: RootState) => + state.dictation.domain.backup.total; + +export const selectBackupAllChecked = (state: RootState) => { + const { tasks } = state.dictation.domain.backup; + return tasks.every((task) => task.checked); +}; + +export const selectIsBackupListLoading = (state: RootState) => + state.dictation.apps.isBackupListLoading; diff --git a/dictation_client/src/features/dictation/state.ts b/dictation_client/src/features/dictation/state.ts index 0d383f7..90a20c9 100644 --- a/dictation_client/src/features/dictation/state.ts +++ b/dictation_client/src/features/dictation/state.ts @@ -4,6 +4,7 @@ import { DisplayInfoType, SortableColumnType, } from "./constants"; +import { BackupTask } from "./types"; export interface DictationState { domain: Domain; @@ -17,6 +18,7 @@ export interface Domain { tasks: Task[]; typists: Typist[]; typistGroups: TypistGroup[]; + backup: Backup; } export interface Apps { @@ -29,4 +31,11 @@ export interface Apps { pool: Assignee[]; }; isLoading: boolean; + isBackupListLoading: boolean; +} + +export interface Backup { + tasks: BackupTask[]; + offset: number; + total: number; } diff --git a/dictation_client/src/features/dictation/types.ts b/dictation_client/src/features/dictation/types.ts new file mode 100644 index 0000000..62d0de3 --- /dev/null +++ b/dictation_client/src/features/dictation/types.ts @@ -0,0 +1,5 @@ +import { Task } from "api"; + +export interface BackupTask extends Task { + checked: boolean; +} diff --git a/dictation_client/src/pages/DictationPage/backupPopup.tsx b/dictation_client/src/pages/DictationPage/backupPopup.tsx new file mode 100644 index 0000000..c622aae --- /dev/null +++ b/dictation_client/src/pages/DictationPage/backupPopup.tsx @@ -0,0 +1,224 @@ +import React, { useCallback, useEffect } from "react"; +import styles from "styles/app.module.scss"; +import { useDispatch, useSelector } from "react-redux"; +import { + BACKUP_POPUP_LIST_SIZE, + changeBackupTaskAllCheched, + changeBackupTaskChecked, + listBackupPopupTasksAsync, + selectBackupAllChecked, + selectBackupTasks, + selectBackupTotal, + selectCurrentBackupPage, + selectIsBackupListLoading, + selectTotalBackupPage, +} from "features/dictation"; +import { AppDispatch } from "app/store"; +import { getTranslationID } from "translation"; +import { useTranslation } from "react-i18next"; +import progress_activit from "../../assets/images/progress_activit.svg"; +import close from "../../assets/images/close.svg"; + +interface BackupPopupProps { + onClose: (isChanged: boolean) => void; + isOpen: boolean; +} + +export const BackupPopup: React.FC = (props) => { + const { onClose, isOpen } = props; + const dispatch: AppDispatch = useDispatch(); + const [t] = useTranslation(); + + const isBackupListLoading = useSelector(selectIsBackupListLoading); + + const backupTasks = useSelector(selectBackupTasks); + + const total = useSelector(selectBackupTotal); + const totalPage = useSelector(selectTotalBackupPage); + const currentPage = useSelector(selectCurrentBackupPage); + + const allChecked = useSelector(selectBackupAllChecked); + + // ポップアップを閉じる処理 + const closePopup = useCallback(() => { + onClose(false); + }, [onClose]); + + useEffect(() => { + if (isOpen) { + dispatch(listBackupPopupTasksAsync({ offset: 0 })); + } + }, [dispatch, isOpen]); + + // ページネーションの制御 + const getFirstPage = useCallback(() => { + dispatch(listBackupPopupTasksAsync({ offset: 0 })); + }, [dispatch]); + + const getLastPage = useCallback(() => { + const lastPageOffset = (totalPage - 1) * BACKUP_POPUP_LIST_SIZE; + dispatch(listBackupPopupTasksAsync({ offset: lastPageOffset })); + }, [dispatch, totalPage]); + + const getPrevPage = useCallback(() => { + const prevPageOffset = (currentPage - 2) * BACKUP_POPUP_LIST_SIZE; + dispatch(listBackupPopupTasksAsync({ offset: prevPageOffset })); + }, [dispatch, currentPage]); + + const getNextPage = useCallback(() => { + const nextPageOffset = currentPage * BACKUP_POPUP_LIST_SIZE; + dispatch(listBackupPopupTasksAsync({ offset: nextPageOffset })); + }, [dispatch, currentPage]); + + return ( +
+
+

+ {t(getTranslationID("dictationPage.label.fileBackup"))} + +

+
+
+
+
+ + + + + + + + + + {!isBackupListLoading && + backupTasks.map((task) => ( + + + + + + + + ))} + {isBackupListLoading && ( + Loading + )} +
+ + dispatch( + changeBackupTaskAllCheched({ + checked: e.target.checked, + }) + ) + } + /> + + {t(getTranslationID("dictationPage.label.jobNumber"))} + + {t(getTranslationID("dictationPage.label.status"))} + + {t(getTranslationID("dictationPage.label.fileName"))} + + {t( + getTranslationID( + "dictationPage.label.transcriptionFinishedDate" + ) + )} +
+ { + dispatch( + changeBackupTaskChecked({ + audioFileId: task.audioFileId, + checked: e.target.checked, + }) + ); + }} + /> + {task.jobNumber}{task.status}{task.fileName}{task.transcriptionFinishedDate}
+
+ + {/** */} +
+ +
+
+
+ +
+
+
+
+
+ ); +}; diff --git a/dictation_client/src/pages/DictationPage/index.tsx b/dictation_client/src/pages/DictationPage/index.tsx index f9c47f8..34df912 100644 --- a/dictation_client/src/pages/DictationPage/index.tsx +++ b/dictation_client/src/pages/DictationPage/index.tsx @@ -42,8 +42,11 @@ import finished from "../../assets/images/finished.svg"; import backup from "../../assets/images/backup.svg"; import lock from "../../assets/images/lock.svg"; import progress_activit from "../../assets/images/progress_activit.svg"; +import download from "../../assets/images/download.svg"; +import open_in_new from "../../assets/images/open_in_new.svg"; import { DisPlayInfo } from "./displayInfo"; import { ChangeTranscriptionistPopup } from "./changeTranscriptionistPopup"; +import { BackupPopup } from "./backupPopup"; const DictationPage: React.FC = (): JSX.Element => { const dispatch: AppDispatch = useDispatch(); @@ -59,6 +62,7 @@ const DictationPage: React.FC = (): JSX.Element => { isChangeTranscriptionistPopupOpen, setIsChangeTranscriptionistPopupOpen, ] = useState(false); + const [isBackupPopupOpen, setIsBackupPopupOpen] = useState(false); const onChangeTranscriptionistPopupOpen = useCallback( (task: Task) => { @@ -413,6 +417,14 @@ const DictationPage: React.FC = (): JSX.Element => { ] ); + const onCloseBackupPopup = useCallback(() => { + setIsBackupPopupOpen(false); + }, []); + + const onClickBackup = useCallback(() => { + setIsBackupPopupOpen(true); + }, []); + const sortIconClass = ( currentParam: SortableColumnType, currentDirection: DirectionType, @@ -467,6 +479,7 @@ const DictationPage: React.FC = (): JSX.Element => { return ( <> + { + diff --git a/dictation_client/src/styles/app.module.scss b/dictation_client/src/styles/app.module.scss index b6728b0..8d64ef1 100644 --- a/dictation_client/src/styles/app.module.scss +++ b/dictation_client/src/styles/app.module.scss @@ -890,6 +890,11 @@ h3 + .brCrumb .tlIcon { width: 42%; text-align: left; position: relative; + white-space: pre-line; +} +.listVertical dt.overLine { + padding: 0.4rem 4%; + line-height: 1.15; } .listVertical dd { width: 42%; @@ -1107,6 +1112,25 @@ h3 + .brCrumb .tlIcon { width: inherit; padding: 0.2rem 0.5rem; } +.modal .form .table.backup .formCheck { + margin-right: 0; +} +.modal .form .table.backup th:first-child { + padding: 0 0.2rem; +} +.modal .form .table.backup td { + max-width: 150px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.modal .form .table.backup td:first-child { + padding: 0.6rem 0.2rem; +} +.modal .form .pagenation { + margin-bottom: 1.5rem; + padding-right: 2.5%; +} .modal .encryptionPass { display: none; } @@ -1898,6 +1922,19 @@ tr.isSelected .menuInTable li a.isDisable { .dictation .menuAction { margin-top: -1rem; + height: 34px; + position: relative; +} +.dictation .menuAction .alignLeft { + position: absolute; + left: 0; +} +.dictation .menuAction .alignLeft .menuLink { + padding: 0.3rem 0.3rem 0.3rem 0.5rem; +} +.dictation .menuAction .alignLeft .menuIcon { + margin-right: 0; + margin-left: 0.4rem; } .dictation .displayOptions { display: none; @@ -2047,7 +2084,7 @@ tr.isSelected .menuInTable li a.isDisable { .dictation .table.dictation td .menuInTable li:nth-child(3) { border-right: none; } -.dictation .table.dictation td .menuInTable li a.mnBack { +.dictation .table.dictation td .menuInTable li a.mnCancel { margin-left: 3rem; } .dictation .table.dictation td:has(img[alt="encrypted"]) { @@ -2266,7 +2303,8 @@ tr.isSelected .menuInTable li a.isDisable { } .formChange ul.chooseMember li input + label:hover, .formChange ul.holdMember li input + label:hover { - background: #e6e6e6 url(../assets/images/arrow_circle_left.svg) no-repeat left center; + background: #e6e6e6 url(../assets/images/arrow_circle_left.svg) no-repeat left + center; background-size: 1.3rem; } .formChange ul.chooseMember li input:checked + label, @@ -2277,8 +2315,8 @@ tr.isSelected .menuInTable li a.isDisable { } .formChange ul.chooseMember li input:checked + label:hover, .formChange ul.holdMember li input:checked + label:hover { - background: #e6e6e6 url(../assets/images/arrow_circle_right.svg) no-repeat right - center; + background: #e6e6e6 url(../assets/images/arrow_circle_right.svg) no-repeat + right center; background-size: 1.3rem; } .formChange > p { @@ -2431,7 +2469,8 @@ tr.isSelected .menuInTable li a.isDisable { } .formChange ul.chooseMember li input + label:hover, .formChange ul.holdMember li input + label:hover { - background: #e6e6e6 url(../assets/images/arrow_circle_left.svg) no-repeat left center; + background: #e6e6e6 url(../assets/images/arrow_circle_left.svg) no-repeat left + center; background-size: 1.3rem; } .formChange ul.chooseMember li input:checked + label, @@ -2442,7 +2481,7 @@ tr.isSelected .menuInTable li a.isDisable { } .formChange ul.chooseMember li input:checked + label:hover, .formChange ul.holdMember li input:checked + label:hover { - background: #e6e6e6 url(../assets/images/arrow_circle_right.svg) no-repeat right + background: #e6e6e6 url(../images/arrow_circle_right.svg) no-repeat right center; background-size: 1.3rem; } diff --git a/dictation_client/src/styles/app.module.scss.d.ts b/dictation_client/src/styles/app.module.scss.d.ts index 6c4bd76..a9c42a8 100644 --- a/dictation_client/src/styles/app.module.scss.d.ts +++ b/dictation_client/src/styles/app.module.scss.d.ts @@ -72,11 +72,12 @@ declare const classNames: { readonly tableWrap: "tableWrap"; readonly table: "table"; readonly tableHeader: "tableHeader"; + readonly backup: "backup"; + readonly pagenation: "pagenation"; readonly encryptionPass: "encryptionPass"; readonly pageHeader: "pageHeader"; readonly pageTitle: "pageTitle"; readonly pageTx: "pageTx"; - readonly pagenation: "pagenation"; readonly pagenationNav: "pagenationNav"; readonly pagenationTotal: "pagenationTotal"; readonly widthMid: "widthMid"; @@ -124,10 +125,11 @@ declare const classNames: { readonly cardHistory: "cardHistory"; readonly partner: "partner"; readonly isOpen: "isOpen"; + readonly alignLeft: "alignLeft"; readonly displayOptions: "displayOptions"; readonly tableFilter: "tableFilter"; readonly tableFilter2: "tableFilter2"; - readonly mnBack: "mnBack"; + readonly mnCancel: "mnCancel"; readonly txWsline: "txWsline"; readonly hidePri: "hidePri"; readonly opPri: "opPri"; @@ -197,7 +199,6 @@ declare const classNames: { readonly template: "template"; readonly worktype: "worktype"; readonly selectMenu: "selectMenu"; - readonly alignLeft: "alignLeft"; readonly floatNone: "floatNone"; readonly floatLeft: "floatLeft"; readonly floatRight: "floatRight"; diff --git a/dictation_client/src/translation/de.json b/dictation_client/src/translation/de.json index 190d940..b08ae0a 100644 --- a/dictation_client/src/translation/de.json +++ b/dictation_client/src/translation/de.json @@ -245,7 +245,9 @@ "changeTranscriptionist": "Transkriptionist ändern", "deleteDictation": "Diktat löschen", "selectedTranscriptionist": "Ausgewählter transkriptionist", - "poolTranscriptionist": "Transkriptionsliste" + "poolTranscriptionist": "Transkriptionsliste", + "fileBackup": "(de)File Backup", + "downloadForBackup": "(de)Download for backup" } }, "cardLicenseIssuePopupPage": { diff --git a/dictation_client/src/translation/en.json b/dictation_client/src/translation/en.json index ee47601..e4426cf 100644 --- a/dictation_client/src/translation/en.json +++ b/dictation_client/src/translation/en.json @@ -245,7 +245,9 @@ "changeTranscriptionist": "Change Transcriptionist", "deleteDictation": "Delete Dictation", "selectedTranscriptionist": "Selected Transcriptionist", - "poolTranscriptionist": "Transcription List" + "poolTranscriptionist": "Transcription List", + "fileBackup": "File Backup", + "downloadForBackup": "Download for backup" } }, "cardLicenseIssuePopupPage": { diff --git a/dictation_client/src/translation/es.json b/dictation_client/src/translation/es.json index 545778b..ada310b 100644 --- a/dictation_client/src/translation/es.json +++ b/dictation_client/src/translation/es.json @@ -245,7 +245,9 @@ "changeTranscriptionist": "Cambiar transcriptor", "deleteDictation": "Borrar dictado", "selectedTranscriptionist": "Transcriptor seleccionado", - "poolTranscriptionist": "Lista de transcriptor" + "poolTranscriptionist": "Lista de transcriptor", + "fileBackup": "(es)File Backup", + "downloadForBackup": "(es)Download for backup" } }, "cardLicenseIssuePopupPage": { diff --git a/dictation_client/src/translation/fr.json b/dictation_client/src/translation/fr.json index ee74ef0..8285a52 100644 --- a/dictation_client/src/translation/fr.json +++ b/dictation_client/src/translation/fr.json @@ -245,7 +245,9 @@ "changeTranscriptionist": "Changer de transcriptionniste ", "deleteDictation": "Supprimer la dictée", "selectedTranscriptionist": "Transcriptionniste sélectionné", - "poolTranscriptionist": "Liste de transcriptionniste" + "poolTranscriptionist": "Liste de transcriptionniste", + "fileBackup": "(fr)File Backup", + "downloadForBackup": "(fr)Download for backup" } }, "cardLicenseIssuePopupPage": { From 68aaa0e548ab74614eb660c4893118eb257dff3d Mon Sep 17 00:00:00 2001 From: "makabe.t" Date: Mon, 20 Nov 2023 08:57:56 +0000 Subject: [PATCH 4/6] =?UTF-8?q?Merged=20PR=20586:=20=E3=83=90=E3=83=83?= =?UTF-8?q?=E3=82=AF=E3=82=A2=E3=83=83=E3=83=97API=E5=AE=9F=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 概要 [Task3121: バックアップAPI実装](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/3121) - タスクのバックアップAPIとテストを実装しました。 - 実装に当たり、タスクエンティティ定義の型を修正しています。 ## レビューポイント - テストケースに過不足はないでしょうか? - エンティティの値を取得した際に`is_job_number_enabled`が数値となってしまうのでtypeをBooleanに変更しましたが問題ないでしょうか? ## UIの変更 - なし ## 動作確認状況 - ローカルで確認 --- dictation_client/openapitools.json | 2 +- .../src/api/.openapi-generator/VERSION | 2 +- dictation_client/src/api/api.ts | 353 +++++++++++------- dictation_client/src/api/base.ts | 16 +- dictation_client/src/api/configuration.ts | 9 + dictation_server/src/api/odms/openapi.json | 62 --- .../src/features/tasks/tasks.controller.ts | 68 ++-- .../src/features/tasks/tasks.service.spec.ts | 295 +++++++++++++++ .../src/features/tasks/tasks.service.ts | 55 +++ .../src/features/tasks/test/utility.ts | 3 +- .../repositories/tasks/entity/task.entity.ts | 2 +- .../tasks/tasks.repository.service.ts | 46 +++ 12 files changed, 663 insertions(+), 250 deletions(-) diff --git a/dictation_client/openapitools.json b/dictation_client/openapitools.json index 4053ae8..15fef60 100644 --- a/dictation_client/openapitools.json +++ b/dictation_client/openapitools.json @@ -2,6 +2,6 @@ "$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json", "spaces": 2, "generator-cli": { - "version": "7.0.1" + "version": "7.1.0" } } diff --git a/dictation_client/src/api/.openapi-generator/VERSION b/dictation_client/src/api/.openapi-generator/VERSION index 73a86b1..3769235 100644 --- a/dictation_client/src/api/.openapi-generator/VERSION +++ b/dictation_client/src/api/.openapi-generator/VERSION @@ -1 +1 @@ -7.0.1 \ No newline at end of file +7.1.0 \ No newline at end of file diff --git a/dictation_client/src/api/api.ts b/dictation_client/src/api/api.ts index 9bcd5d0..2b5689d 100644 --- a/dictation_client/src/api/api.ts +++ b/dictation_client/src/api/api.ts @@ -21,7 +21,7 @@ import globalAxios from 'axios'; import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction } from './common'; import type { RequestArgs } from './base'; // @ts-ignore -import { BASE_PATH, COLLECTION_FORMATS, BaseAPI, RequiredError } from './base'; +import { BASE_PATH, COLLECTION_FORMATS, BaseAPI, RequiredError, operationServerMap } from './base'; /** * @@ -1004,11 +1004,11 @@ export interface GetPartnersResponse { */ export interface GetRelationsResponse { /** - * ログインしたユーザーのAuthorID(Authorでない場合は空文字) + * ログインしたユーザーのAuthorID(Authorでない場合はundefined) * @type {string} * @memberof GetRelationsResponse */ - 'authorId': string; + 'authorId'?: string; /** * 属しているアカウントのAuthorID List(全て) * @type {Array} @@ -3368,7 +3368,9 @@ export const AccountsApiFp = function(configuration?: Configuration) { */ async activeWorktype(postActiveWorktypeRequest: PostActiveWorktypeRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.activeWorktype(postActiveWorktypeRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['AccountsApi.activeWorktype']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * ライセンス発行をキャンセルします @@ -3379,7 +3381,9 @@ export const AccountsApiFp = function(configuration?: Configuration) { */ async cancelIssue(cancelIssueRequest: CancelIssueRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.cancelIssue(cancelIssueRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['AccountsApi.cancelIssue']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * @@ -3390,7 +3394,9 @@ export const AccountsApiFp = function(configuration?: Configuration) { */ async createAccount(createAccountRequest: CreateAccountRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.createAccount(createAccountRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['AccountsApi.createAccount']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * @@ -3401,7 +3407,9 @@ export const AccountsApiFp = function(configuration?: Configuration) { */ async createPartnerAccount(createPartnerAccountRequest: CreatePartnerAccountRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.createPartnerAccount(createPartnerAccountRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['AccountsApi.createPartnerAccount']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * ログインしているユーザーのアカウント配下にタイピストグループを追加します @@ -3412,7 +3420,9 @@ export const AccountsApiFp = function(configuration?: Configuration) { */ async createTypistGroup(createTypistGroupRequest: CreateTypistGroupRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.createTypistGroup(createTypistGroupRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['AccountsApi.createTypistGroup']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * @@ -3423,7 +3433,9 @@ export const AccountsApiFp = function(configuration?: Configuration) { */ async createWorktype(createWorktypesRequest: CreateWorktypesRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.createWorktype(createWorktypesRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['AccountsApi.createWorktype']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * @@ -3434,7 +3446,9 @@ export const AccountsApiFp = function(configuration?: Configuration) { */ async deleteAccountAndData(deleteAccountRequest: DeleteAccountRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.deleteAccountAndData(deleteAccountRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['AccountsApi.deleteAccountAndData']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * @@ -3445,7 +3459,9 @@ export const AccountsApiFp = function(configuration?: Configuration) { */ async deleteWorktype(id: number, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.deleteWorktype(id, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['AccountsApi.deleteWorktype']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * @@ -3456,7 +3472,9 @@ export const AccountsApiFp = function(configuration?: Configuration) { */ async getAccountInfoMinimalAccess(getAccountInfoMinimalAccessRequest: GetAccountInfoMinimalAccessRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.getAccountInfoMinimalAccess(getAccountInfoMinimalAccessRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['AccountsApi.getAccountInfoMinimalAccess']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * ログインしているユーザーのアカウント配下のAuthor一覧を取得します @@ -3466,7 +3484,9 @@ export const AccountsApiFp = function(configuration?: Configuration) { */ async getAuthors(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.getAuthors(options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['AccountsApi.getAuthors']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * @@ -3476,7 +3496,9 @@ export const AccountsApiFp = function(configuration?: Configuration) { */ async getDealers(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.getDealers(options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['AccountsApi.getDealers']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * 指定したアカウントのライセンス集計情報を取得します @@ -3487,7 +3509,9 @@ export const AccountsApiFp = function(configuration?: Configuration) { */ async getLicenseSummary(getLicenseSummaryRequest: GetLicenseSummaryRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.getLicenseSummary(getLicenseSummaryRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['AccountsApi.getLicenseSummary']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * ログインしているユーザーのアカウント情報を取得します @@ -3497,7 +3521,9 @@ export const AccountsApiFp = function(configuration?: Configuration) { */ async getMyAccount(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.getMyAccount(options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['AccountsApi.getMyAccount']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * @@ -3508,7 +3534,9 @@ export const AccountsApiFp = function(configuration?: Configuration) { */ async getOptionItems(id: number, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.getOptionItems(id, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['AccountsApi.getOptionItems']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * @@ -3519,7 +3547,9 @@ export const AccountsApiFp = function(configuration?: Configuration) { */ async getOrderHistories(getOrderHistoriesRequest: GetOrderHistoriesRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.getOrderHistories(getOrderHistoriesRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['AccountsApi.getOrderHistories']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * @@ -3530,7 +3560,9 @@ export const AccountsApiFp = function(configuration?: Configuration) { */ async getPartnerLicenses(getPartnerLicensesRequest: GetPartnerLicensesRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.getPartnerLicenses(getPartnerLicensesRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['AccountsApi.getPartnerLicenses']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * @@ -3542,7 +3574,9 @@ export const AccountsApiFp = function(configuration?: Configuration) { */ async getPartners(limit: number, offset: number, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.getPartners(limit, offset, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['AccountsApi.getPartners']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * ログインしているユーザーのアカウント配下でIDで指定されたタイピストグループを取得します @@ -3553,7 +3587,9 @@ export const AccountsApiFp = function(configuration?: Configuration) { */ async getTypistGroup(typistGroupId: number, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.getTypistGroup(typistGroupId, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['AccountsApi.getTypistGroup']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * ログインしているユーザーのアカウント配下のタイピストグループ一覧を取得します @@ -3563,7 +3599,9 @@ export const AccountsApiFp = function(configuration?: Configuration) { */ async getTypistGroups(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.getTypistGroups(options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['AccountsApi.getTypistGroups']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * ログインしているユーザーのアカウント配下のタイピスト一覧を取得します @@ -3573,7 +3611,9 @@ export const AccountsApiFp = function(configuration?: Configuration) { */ async getTypists(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.getTypists(options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['AccountsApi.getTypists']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * @@ -3583,7 +3623,9 @@ export const AccountsApiFp = function(configuration?: Configuration) { */ async getWorktypes(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.getWorktypes(options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['AccountsApi.getWorktypes']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * @@ -3594,7 +3636,9 @@ export const AccountsApiFp = function(configuration?: Configuration) { */ async issueLicense(issueLicenseRequest: IssueLicenseRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.issueLicense(issueLicenseRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['AccountsApi.issueLicense']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * @@ -3605,7 +3649,9 @@ export const AccountsApiFp = function(configuration?: Configuration) { */ async updateAccountInfo(updateAccountInfoRequest: UpdateAccountInfoRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.updateAccountInfo(updateAccountInfoRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['AccountsApi.updateAccountInfo']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * @@ -3617,7 +3663,9 @@ export const AccountsApiFp = function(configuration?: Configuration) { */ async updateOptionItems(id: number, updateOptionItemsRequest: UpdateOptionItemsRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.updateOptionItems(id, updateOptionItemsRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['AccountsApi.updateOptionItems']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * ログインしているユーザーのアカウント配下でIDで指定されたタイピストグループを更新します @@ -3629,7 +3677,9 @@ export const AccountsApiFp = function(configuration?: Configuration) { */ async updateTypistGroup(typistGroupId: number, updateTypistGroupRequest: UpdateTypistGroupRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.updateTypistGroup(typistGroupId, updateTypistGroupRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['AccountsApi.updateTypistGroup']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * @@ -3641,7 +3691,9 @@ export const AccountsApiFp = function(configuration?: Configuration) { */ async updateWorktype(id: number, updateWorktypesRequest: UpdateWorktypesRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.updateWorktype(id, updateWorktypesRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['AccountsApi.updateWorktype']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, } }; @@ -4402,7 +4454,9 @@ export const AuthApiFp = function(configuration?: Configuration) { */ async accessToken(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.accessToken(options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['AuthApi.accessToken']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * 代行操作用のアクセストークンを再生成します @@ -4412,7 +4466,9 @@ export const AuthApiFp = function(configuration?: Configuration) { */ async delegationAccessToken(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.delegationAccessToken(options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['AuthApi.delegationAccessToken']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * 代行操作用のリフレッシュトークン・アクセストークンを生成します @@ -4423,7 +4479,9 @@ export const AuthApiFp = function(configuration?: Configuration) { */ async delegationToken(delegationTokenRequest: DelegationTokenRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.delegationToken(delegationTokenRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['AuthApi.delegationToken']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * AzureADB2Cでのサインイン後に払いだされるIDトークンを元に認証用のアクセストークンとリフレッシュトークンを生成します @@ -4434,7 +4492,9 @@ export const AuthApiFp = function(configuration?: Configuration) { */ async token(tokenRequest: TokenRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.token(tokenRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['AuthApi.token']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, } }; @@ -4597,7 +4657,9 @@ export const DefaultApiFp = function(configuration?: Configuration) { */ async checkHealth(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.checkHealth(options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['DefaultApi.checkHealth']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, } }; @@ -4897,7 +4959,9 @@ export const FilesApiFp = function(configuration?: Configuration) { */ async downloadLocation(audioFileId: number, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.downloadLocation(audioFileId, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['FilesApi.downloadLocation']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * 指定した音声ファイルに対応したテンプレートファイルのBlob Storage上のダウンロード先アクセスURLを取得します @@ -4908,7 +4972,9 @@ export const FilesApiFp = function(configuration?: Configuration) { */ async downloadTemplateLocation(audioFileId: number, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.downloadTemplateLocation(audioFileId, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['FilesApi.downloadTemplateLocation']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * アップロードが完了した音声ファイルの情報を登録し、文字起こしタスクを生成します @@ -4919,7 +4985,9 @@ export const FilesApiFp = function(configuration?: Configuration) { */ async uploadFinished(audioUploadFinishedRequest: AudioUploadFinishedRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.uploadFinished(audioUploadFinishedRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['FilesApi.uploadFinished']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * ログイン中ユーザー用のBlob Storage上の音声ファイルのアップロード先アクセスURLを取得します @@ -4929,7 +4997,9 @@ export const FilesApiFp = function(configuration?: Configuration) { */ async uploadLocation(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.uploadLocation(options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['FilesApi.uploadLocation']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * アップロードが完了したテンプレートファイルの情報を登録します @@ -4940,7 +5010,9 @@ export const FilesApiFp = function(configuration?: Configuration) { */ async uploadTemplateFinished(templateUploadFinishedRequest: TemplateUploadFinishedRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.uploadTemplateFinished(templateUploadFinishedRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['FilesApi.uploadTemplateFinished']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * ログイン中ユーザー用のBlob Storage上のテンプレートファイルのアップロード先アクセスURLを取得します @@ -4950,7 +5022,9 @@ export const FilesApiFp = function(configuration?: Configuration) { */ async uploadTemplateLocation(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.uploadTemplateLocation(options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['FilesApi.uploadTemplateLocation']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, } }; @@ -5322,7 +5396,9 @@ export const LicensesApiFp = function(configuration?: Configuration) { */ async activateCardLicenses(activateCardLicensesRequest: ActivateCardLicensesRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.activateCardLicenses(activateCardLicensesRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['LicensesApi.activateCardLicenses']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * ライセンス注文をキャンセルします @@ -5333,7 +5409,9 @@ export const LicensesApiFp = function(configuration?: Configuration) { */ async cancelOrder(cancelOrderRequest: CancelOrderRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.cancelOrder(cancelOrderRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['LicensesApi.cancelOrder']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * @@ -5344,7 +5422,9 @@ export const LicensesApiFp = function(configuration?: Configuration) { */ async createOrders(createOrdersRequest: CreateOrdersRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.createOrders(createOrdersRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['LicensesApi.createOrders']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * 割り当て可能なライセンスを取得します @@ -5354,7 +5434,9 @@ export const LicensesApiFp = function(configuration?: Configuration) { */ async getAllocatableLicenses(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.getAllocatableLicenses(options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['LicensesApi.getAllocatableLicenses']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * @@ -5365,7 +5447,9 @@ export const LicensesApiFp = function(configuration?: Configuration) { */ async issueCardLicenses(issueCardLicensesRequest: IssueCardLicensesRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.issueCardLicenses(issueCardLicensesRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['LicensesApi.issueCardLicenses']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, } }; @@ -5563,7 +5647,9 @@ export const NotificationApiFp = function(configuration?: Configuration) { */ async register(registerRequest: RegisterRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.register(registerRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['NotificationApi.register']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, } }; @@ -5903,44 +5989,6 @@ export const TasksApiAxiosParamCreator = function (configuration?: Configuration - setSearchParams(localVarUrlObj, localVarQueryParameter); - let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; - localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; - - return { - url: toPathString(localVarUrlObj), - options: localVarRequestOptions, - }; - }, - /** - * 指定した文字起こしタスクを差し戻します(ステータスをPendingにします) - * @summary - * @param {number} audioFileId ODMS Cloud上の音声ファイルID - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - sendBack: async (audioFileId: number, options: AxiosRequestConfig = {}): Promise => { - // verify required parameter 'audioFileId' is not null or undefined - assertParamExists('sendBack', 'audioFileId', audioFileId) - const localVarPath = `/tasks/{audioFileId}/send-back` - .replace(`{${"audioFileId"}}`, encodeURIComponent(String(audioFileId))); - // use dummy base URL string because the URL constructor only accepts absolute URLs. - const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); - let baseOptions; - if (configuration) { - baseOptions = configuration.baseOptions; - } - - const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; - const localVarHeaderParameter = {} as any; - const localVarQueryParameter = {} as any; - - // authentication bearer required - // http bearer authentication required - await setBearerAuthToObject(localVarHeaderParameter, configuration) - - - setSearchParams(localVarUrlObj, localVarQueryParameter); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; @@ -6007,7 +6055,9 @@ export const TasksApiFp = function(configuration?: Configuration) { */ async backup(audioFileId: number, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.backup(audioFileId, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['TasksApi.backup']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * 指定した文字起こしタスクをキャンセルします(ステータスをUploadedにします) @@ -6018,7 +6068,9 @@ export const TasksApiFp = function(configuration?: Configuration) { */ async cancel(audioFileId: number, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.cancel(audioFileId, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['TasksApi.cancel']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * 指定した文字起こしタスクのチェックアウト候補を変更します。 @@ -6030,7 +6082,9 @@ export const TasksApiFp = function(configuration?: Configuration) { */ async changeCheckoutPermission(audioFileId: number, postCheckoutPermissionRequest: PostCheckoutPermissionRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.changeCheckoutPermission(audioFileId, postCheckoutPermissionRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['TasksApi.changeCheckoutPermission']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * 指定した文字起こしタスクをチェックインします(ステータスをFinishedにします) @@ -6041,7 +6095,9 @@ export const TasksApiFp = function(configuration?: Configuration) { */ async checkin(audioFileId: number, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.checkin(audioFileId, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['TasksApi.checkin']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * 指定した文字起こしタスクをチェックアウトします(ステータスをInprogressにします) @@ -6052,7 +6108,9 @@ export const TasksApiFp = function(configuration?: Configuration) { */ async checkout(audioFileId: number, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.checkout(audioFileId, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['TasksApi.checkout']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * 指定した文字起こしタスクの次のタスクに紐づく音声ファイルIDを取得します @@ -6063,7 +6121,9 @@ export const TasksApiFp = function(configuration?: Configuration) { */ async getNextAudioFile(endedFileId: number, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.getNextAudioFile(endedFileId, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['TasksApi.getNextAudioFile']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * 音声ファイル・文字起こしタスク情報をページ指定して取得します @@ -6078,18 +6138,9 @@ export const TasksApiFp = function(configuration?: Configuration) { */ async getTasks(limit?: number, offset?: number, status?: string, direction?: string, paramName?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.getTasks(limit, offset, status, direction, paramName, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); - }, - /** - * 指定した文字起こしタスクを差し戻します(ステータスをPendingにします) - * @summary - * @param {number} audioFileId ODMS Cloud上の音声ファイルID - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - async sendBack(audioFileId: number, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.sendBack(audioFileId, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['TasksApi.getTasks']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * 指定した文字起こしタスクを一時中断します(ステータスをPendingにします) @@ -6100,7 +6151,9 @@ export const TasksApiFp = function(configuration?: Configuration) { */ async suspend(audioFileId: number, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.suspend(audioFileId, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['TasksApi.suspend']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, } }; @@ -6187,16 +6240,6 @@ export const TasksApiFactory = function (configuration?: Configuration, basePath getTasks(limit?: number, offset?: number, status?: string, direction?: string, paramName?: string, options?: any): AxiosPromise { return localVarFp.getTasks(limit, offset, status, direction, paramName, options).then((request) => request(axios, basePath)); }, - /** - * 指定した文字起こしタスクを差し戻します(ステータスをPendingにします) - * @summary - * @param {number} audioFileId ODMS Cloud上の音声ファイルID - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - sendBack(audioFileId: number, options?: any): AxiosPromise { - return localVarFp.sendBack(audioFileId, options).then((request) => request(axios, basePath)); - }, /** * 指定した文字起こしタスクを一時中断します(ステータスをPendingにします) * @summary @@ -6306,18 +6349,6 @@ export class TasksApi extends BaseAPI { return TasksApiFp(this.configuration).getTasks(limit, offset, status, direction, paramName, options).then((request) => request(this.axios, this.basePath)); } - /** - * 指定した文字起こしタスクを差し戻します(ステータスをPendingにします) - * @summary - * @param {number} audioFileId ODMS Cloud上の音声ファイルID - * @param {*} [options] Override http request option. - * @throws {RequiredError} - * @memberof TasksApi - */ - public sendBack(audioFileId: number, options?: AxiosRequestConfig) { - return TasksApiFp(this.configuration).sendBack(audioFileId, options).then((request) => request(this.axios, this.basePath)); - } - /** * 指定した文字起こしタスクを一時中断します(ステータスをPendingにします) * @summary @@ -6391,7 +6422,9 @@ export const TemplatesApiFp = function(configuration?: Configuration) { */ async getTemplates(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.getTemplates(options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['TemplatesApi.getTemplates']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, } }; @@ -6490,7 +6523,9 @@ export const TermsApiFp = function(configuration?: Configuration) { */ async getTermsInfo(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.getTermsInfo(options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['TermsApi.getTermsInfo']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, } }; @@ -7004,7 +7039,9 @@ export const UsersApiFp = function(configuration?: Configuration) { */ async allocateLicense(allocateLicenseRequest: AllocateLicenseRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.allocateLicense(allocateLicenseRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['UsersApi.allocateLicense']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * @@ -7015,7 +7052,9 @@ export const UsersApiFp = function(configuration?: Configuration) { */ async confirmUser(confirmRequest: ConfirmRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.confirmUser(confirmRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['UsersApi.confirmUser']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * @@ -7026,7 +7065,9 @@ export const UsersApiFp = function(configuration?: Configuration) { */ async confirmUserAndInitPassword(confirmRequest: ConfirmRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.confirmUserAndInitPassword(confirmRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['UsersApi.confirmUserAndInitPassword']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * ライセンス割り当てを解除します @@ -7037,7 +7078,9 @@ export const UsersApiFp = function(configuration?: Configuration) { */ async deallocateLicense(deallocateLicenseRequest: DeallocateLicenseRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.deallocateLicense(deallocateLicenseRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['UsersApi.deallocateLicense']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * ログインしているユーザーの情報を取得します @@ -7047,7 +7090,9 @@ export const UsersApiFp = function(configuration?: Configuration) { */ async getMyUser(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.getMyUser(options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['UsersApi.getMyUser']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * ログインしているユーザーに関連する各種情報を取得します @@ -7057,7 +7102,9 @@ export const UsersApiFp = function(configuration?: Configuration) { */ async getRelations(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.getRelations(options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['UsersApi.getRelations']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * ログインしているユーザーのタスクソート条件を取得します @@ -7067,7 +7114,9 @@ export const UsersApiFp = function(configuration?: Configuration) { */ async getSortCriteria(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.getSortCriteria(options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['UsersApi.getSortCriteria']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * @@ -7077,7 +7126,9 @@ export const UsersApiFp = function(configuration?: Configuration) { */ async getUsers(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.getUsers(options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['UsersApi.getUsers']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * @@ -7088,7 +7139,9 @@ export const UsersApiFp = function(configuration?: Configuration) { */ async signup(signupRequest: SignupRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.signup(signupRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['UsersApi.signup']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * 利用規約同意バージョンを更新 @@ -7099,7 +7152,9 @@ export const UsersApiFp = function(configuration?: Configuration) { */ async updateAcceptedVersion(updateAcceptedVersionRequest: UpdateAcceptedVersionRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.updateAcceptedVersion(updateAcceptedVersionRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['UsersApi.updateAcceptedVersion']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * ログインしているユーザーのタスクソート条件を更新します @@ -7110,7 +7165,9 @@ export const UsersApiFp = function(configuration?: Configuration) { */ async updateSortCriteria(postSortCriteriaRequest: PostSortCriteriaRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.updateSortCriteria(postSortCriteriaRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['UsersApi.updateSortCriteria']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * ユーザーの情報を更新します @@ -7121,7 +7178,9 @@ export const UsersApiFp = function(configuration?: Configuration) { */ async updateUser(postUpdateUserRequest: PostUpdateUserRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.updateUser(postUpdateUserRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['UsersApi.updateUser']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, } }; @@ -7583,7 +7642,9 @@ export const WorkflowsApiFp = function(configuration?: Configuration) { */ async createWorkflows(createWorkflowsRequest: CreateWorkflowsRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.createWorkflows(createWorkflowsRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['WorkflowsApi.createWorkflows']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * アカウント内のワークフローを削除します @@ -7594,7 +7655,9 @@ export const WorkflowsApiFp = function(configuration?: Configuration) { */ async deleteWorkflow(workflowId: number, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.deleteWorkflow(workflowId, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['WorkflowsApi.deleteWorkflow']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * アカウント内のワークフローの一覧を取得します @@ -7604,7 +7667,9 @@ export const WorkflowsApiFp = function(configuration?: Configuration) { */ async getWorkflows(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.getWorkflows(options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['WorkflowsApi.getWorkflows']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, /** * アカウント内のワークフローを編集します @@ -7616,7 +7681,9 @@ export const WorkflowsApiFp = function(configuration?: Configuration) { */ async updateWorkflow(workflowId: number, updateWorkflowRequest: UpdateWorkflowRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.updateWorkflow(workflowId, updateWorkflowRequest, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['WorkflowsApi.updateWorkflow']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, } }; diff --git a/dictation_client/src/api/base.ts b/dictation_client/src/api/base.ts index 0a09f9c..4e44af5 100644 --- a/dictation_client/src/api/base.ts +++ b/dictation_client/src/api/base.ts @@ -53,7 +53,7 @@ export class BaseAPI { constructor(configuration?: Configuration, protected basePath: string = BASE_PATH, protected axios: AxiosInstance = globalAxios) { if (configuration) { this.configuration = configuration; - this.basePath = configuration.basePath || this.basePath; + this.basePath = configuration.basePath ?? basePath; } } }; @@ -70,3 +70,17 @@ export class RequiredError extends Error { this.name = "RequiredError" } } + +interface ServerMap { + [key: string]: { + url: string, + description: string, + }[]; +} + +/** + * + * @export + */ +export const operationServerMap: ServerMap = { +} diff --git a/dictation_client/src/api/configuration.ts b/dictation_client/src/api/configuration.ts index eabe78f..9941122 100644 --- a/dictation_client/src/api/configuration.ts +++ b/dictation_client/src/api/configuration.ts @@ -19,6 +19,7 @@ export interface ConfigurationParameters { password?: string; accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise); basePath?: string; + serverIndex?: number; baseOptions?: any; formDataCtor?: new () => any; } @@ -58,6 +59,13 @@ export class Configuration { * @memberof Configuration */ basePath?: string; + /** + * override server index + * + * @type {number} + * @memberof Configuration + */ + serverIndex?: number; /** * base options for axios calls * @@ -80,6 +88,7 @@ export class Configuration { this.password = param.password; this.accessToken = param.accessToken; this.basePath = param.basePath; + this.serverIndex = param.serverIndex; this.baseOptions = param.baseOptions; this.formDataCtor = param.formDataCtor; } diff --git a/dictation_server/src/api/odms/openapi.json b/dictation_server/src/api/odms/openapi.json index cea7c44..e112ae2 100644 --- a/dictation_server/src/api/odms/openapi.json +++ b/dictation_server/src/api/odms/openapi.json @@ -2689,68 +2689,6 @@ "security": [{ "bearer": [] }] } }, - "/tasks/{audioFileId}/send-back": { - "post": { - "operationId": "sendBack", - "summary": "", - "description": "指定した文字起こしタスクを差し戻します(ステータスをPendingにします)", - "parameters": [ - { - "name": "audioFileId", - "required": true, - "in": "path", - "description": "ODMS Cloud上の音声ファイルID", - "schema": { "type": "number" } - } - ], - "responses": { - "200": { - "description": "成功時のレスポンス", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ChangeStatusResponse" - } - } - } - }, - "400": { - "description": "不正なパラメータ", - "content": { - "application/json": { - "schema": { "$ref": "#/components/schemas/ErrorResponse" } - } - } - }, - "401": { - "description": "認証エラー", - "content": { - "application/json": { - "schema": { "$ref": "#/components/schemas/ErrorResponse" } - } - } - }, - "404": { - "description": "指定したIDの音声ファイルが存在しない場合", - "content": { - "application/json": { - "schema": { "$ref": "#/components/schemas/ErrorResponse" } - } - } - }, - "500": { - "description": "想定外のサーバーエラー", - "content": { - "application/json": { - "schema": { "$ref": "#/components/schemas/ErrorResponse" } - } - } - } - }, - "tags": ["tasks"], - "security": [{ "bearer": [] }] - } - }, "/tasks/{audioFileId}/backup": { "post": { "operationId": "backup", diff --git a/dictation_server/src/features/tasks/tasks.controller.ts b/dictation_server/src/features/tasks/tasks.controller.ts index c1e8b0d..2b976b2 100644 --- a/dictation_server/src/features/tasks/tasks.controller.ts +++ b/dictation_server/src/features/tasks/tasks.controller.ts @@ -462,45 +462,6 @@ export class TasksController { return {}; } - @Post(':audioFileId/send-back') - @ApiResponse({ - status: HttpStatus.OK, - type: ChangeStatusResponse, - description: '成功時のレスポンス', - }) - @ApiResponse({ - status: HttpStatus.BAD_REQUEST, - description: '不正なパラメータ', - type: ErrorResponse, - }) - @ApiResponse({ - status: HttpStatus.NOT_FOUND, - description: '指定したIDの音声ファイルが存在しない場合', - type: ErrorResponse, - }) - @ApiResponse({ - status: HttpStatus.UNAUTHORIZED, - description: '認証エラー', - type: ErrorResponse, - }) - @ApiResponse({ - status: HttpStatus.INTERNAL_SERVER_ERROR, - description: '想定外のサーバーエラー', - type: ErrorResponse, - }) - @ApiOperation({ - operationId: 'sendBack', - description: - '指定した文字起こしタスクを差し戻します(ステータスをPendingにします)', - }) - @ApiBearerAuth() - async sendBack( - @Headers() headers, - @Param() params: ChangeStatusRequest, - ): Promise { - return {}; - } - @Post(':audioFileId/backup') @ApiResponse({ status: HttpStatus.OK, @@ -533,10 +494,37 @@ export class TasksController { '指定した文字起こしタスクをバックアップします(ステータスをBackupにします)', }) @ApiBearerAuth() + @UseGuards(AuthGuard) + @UseGuards( + RoleGuard.requireds({ + roles: [ADMIN_ROLES.ADMIN], + }), + ) async backup( - @Headers() headers, + @Req() req: Request, @Param() params: ChangeStatusRequest, ): Promise { + const { audioFileId } = params; + + const accessToken = retrieveAuthorizationToken(req); + if (!accessToken) { + throw new HttpException( + makeErrorResponse('E000107'), + HttpStatus.UNAUTHORIZED, + ); + } + const decodedAccessToken = jwt.decode(accessToken, { json: true }); + if (!decodedAccessToken) { + throw new HttpException( + makeErrorResponse('E000101'), + HttpStatus.UNAUTHORIZED, + ); + } + const { userId } = decodedAccessToken as AccessToken; + + const context = makeContext(userId); + + await this.taskService.backup(context, audioFileId, userId); return {}; } diff --git a/dictation_server/src/features/tasks/tasks.service.spec.ts b/dictation_server/src/features/tasks/tasks.service.spec.ts index c74de6b..cb8ac34 100644 --- a/dictation_server/src/features/tasks/tasks.service.spec.ts +++ b/dictation_server/src/features/tasks/tasks.service.spec.ts @@ -36,6 +36,7 @@ import { import { createTemplateFile } from '../templates/test/utility'; import { NotificationhubService } from '../../gateways/notificationhub/notificationhub.service'; import { Roles } from '../../common/types/role'; +import { TasksRepositoryService } from '../../repositories/tasks/tasks.repository.service'; describe('TasksService', () => { it('タスク一覧を取得できる(admin)', async () => { @@ -2972,6 +2973,300 @@ describe('cancel', () => { }); }); +describe('backup', () => { + let source: DataSource | null = null; + beforeEach(async () => { + source = new DataSource({ + type: 'sqlite', + database: ':memory:', + logging: false, + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: true, // trueにすると自動的にmigrationが行われるため注意 + }); + return source.initialize(); + }); + + afterEach(async () => { + if (!source) return; + await source.destroy(); + source = null; + }); + + it('文字起こし完了のタスクをバックアップできる', async () => { + if (!source) fail(); + const module = await makeTestingModule(source); + if (!module) fail(); + const { account, admin } = await makeTestAccount(source); + const { id: authorUserId } = await makeTestUser(source, { + account_id: account.id, + external_id: 'author-user-external-id', + role: 'author', + author_id: 'MY_AUTHOR_ID', + }); + const { id: typistUserId } = await makeTestUser(source, { + account_id: account.id, + external_id: 'typist-user-external-id', + role: 'typist', + }); + + const { taskId, audioFileId } = await createTask( + source, + account.id, + authorUserId, + 'MY_AUTHOR_ID', + '', + '01', + '00000001', + TASK_STATUS.FINISHED, + typistUserId, + ); + + // 作成したデータを確認 + { + const task = await getTask(source, taskId); + expect(task?.status).toBe(TASK_STATUS.FINISHED); + expect(task?.is_job_number_enabled).toBe(true); + } + + const service = module.get(TasksService); + await service.backup( + makeContext(admin.external_id), + audioFileId, + admin.external_id, + ); + + // バックアップしたデータを確認 + { + const task = await getTask(source, taskId); + expect(task?.status).toBe(TASK_STATUS.BACKUP); + expect(task?.is_job_number_enabled).toBe(false); + } + }); + + it('文字起こしバックアップ済みのタスクをバックアップできる', async () => { + if (!source) fail(); + const module = await makeTestingModule(source); + if (!module) fail(); + const { account, admin } = await makeTestAccount(source); + const { id: authorUserId } = await makeTestUser(source, { + account_id: account.id, + external_id: 'author-user-external-id', + role: 'author', + author_id: 'MY_AUTHOR_ID', + }); + const { id: typistUserId } = await makeTestUser(source, { + account_id: account.id, + external_id: 'typist-user-external-id', + role: 'typist', + }); + + const { taskId, audioFileId } = await createTask( + source, + account.id, + authorUserId, + 'MY_AUTHOR_ID', + '', + '01', + '00000001', + TASK_STATUS.BACKUP, + typistUserId, + false, + ); + + // 作成したデータを確認 + { + const task = await getTask(source, taskId); + expect(task?.status).toBe(TASK_STATUS.BACKUP); + expect(task?.is_job_number_enabled).toBe(false); + } + + const service = module.get(TasksService); + await service.backup( + makeContext(admin.external_id), + audioFileId, + admin.external_id, + ); + + // バックアップしたデータを確認 + { + const task = await getTask(source, taskId); + expect(task?.status).toBe(TASK_STATUS.BACKUP); + expect(task?.is_job_number_enabled).toBe(false); + } + }); + + it('タスクのステータスが[Finished,Backup]でない時、エラーを返却する', async () => { + if (!source) fail(); + const module = await makeTestingModule(source); + if (!module) fail(); + const { account, admin } = await makeTestAccount(source); + const { id: authorUserId } = await makeTestUser(source, { + account_id: account.id, + external_id: 'author-user-external-id', + role: 'author', + author_id: 'MY_AUTHOR_ID', + }); + const { id: typistUserId } = await makeTestUser(source, { + account_id: account.id, + external_id: 'typist-user-external-id', + role: 'typist', + }); + + const { taskId, audioFileId } = await createTask( + source, + account.id, + authorUserId, + 'MY_AUTHOR_ID', + '', + '01', + '00000001', + TASK_STATUS.IN_PROGRESS, + typistUserId, + ); + + // 作成したデータを確認 + { + const task = await getTask(source, taskId); + expect(task?.status).toBe(TASK_STATUS.IN_PROGRESS); + expect(task?.is_job_number_enabled).toBe(true); + } + + const service = module.get(TasksService); + + try { + await service.backup( + makeContext(admin.external_id), + audioFileId, + admin.external_id, + ); + fail(); + } catch (e) { + if (e instanceof HttpException) { + expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); + expect(e.getResponse()).toEqual(makeErrorResponse('E010601')); + } else { + fail(); + } + } + }); + + it('指定タスクが存在しない時、エラーを返却する', async () => { + if (!source) fail(); + const module = await makeTestingModule(source); + if (!module) fail(); + const { account, admin } = await makeTestAccount(source); + const { id: authorUserId } = await makeTestUser(source, { + account_id: account.id, + external_id: 'author-user-external-id', + role: 'author', + author_id: 'MY_AUTHOR_ID', + }); + const { id: typistUserId } = await makeTestUser(source, { + account_id: account.id, + external_id: 'typist-user-external-id', + role: 'typist', + }); + + const { taskId } = await createTask( + source, + account.id, + authorUserId, + 'MY_AUTHOR_ID', + '', + '01', + '00000001', + TASK_STATUS.FINISHED, + typistUserId, + ); + + // 作成したデータを確認 + { + const task = await getTask(source, taskId); + expect(task?.status).toBe(TASK_STATUS.FINISHED); + expect(task?.is_job_number_enabled).toBe(true); + } + + const service = module.get(TasksService); + + try { + await service.backup( + makeContext(admin.external_id), + 9999, // 存在しないタスクID + admin.external_id, + ); + fail(); + } catch (e) { + if (e instanceof HttpException) { + expect(e.getStatus()).toEqual(HttpStatus.NOT_FOUND); + expect(e.getResponse()).toEqual(makeErrorResponse('E010603')); + } else { + fail(); + } + } + }); + + it('DBアクセスに失敗した場合、エラーを返却する', async () => { + if (!source) fail(); + const module = await makeTestingModule(source); + if (!module) fail(); + const { account, admin } = await makeTestAccount(source); + const { id: authorUserId } = await makeTestUser(source, { + account_id: account.id, + external_id: 'author-user-external-id', + role: 'author', + author_id: 'MY_AUTHOR_ID', + }); + const { id: typistUserId } = await makeTestUser(source, { + account_id: account.id, + external_id: 'typist-user-external-id', + role: 'typist', + }); + + const { taskId, audioFileId } = await createTask( + source, + account.id, + authorUserId, + 'MY_AUTHOR_ID', + '', + '01', + '00000001', + TASK_STATUS.FINISHED, + typistUserId, + ); + + // 作成したデータを確認 + { + const task = await getTask(source, taskId); + expect(task?.status).toBe(TASK_STATUS.FINISHED); + expect(task?.is_job_number_enabled).toBe(true); + } + + const service = module.get(TasksService); + + //DBアクセスに失敗するようにする + const tasksService = module.get( + TasksRepositoryService, + ); + tasksService.backup = jest.fn().mockRejectedValue('DB failed'); + + try { + await service.backup( + makeContext(admin.external_id), + audioFileId, + admin.external_id, + ); + fail(); + } catch (e) { + if (e instanceof HttpException) { + expect(e.getStatus()).toEqual(HttpStatus.INTERNAL_SERVER_ERROR); + expect(e.getResponse()).toEqual(makeErrorResponse('E009999')); + } else { + fail(); + } + } + }); +}); + describe('getNextTask', () => { let source: DataSource | null = null; beforeEach(async () => { diff --git a/dictation_server/src/features/tasks/tasks.service.ts b/dictation_server/src/features/tasks/tasks.service.ts index 0801572..1a26637 100644 --- a/dictation_server/src/features/tasks/tasks.service.ts +++ b/dictation_server/src/features/tasks/tasks.service.ts @@ -546,6 +546,61 @@ export class TasksService { } } + /** + * 指定した音声ファイルに紐づくタスクをbackupする + * @param context + * @param audioFileId + * @param externalId + * @returns backup + */ + async backup( + context: Context, + audioFileId: number, + externalId: string, + ): Promise { + try { + this.logger.log( + `[IN] [${context.getTrackingId()}] ${ + this.backup.name + } | params: { audioFileId: ${audioFileId}, externalId: ${externalId} };`, + ); + const { account_id: accountId } = + await this.usersRepository.findUserByExternalId(externalId); + + await this.taskRepository.backup(accountId, audioFileId, [ + TASK_STATUS.FINISHED, + TASK_STATUS.BACKUP, + ]); + } catch (e) { + this.logger.error(`[${context.getTrackingId()}] error=${e}`); + if (e instanceof Error) { + switch (e.constructor) { + case TasksNotFoundError: + throw new HttpException( + makeErrorResponse('E010603'), + HttpStatus.NOT_FOUND, + ); + case StatusNotMatchError: + throw new HttpException( + makeErrorResponse('E010601'), + HttpStatus.BAD_REQUEST, + ); + default: + throw new HttpException( + makeErrorResponse('E009999'), + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + } + throw new HttpException( + makeErrorResponse('E009999'), + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } finally { + this.logger.log(`[OUT] [${context.getTrackingId()}] ${this.backup.name}`); + } + } + private async getB2cUsers( context: Context, tasks: TaskEntity[], diff --git a/dictation_server/src/features/tasks/test/utility.ts b/dictation_server/src/features/tasks/test/utility.ts index 705c0bd..b4de930 100644 --- a/dictation_server/src/features/tasks/test/utility.ts +++ b/dictation_server/src/features/tasks/test/utility.ts @@ -110,6 +110,7 @@ export const createTask = async ( jobNumber: string, status: string, typist_user_id?: number | undefined, + is_job_number_enabled?: boolean | undefined, ): Promise<{ taskId: number; audioFileId: number }> => { const { identifiers: audioFileIdentifiers } = await datasource .getRepository(AudioFile) @@ -135,7 +136,7 @@ export const createTask = async ( .insert({ job_number: jobNumber, account_id: account_id, - is_job_number_enabled: true, + is_job_number_enabled: is_job_number_enabled ?? true, audio_file_id: audioFile.id, status: status, typist_user_id: typist_user_id, diff --git a/dictation_server/src/repositories/tasks/entity/task.entity.ts b/dictation_server/src/repositories/tasks/entity/task.entity.ts index 7abb66f..373ee78 100644 --- a/dictation_server/src/repositories/tasks/entity/task.entity.ts +++ b/dictation_server/src/repositories/tasks/entity/task.entity.ts @@ -23,7 +23,7 @@ export class Task { job_number: string; @Column() account_id: number; - @Column({ nullable: true, type: 'tinyint' }) + @Column({ nullable: true, type: 'boolean' }) is_job_number_enabled: boolean | null; @Column() audio_file_id: number; diff --git a/dictation_server/src/repositories/tasks/tasks.repository.service.ts b/dictation_server/src/repositories/tasks/tasks.repository.service.ts index 3e6fd6f..d543609 100644 --- a/dictation_server/src/repositories/tasks/tasks.repository.service.ts +++ b/dictation_server/src/repositories/tasks/tasks.repository.service.ts @@ -425,6 +425,52 @@ export class TasksRepositoryService { }); } + /** + * 音声ファイルIDで指定したタスクをbackupする + * @param accountId バックアップするタスクのアカウントID + * @param audio_file_id バックアップするタスクの音声ファイルID + * @param permittedSourceStatus バックアップ可能なステータス + * @returns backup + */ + async backup( + accountId: number, + audio_file_id: number, + permittedSourceStatus: TaskStatus[], + ): Promise { + await this.dataSource.transaction(async (entityManager) => { + const taskRepo = entityManager.getRepository(Task); + const task = await taskRepo.findOne({ + where: { + account_id: accountId, + audio_file_id: audio_file_id, + }, + }); + if (!task) { + throw new TasksNotFoundError( + `task not found. audio_file_id:${audio_file_id}`, + ); + } + + if (!isTaskStatus(task.status)) { + throw new Error(`invalid task status. status:${task.status}`); + } + if (!permittedSourceStatus.includes(task.status)) { + throw new StatusNotMatchError( + `Unexpected task status. status:${task.status}`, + ); + } + + // ステータスをバックアップに更新、JobNumberを無効化 + await taskRepo.update( + { audio_file_id: audio_file_id }, + { + status: TASK_STATUS.BACKUP, + is_job_number_enabled: false, + }, + ); + }); + } + /** * 指定したアカウントIDに紐づくTask関連情報の一覧を取得します * @param account_id From f38733f9b2eafd57bd9fb9a129ed0ab23c5a9c3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B9=AF=E6=9C=AC=20=E9=96=8B?= Date: Tue, 21 Nov 2023 10:48:57 +0000 Subject: [PATCH 5/6] =?UTF-8?q?Merged=20PR=20589:=20=E3=83=A9=E3=82=A4?= =?UTF-8?q?=E3=82=BB=E3=83=B3=E3=82=B9=E3=83=81=E3=82=A7=E3=83=83=E3=82=AF?= =?UTF-8?q?=E5=87=A6=E7=90=86=E3=82=92licenses=E3=81=BE=E3=81=9F=E3=81=AFu?= =?UTF-8?q?sers=E9=85=8D=E4=B8=8B=E3=81=AB=E7=A7=BB=E5=8B=95=E3=81=97?= =?UTF-8?q?=E3=81=A6=E5=85=B1=E9=80=9A=E9=83=A8=E5=93=81=E5=8C=96=E3=81=99?= =?UTF-8?q?=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 概要 [Task3084: ライセンスチェック処理をlicensesまたはusers配下に移動して共通部品化する](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/3084) - "チェック"する関数でなく、ライセンスの割当状態を取得する関数に変更 - 利用側では、割当状態を元にして必要なら例外をthrowする実装に変更 - 関数の機能を `LicensesRepository` が提供する形に変更 ## レビューポイント - 関数のシグネチャは問題なさそうか ## 動作確認状況 - テストは通過 --- .../src/features/files/files.module.ts | 2 + .../src/features/files/files.service.ts | 86 ++++++------------- .../licenses/licenses.repository.service.ts | 35 ++++++++ .../users/users.repository.service.ts | 18 ---- 4 files changed, 61 insertions(+), 80 deletions(-) diff --git a/dictation_server/src/features/files/files.module.ts b/dictation_server/src/features/files/files.module.ts index d5ca8cc..56ba499 100644 --- a/dictation_server/src/features/files/files.module.ts +++ b/dictation_server/src/features/files/files.module.ts @@ -9,6 +9,7 @@ import { BlobstorageModule } from '../../gateways/blobstorage/blobstorage.module import { TemplateFilesRepositoryModule } from '../../repositories/template_files/template_files.repository.module'; import { UserGroupsRepositoryModule } from '../../repositories/user_groups/user_groups.repository.module'; import { NotificationhubModule } from '../../gateways/notificationhub/notificationhub.module'; +import { LicensesRepositoryModule } from '../../repositories/licenses/licenses.repository.module'; @Module({ imports: [ @@ -20,6 +21,7 @@ import { NotificationhubModule } from '../../gateways/notificationhub/notificati TemplateFilesRepositoryModule, UserGroupsRepositoryModule, NotificationhubModule, + LicensesRepositoryModule, ], providers: [FilesService], controllers: [FilesController], diff --git a/dictation_server/src/features/files/files.service.ts b/dictation_server/src/features/files/files.service.ts index ae441af..0699419 100644 --- a/dictation_server/src/features/files/files.service.ts +++ b/dictation_server/src/features/files/files.service.ts @@ -35,7 +35,7 @@ import { LicenseExpiredError, LicenseNotAllocatedError, } from '../../repositories/licenses/errors/types'; -import { DateWithZeroTime } from '../licenses/types/types'; +import { LicensesRepositoryService } from '../../repositories/licenses/licenses.repository.service'; @Injectable() export class FilesService { @@ -48,6 +48,7 @@ export class FilesService { private readonly blobStorageService: BlobstorageService, private readonly userGroupsRepositoryService: UserGroupsRepositoryService, private readonly notificationhubService: NotificationhubService, + private readonly licensesRepository: LicensesRepositoryService, ) {} /** @@ -295,13 +296,16 @@ export class FilesService { if (user.account.locked) { throw new AccountLockedError('account is locked.'); } - // ライセンスの有効性をチェック - const { licenseError } = await this.checkLicenseValidityByUserId( - context, + + // ライセンスが有効でない場合、エラー + const { state } = await this.licensesRepository.getLicenseState( user.id, ); - if (licenseError) { - throw licenseError; + if (state === 'expired') { + throw new LicenseExpiredError('license is expired.'); + } + if (state === 'inallocated') { + throw new LicenseNotAllocatedError('license is not allocated.'); } } // 国に応じたリージョンのBlobストレージにコンテナが存在するか確認 @@ -379,13 +383,15 @@ export class FilesService { } // 第五階層のみチェック if (user.account.tier === TIERS.TIER5) { - // ライセンスの有効性をチェック - const { licenseError } = await this.checkLicenseValidityByUserId( - context, + // ライセンスが有効でない場合、エラー + const { state } = await this.licensesRepository.getLicenseState( user.id, ); - if (licenseError) { - throw licenseError; + if (state === 'expired') { + throw new LicenseExpiredError('license is expired.'); + } + if (state === 'inallocated') { + throw new LicenseNotAllocatedError('license is not allocated.'); } } accountId = user.account.id; @@ -545,13 +551,15 @@ export class FilesService { } // 第五階層のみチェック if (user.account.tier === TIERS.TIER5) { - // ライセンスの有効性をチェック - const { licenseError } = await this.checkLicenseValidityByUserId( - context, + // ライセンスが有効でない場合、エラー + const { state } = await this.licensesRepository.getLicenseState( user.id, ); - if (licenseError) { - throw licenseError; + if (state === 'expired') { + throw new LicenseExpiredError('license is expired.'); + } + if (state === 'inallocated') { + throw new LicenseNotAllocatedError('license is not allocated.'); } } accountId = user.account_id; @@ -801,50 +809,4 @@ export class FilesService { ); } } - - /** - * ユーザーに割り当てられているライセンスの有効性をチェックする。 - * ライセンスが割り当てられていない場合、またはライセンスが有効期限切れの場合、エラー返却する。 - * @param userId - * @returns licenseError? - */ - // TODO: TASK3084で共通部品化する - private async checkLicenseValidityByUserId( - context: Context, - userId: number, - ): Promise<{ licenseError?: Error }> { - this.logger.log( - `[IN] [${context.getTrackingId()}] ${ - this.checkLicenseValidityByUserId.name - } | params: { userId: ${userId} };`, - ); - try { - const allocatedLicense = await this.usersRepository.findLicenseByUserId( - userId, - ); - - if (!allocatedLicense) { - return { - licenseError: new LicenseNotAllocatedError( - 'license is not allocated.', - ), - }; - } else { - const currentDate = new DateWithZeroTime(); - if ( - allocatedLicense.expiry_date && - allocatedLicense.expiry_date < currentDate - ) { - return { - licenseError: new LicenseExpiredError('license is expired.'), - }; - } - } - - return {}; // エラーがない場合は空のオブジェクトを返す - } catch (e) { - // リポジトリ層のエラーやその他の例外をハンドリング - return e; - } - } } diff --git a/dictation_server/src/repositories/licenses/licenses.repository.service.ts b/dictation_server/src/repositories/licenses/licenses.repository.service.ts index 6f107fc..ddac253 100644 --- a/dictation_server/src/repositories/licenses/licenses.repository.service.ts +++ b/dictation_server/src/repositories/licenses/licenses.repository.service.ts @@ -643,4 +643,39 @@ export class LicensesRepositoryService { await orderRepo.save(targetOrder); }); } + + /** + * ライセンスの割当状態を取得します + * @param userId ユーザーID + * @error { Error } DBアクセス失敗時の例外 + * @returns Promise<{ state: 'allocated' | 'inallocated' | 'expired' }> + */ + async getLicenseState( + userId: number, + ): Promise<{ state: 'allocated' | 'inallocated' | 'expired' }> { + const allocatedLicense = await this.dataSource + .getRepository(License) + .findOne({ + where: { + allocated_user_id: userId, + status: LICENSE_ALLOCATED_STATUS.ALLOCATED, + }, + }); + + // ライセンスが割り当てられていない場合は未割当状態 + if (allocatedLicense == null) { + return { state: 'inallocated' }; + } + + // ライセンスの有効期限が過ぎている場合は期限切れ状態 + const currentDate = new DateWithZeroTime(); + if ( + allocatedLicense.expiry_date && + allocatedLicense.expiry_date < currentDate + ) { + return { state: 'expired' }; + } + + return { state: 'allocated' }; + } } diff --git a/dictation_server/src/repositories/users/users.repository.service.ts b/dictation_server/src/repositories/users/users.repository.service.ts index 97787de..af179e9 100644 --- a/dictation_server/src/repositories/users/users.repository.service.ts +++ b/dictation_server/src/repositories/users/users.repository.service.ts @@ -648,24 +648,6 @@ export class UsersRepositoryService { return originAccount.delegation_permission; }); } - /** - * ユーザーに割り当てられているライセンスを取得する - * @param userId ユーザーID - * @returns License - */ - async findLicenseByUserId(userId: number): Promise { - const allocatedLicense = await this.dataSource - .getRepository(License) - .findOne({ - where: { - allocated_user_id: userId, - status: LICENSE_ALLOCATED_STATUS.ALLOCATED, - }, - }); - - return allocatedLicense; - } - /** * ユーザーに紐づく各種情報を取得する * @param userId From 501fc5a15dfd9a1f874d3660cac83f1a5c490e6e Mon Sep 17 00:00:00 2001 From: masaaki Date: Wed, 22 Nov 2023 01:13:03 +0000 Subject: [PATCH 6/6] =?UTF-8?q?Merged=20PR=20588:=20=E7=94=BB=E9=9D=A2?= =?UTF-8?q?=E5=AE=9F=E8=A3=85=EF=BC=88=E3=82=BF=E3=82=B9=E3=82=AF=E4=B8=80?= =?UTF-8?q?=E8=A6=A7=E7=94=BB=E9=9D=A2=EF=BC=9A=E3=82=BF=E3=82=B9=E3=82=AF?= =?UTF-8?q?=E3=82=AD=E3=83=A3=E3=83=B3=E3=82=BB=E3=83=AB=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 概要 [Task3131: 画面実装(タスク一覧画面:タスクキャンセル操作追加)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/3131) - タスク 3131: 画面実装(タスク一覧画面:タスクキャンセル操作追加) - タスク一覧に対してCancel Dictationボタンを実装しました ## レビューポイント - タスク関連のほかの処理で実施しているものについて、キャンセルで実施必要か確認いただきたいです。 - キャンセル後のデスクトップアプリ起動 - 不要の認識 - キャンセル前のソート条件保存 - ステータスが変わるため、必要な認識 - ログイン名を取得するためにloginのselectorを使用していますが問題ないか確認いただきたいです (他フィーチャと余計な関連を作るのはあまりよくないと思いつつ、同じような取得処理を作るのも嫌だと思いつつ。。) ## UIの変更 - https://ndstokyo.sharepoint.com/:f:/r/sites/Piranha/Shared%20Documents/General/OMDS/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88/Task3131?csf=1&web=1&e=EdWfPJ ## 動作確認状況 - ローカルで確認実施 ## 補足 - 相談、参考資料などがあれば --- .../src/features/dictation/dictationSlice.ts | 10 +++ .../src/features/dictation/operations.ts | 72 +++++++++++++++++ .../src/pages/DictationPage/index.tsx | 77 +++++++++++++++++++ dictation_client/src/translation/de.json | 7 +- dictation_client/src/translation/en.json | 7 +- dictation_client/src/translation/es.json | 7 +- dictation_client/src/translation/fr.json | 7 +- 7 files changed, 179 insertions(+), 8 deletions(-) diff --git a/dictation_client/src/features/dictation/dictationSlice.ts b/dictation_client/src/features/dictation/dictationSlice.ts index 0775825..66559fb 100644 --- a/dictation_client/src/features/dictation/dictationSlice.ts +++ b/dictation_client/src/features/dictation/dictationSlice.ts @@ -9,6 +9,7 @@ import { listTypistsAsync, playbackAsync, updateAssigneeAsync, + cancelAsync, } from "./operations"; import { SORTABLE_COLUMN, @@ -176,6 +177,15 @@ export const dictationSlice = createSlice({ builder.addCase(playbackAsync.rejected, (state) => { state.apps.isLoading = false; }); + builder.addCase(cancelAsync.pending, (state) => { + state.apps.isLoading = true; + }); + builder.addCase(cancelAsync.fulfilled, (state) => { + state.apps.isLoading = false; + }); + builder.addCase(cancelAsync.rejected, (state) => { + state.apps.isLoading = false; + }); builder.addCase(listBackupPopupTasksAsync.pending, (state) => { state.apps.isBackupListLoading = true; }); diff --git a/dictation_client/src/features/dictation/operations.ts b/dictation_client/src/features/dictation/operations.ts index e7ff81d..b78e67f 100644 --- a/dictation_client/src/features/dictation/operations.ts +++ b/dictation_client/src/features/dictation/operations.ts @@ -355,6 +355,78 @@ export const playbackAsync = createAsyncThunk< } }); +export const cancelAsync = createAsyncThunk< + { + /** empty */ + }, + { + direction: DirectionType; + paramName: SortableColumnType; + audioFileId: number; + isTypist: boolean; + }, + { + // rejectした時の返却値の型 + rejectValue: { + error: ErrorObject; + }; + } +>("dictations/cancelAsync", async (args, thunkApi) => { + const { audioFileId, direction, paramName, isTypist } = args; + + // apiのConfigurationを取得する + const { getState } = thunkApi; + const state = getState() as RootState; + const { configuration } = state.auth; + const accessToken = getAccessToken(state.auth); + const config = new Configuration(configuration); + const tasksApi = new TasksApi(config); + const usersApi = new UsersApi(config); + try { + // ユーザーがタイピストである場合に、ソート条件を保存する + if (isTypist) { + await usersApi.updateSortCriteria( + { direction, paramName }, + { + headers: { authorization: `Bearer ${accessToken}` }, + } + ); + } + await tasksApi.cancel(audioFileId, { + headers: { authorization: `Bearer ${accessToken}` }, + }); + thunkApi.dispatch( + openSnackbar({ + level: "info", + message: getTranslationID("common.message.success"), + }) + ); + return {}; + } catch (e) { + // e ⇒ errorObjectに変換" + const error = createErrorObject(e); + + // ステータスが[Inprogress,Pending]以外、またはタスクが存在しない場合、またはtypistで自分のタスクでない場合 + if (error.code === "E010601" || error.code === "E010603") { + thunkApi.dispatch( + openSnackbar({ + level: "error", + message: getTranslationID("dictationPage.message.cancelFailedError"), + }) + ); + return thunkApi.rejectWithValue({ error }); + } + + thunkApi.dispatch( + openSnackbar({ + level: "error", + message: getTranslationID("common.message.internalServerError"), + }) + ); + return thunkApi.rejectWithValue({ error }); + } +}); + export const listBackupPopupTasksAsync = createAsyncThunk< TasksResponse, { diff --git a/dictation_client/src/pages/DictationPage/index.tsx b/dictation_client/src/pages/DictationPage/index.tsx index 34df912..ce0d896 100644 --- a/dictation_client/src/pages/DictationPage/index.tsx +++ b/dictation_client/src/pages/DictationPage/index.tsx @@ -30,7 +30,9 @@ import { DirectionType, selectIsLoading, playbackAsync, + cancelAsync, } from "features/dictation"; +import { selectUserName } from "features/login/index"; import { getTranslationID } from "translation"; import { Task } from "api/api"; import { isAdminUser, isAuthorUser, isTypistUser } from "features/auth"; @@ -73,6 +75,9 @@ const DictationPage: React.FC = (): JSX.Element => { [dispatch, setIsChangeTranscriptionistPopupOpen] ); + // ログイン中のユーザ名 + const myName = useSelector(selectUserName); + // 各カラムの表示/非表示 const displayColumn = useSelector(selectDisplayInfo); @@ -417,6 +422,57 @@ const DictationPage: React.FC = (): JSX.Element => { ] ); + const onCancel = useCallback( + async (audioFileId: number) => { + if ( + /* eslint-disable-next-line no-alert */ + !window.confirm(t(getTranslationID("common.message.dialogConfirm"))) + ) { + return; + } + const { meta } = await dispatch( + cancelAsync({ + audioFileId, + direction: sortDirection, + paramName: sortableParamName, + isTypist, + }) + ); + if (meta.requestStatus === "fulfilled") { + const filter = getFilter( + filterUploaded, + filterInProgress, + filterPending, + filterFinished, + filterBackup + ); + dispatch( + listTasksAsync({ + limit: LIMIT_TASK_NUM, + offset: 0, + filter, + direction: sortDirection, + paramName: sortableParamName, + }) + ); + dispatch(listTypistsAsync()); + dispatch(listTypistGroupsAsync()); + } + }, + [ + dispatch, + filterBackup, + filterFinished, + filterInProgress, + filterPending, + filterUploaded, + isTypist, + sortDirection, + sortableParamName, + t, + ] + ); + const onCloseBackupPopup = useCallback(() => { setIsBackupPopupOpen(false); }, []); @@ -1056,6 +1112,27 @@ const DictationPage: React.FC = (): JSX.Element => { )} +
  • + {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */} + { + onCancel(x.audioFileId); + }} + > + {t( + getTranslationID( + "dictationPage.label.cancelDictation" + ) + )} + +
  • {t( diff --git a/dictation_client/src/translation/de.json b/dictation_client/src/translation/de.json index b08ae0a..d9594e9 100644 --- a/dictation_client/src/translation/de.json +++ b/dictation_client/src/translation/de.json @@ -203,7 +203,9 @@ "message": { "noPlaybackAuthorization": "Sie haben keine Berechtigung zum Abspielen dieser Datei.", "taskToPlaybackNoExists": "Die Datei kann nicht abgespielt werden, da sie bereits transkribiert wurde oder nicht existiert.", - "taskNotEditable": "Der Transkriptionist kann nicht geändert werden, da die Transkription bereits ausgeführt wird oder die Datei nicht vorhanden ist. Bitte aktualisieren Sie den Bildschirm und prüfen Sie den aktuellen Status." + "taskNotEditable": "Der Transkriptionist kann nicht geändert werden, da die Transkription bereits ausgeführt wird oder die Datei nicht vorhanden ist. Bitte aktualisieren Sie den Bildschirm und prüfen Sie den aktuellen Status.", + "backupFailedError": "(de)ファイルのバックアップに失敗したため処理を中断しました。時間をおいて再実行しても解決しない場合はシステム管理者にお問い合わせください。", + "cancelFailedError": "(de)タスクのキャンセルに失敗しました。画面を更新し、再度ご確認ください。" }, "label": { "title": "Diktate", @@ -247,7 +249,8 @@ "selectedTranscriptionist": "Ausgewählter transkriptionist", "poolTranscriptionist": "Transkriptionsliste", "fileBackup": "(de)File Backup", - "downloadForBackup": "(de)Download for backup" + "downloadForBackup": "(de)Download for backup", + "cancelDictation": "(de)Cancel Dictation" } }, "cardLicenseIssuePopupPage": { diff --git a/dictation_client/src/translation/en.json b/dictation_client/src/translation/en.json index e4426cf..7d9fe63 100644 --- a/dictation_client/src/translation/en.json +++ b/dictation_client/src/translation/en.json @@ -203,7 +203,9 @@ "message": { "noPlaybackAuthorization": "You do not have permission to playback this file.", "taskToPlaybackNoExists": "The file cannot be played because it has already been transcribed or does not exist.", - "taskNotEditable": "The transcriptionist cannot be changed because the transcription is already in progress or the file does not exist. Please refresh the screen and check the latest status." + "taskNotEditable": "The transcriptionist cannot be changed because the transcription is already in progress or the file does not exist. Please refresh the screen and check the latest status.", + "backupFailedError": "ファイルのバックアップに失敗したため処理を中断しました。時間をおいて再実行しても解決しない場合はシステム管理者にお問い合わせください。", + "cancelFailedError": "タスクのキャンセルに失敗しました。画面を更新し、再度ご確認ください。" }, "label": { "title": "Dictations", @@ -247,7 +249,8 @@ "selectedTranscriptionist": "Selected Transcriptionist", "poolTranscriptionist": "Transcription List", "fileBackup": "File Backup", - "downloadForBackup": "Download for backup" + "downloadForBackup": "Download for backup", + "cancelDictation": "Cancel Dictation" } }, "cardLicenseIssuePopupPage": { diff --git a/dictation_client/src/translation/es.json b/dictation_client/src/translation/es.json index ada310b..0cf0ebe 100644 --- a/dictation_client/src/translation/es.json +++ b/dictation_client/src/translation/es.json @@ -203,7 +203,9 @@ "message": { "noPlaybackAuthorization": "No tienes permiso para reproducir este archivo.", "taskToPlaybackNoExists": "El archivo no se puede reproducir porque ya ha sido transcrito o no existe.", - "taskNotEditable": "No se puede cambiar el transcriptor porque la transcripción ya está en curso o el archivo no existe. Actualice la pantalla y verifique el estado más reciente." + "taskNotEditable": "No se puede cambiar el transcriptor porque la transcripción ya está en curso o el archivo no existe. Actualice la pantalla y verifique el estado más reciente.", + "backupFailedError": "(es)ファイルのバックアップに失敗したため処理を中断しました。時間をおいて再実行しても解決しない場合はシステム管理者にお問い合わせください。", + "cancelFailedError": "(es)タスクのキャンセルに失敗しました。画面を更新し、再度ご確認ください。" }, "label": { "title": "Dictado", @@ -247,7 +249,8 @@ "selectedTranscriptionist": "Transcriptor seleccionado", "poolTranscriptionist": "Lista de transcriptor", "fileBackup": "(es)File Backup", - "downloadForBackup": "(es)Download for backup" + "downloadForBackup": "(es)Download for backup", + "cancelDictation": "(es)Cancel Dictation" } }, "cardLicenseIssuePopupPage": { diff --git a/dictation_client/src/translation/fr.json b/dictation_client/src/translation/fr.json index 8285a52..623936d 100644 --- a/dictation_client/src/translation/fr.json +++ b/dictation_client/src/translation/fr.json @@ -203,7 +203,9 @@ "message": { "noPlaybackAuthorization": "Vous n'êtes pas autorisé à lire ce fichier.", "taskToPlaybackNoExists": "Le fichier ne peut pas être lu car il a déjà été transcrit ou n'existe pas.", - "taskNotEditable": "Le transcripteur ne peut pas être changé car la transcription est déjà en cours ou le fichier n'existe pas. Veuillez actualiser l'écran et vérifier le dernier statut." + "taskNotEditable": "Le transcripteur ne peut pas être changé car la transcription est déjà en cours ou le fichier n'existe pas. Veuillez actualiser l'écran et vérifier le dernier statut.", + "backupFailedError": "(fr)ファイルのバックアップに失敗したため処理を中断しました。時間をおいて再実行しても解決しない場合はシステム管理者にお問い合わせください。", + "cancelFailedError": "(fr)タスクのキャンセルに失敗しました。画面を更新し、再度ご確認ください。" }, "label": { "title": "Dictées", @@ -247,7 +249,8 @@ "selectedTranscriptionist": "Transcriptionniste sélectionné", "poolTranscriptionist": "Liste de transcriptionniste", "fileBackup": "(fr)File Backup", - "downloadForBackup": "(fr)Download for backup" + "downloadForBackup": "(fr)Download for backup", + "cancelDictation": "(fr)Cancel Dictation" } }, "cardLicenseIssuePopupPage": {