From 68d1a1796bd6f5e40b4f26a34e8b5c101f84958d Mon Sep 17 00:00:00 2001 From: masaaki Date: Mon, 26 Feb 2024 08:59:37 +0000 Subject: [PATCH 1/4] =?UTF-8?q?Merged=20PR=20783:=20[1=E5=9B=9E=E7=9B=AE?= =?UTF-8?q?=E5=AE=9F=E8=A1=8C]=E5=AE=9F=E6=96=BD=E5=BE=8C=E3=81=AE?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E5=AE=9F=E6=96=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 概要 [Task3790: [1回目実行]実施後の修正実施](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/3790) - 移行データ動作確認(1回目)で発生した不具合の対応を実施しました  ・バリデータでエラーとなる(コメントアウトして実行したところ、成功)  ・アカウント管理者のユーザーのメール認証がfalseで登録されるので、   パスワード変更では認証をできない⇒強制敵にtrueで登録する  ・(指摘外、検証ツール実装時に内部検出)カードライセンス登録時、カードライセンス発行・ライセンステーブルも登録する - このPull Requestでの対象/対象外  上記以外の指摘(下記)はタスク3772にて対応するため本プルリク対象外  変換ツール   ・ディーラーアカウントに登録されたアカウントがいないCSVで    変換するとディーラーがundefined(パラメータがない)状態でJSON出力されてしまう。   ・重複したメールアドレスの取り込みが未実装   ・有効期限が9999/~は移行対象外とする   ・ワークタイプの出力がされない  登録ツール   ・ファイルパスの取り扱いが変換ツールと異なる - 影響範囲(他の機能にも影響があるか) ## レビューポイント - カードライセンス登録時のライセンスのアカウントIDについて、第一階層アカウントのため「AUTO_INCREMENT_START: 853211」を設定しているが問題ないか?  →移行データ上第一階層アカウントは最初に登場するため問題ない認識 ## UIの変更 - 無し ## 動作確認状況 - ローカルで確認済 ## 補足 - 相談、参考資料などがあれば --- .../server/src/common/types/types.ts | 2 +- .../accounts/accounts.repository.service.ts | 17 ++--- .../licenses/entity/license.entity.ts | 27 +++++++ .../licenses/licenses.repository.module.ts | 7 +- .../licenses/licenses.repository.service.ts | 75 +++++++++++++++---- 5 files changed, 102 insertions(+), 26 deletions(-) diff --git a/data_migration_tools/server/src/common/types/types.ts b/data_migration_tools/server/src/common/types/types.ts index 660b942..de92211 100644 --- a/data_migration_tools/server/src/common/types/types.ts +++ b/data_migration_tools/server/src/common/types/types.ts @@ -134,7 +134,7 @@ export function isAccountsInputFile(obj: any): obj is AccountsInputFile { "country" in obj && typeof obj.country === "string" && ("dealerAccountId" in obj - ? typeof obj.dealerAccountId === "number" + ? obj.dealerAccountId === null || typeof obj.dealerAccountId === "number" : true) && "adminName" in obj && typeof obj.adminName === "string" && diff --git a/data_migration_tools/server/src/repositories/accounts/accounts.repository.service.ts b/data_migration_tools/server/src/repositories/accounts/accounts.repository.service.ts index ec24808..b38f6ba 100644 --- a/data_migration_tools/server/src/repositories/accounts/accounts.repository.service.ts +++ b/data_migration_tools/server/src/repositories/accounts/accounts.repository.service.ts @@ -1,20 +1,18 @@ -import { Injectable } from '@nestjs/common'; -import { - DataSource, -} from 'typeorm'; -import { User } from '../users/entity/user.entity'; -import { Account } from './entity/account.entity'; +import { Injectable } from "@nestjs/common"; +import { DataSource } from "typeorm"; +import { User } from "../users/entity/user.entity"; +import { Account } from "./entity/account.entity"; import { getDirection, getTaskListSortableAttribute, -} from '../../common/types/sort/util'; +} from "../../common/types/sort/util"; import { SortCriteria } from "../sort_criteria/entity/sort_criteria.entity"; import { insertEntity, updateEntity, deleteEntity, -} from '../../common/repository'; -import { Context } from '../../common/log'; +} from "../../common/repository"; +import { Context } from "../../common/log"; @Injectable() export class AccountsRepositoryService { @@ -81,6 +79,7 @@ export class AccountsRepositoryService { user.accepted_privacy_notice_version = adminUserAcceptedPrivacyNoticeVersion ?? null; user.accepted_dpa_version = adminUserAcceptedDpaVersion ?? null; + user.email_verified = true; } const usersRepo = entityManager.getRepository(User); const newUser = usersRepo.create(user); diff --git a/data_migration_tools/server/src/repositories/licenses/entity/license.entity.ts b/data_migration_tools/server/src/repositories/licenses/entity/license.entity.ts index 90715ae..57ba60c 100644 --- a/data_migration_tools/server/src/repositories/licenses/entity/license.entity.ts +++ b/data_migration_tools/server/src/repositories/licenses/entity/license.entity.ts @@ -129,6 +129,33 @@ export class CardLicense { @Column({ nullable: true, type: "datetime" }) updated_by: string | null; + @UpdateDateColumn({ + default: () => "datetime('now', 'localtime')", + type: "datetime", + }) + updated_at: Date; +} + +@Entity({ name: "card_license_issue" }) +export class CardLicenseIssue { + @PrimaryGeneratedColumn() + id: number; + + @Column() + issued_at: Date; + + @Column({ nullable: true, type: "datetime" }) + created_by: string | null; + + @CreateDateColumn({ + default: () => "datetime('now', 'localtime')", + type: "datetime", + }) + created_at: Date; + + @Column({ nullable: true, type: "datetime" }) + updated_by: string | null; + @UpdateDateColumn({ default: () => "datetime('now', 'localtime')", type: "datetime", diff --git a/data_migration_tools/server/src/repositories/licenses/licenses.repository.module.ts b/data_migration_tools/server/src/repositories/licenses/licenses.repository.module.ts index e3e3d0c..006f054 100644 --- a/data_migration_tools/server/src/repositories/licenses/licenses.repository.module.ts +++ b/data_migration_tools/server/src/repositories/licenses/licenses.repository.module.ts @@ -2,6 +2,7 @@ import { Module } from "@nestjs/common"; import { TypeOrmModule } from "@nestjs/typeorm"; import { CardLicense, + CardLicenseIssue, License, LicenseAllocationHistory, } from "./entity/license.entity"; @@ -9,7 +10,11 @@ import { LicensesRepositoryService } from "./licenses.repository.service"; @Module({ imports: [ - TypeOrmModule.forFeature([License, CardLicense, LicenseAllocationHistory]), + TypeOrmModule.forFeature([ + License, + CardLicense, + CardLicenseIssue, LicenseAllocationHistory, + ]), ], providers: [LicensesRepositoryService], exports: [LicensesRepositoryService], diff --git a/data_migration_tools/server/src/repositories/licenses/licenses.repository.service.ts b/data_migration_tools/server/src/repositories/licenses/licenses.repository.service.ts index 52e13b5..643b7f4 100644 --- a/data_migration_tools/server/src/repositories/licenses/licenses.repository.service.ts +++ b/data_migration_tools/server/src/repositories/licenses/licenses.repository.service.ts @@ -4,14 +4,19 @@ import { License, LicenseAllocationHistory, CardLicense, + CardLicenseIssue, } from "./entity/license.entity"; -import { insertEntities } from "../../common/repository"; +import { insertEntity, insertEntities } from "../../common/repository"; import { Context } from "../../common/log"; import { LicensesInputFile, CardLicensesInputFile, } from "../../common/types/types"; - +import {AUTO_INCREMENT_START} from "../../constants/index" +import { + LICENSE_ALLOCATED_STATUS, + LICENSE_TYPE, +} from "../../constants"; @Injectable() export class LicensesRepositoryService { //クエリログにコメントを出力するかどうか @@ -38,7 +43,9 @@ export class LicensesRepositoryService { license.account_id = licensesInputFile.account_id; license.status = licensesInputFile.status; license.type = licensesInputFile.type; - license.expiry_date = (licensesInputFile.expiry_date) ? new Date(licensesInputFile.expiry_date) : null; + license.expiry_date = licensesInputFile.expiry_date + ? new Date(licensesInputFile.expiry_date) + : null; if (licensesInputFile.allocated_user_id) { license.allocated_user_id = licensesInputFile.allocated_user_id; } @@ -97,22 +104,61 @@ export class LicensesRepositoryService { ): Promise<{}> { return await this.dataSource.transaction(async (entityManager) => { const cardLicenseRepo = entityManager.getRepository(CardLicense); + const licensesRepo = entityManager.getRepository(License); + const cardLicenseIssueRepo = + entityManager.getRepository(CardLicenseIssue); + const licenses: License[] = []; + // ライセンステーブルを作成する(BULK INSERT) + for (let i = 0; i < cardLicensesInputFiles.length; i++) { + const license = new License(); + license.account_id = AUTO_INCREMENT_START; // 最初に登場するアカウント(第一アカウント) + license.status = LICENSE_ALLOCATED_STATUS.UNALLOCATED; + license.type = LICENSE_TYPE.CARD; + licenses.push(license); + } + const savedLicenses = await insertEntities( + License, + licensesRepo, + licenses, + this.isCommentOut, + context + ); - let newCardLicenses: CardLicense[] = []; - cardLicensesInputFiles.forEach((cardLicensesInputFile) => { + // カードライセンス発行テーブルを作成する + const cardLicenseIssue = new CardLicenseIssue(); + cardLicenseIssue.issued_at = new Date(); + const newCardLicenseIssue = cardLicenseIssueRepo.create(cardLicenseIssue); + const savedCardLicensesIssue = await insertEntity( + CardLicenseIssue, + cardLicenseIssueRepo, + newCardLicenseIssue, + this.isCommentOut, + context + ); + + const newCardLicenses: CardLicense[] = []; + // カードライセンステーブルを作成する(BULK INSERT) + for (let i = 0; i < cardLicensesInputFiles.length; i++) { const cardLicense = new CardLicense(); - cardLicense.license_id = cardLicensesInputFile.license_id; - cardLicense.issue_id = cardLicensesInputFile.issue_id; - cardLicense.card_license_key = cardLicensesInputFile.card_license_key; - cardLicense.activated_at = (cardLicensesInputFile.activated_at) ? new Date(cardLicensesInputFile.activated_at) : null; - cardLicense.created_at = (cardLicensesInputFile.created_at) ? new Date(cardLicensesInputFile.created_at) : null; - cardLicense.created_by = cardLicensesInputFile.created_by; - cardLicense.updated_at = (cardLicensesInputFile.updated_at) ? new Date(cardLicensesInputFile.updated_at) : null; - cardLicense.updated_by = cardLicensesInputFile.updated_by; + cardLicense.license_id = savedLicenses[i].id; // Licenseテーブルの自動採番されたIDを挿入 + cardLicense.issue_id = savedCardLicensesIssue.id; // CardLicenseIssueテーブルの自動採番されたIDを挿入 + cardLicense.card_license_key = + cardLicensesInputFiles[i].card_license_key; + cardLicense.activated_at = cardLicensesInputFiles[i].activated_at + ? new Date(cardLicensesInputFiles[i].activated_at) + : null; + cardLicense.created_at = cardLicensesInputFiles[i].created_at + ? new Date(cardLicensesInputFiles[i].created_at) + : null; + cardLicense.created_by = cardLicensesInputFiles[i].created_by; + cardLicense.updated_at = cardLicensesInputFiles[i].updated_at + ? new Date(cardLicensesInputFiles[i].updated_at) + : null; + cardLicense.updated_by = cardLicensesInputFiles[i].updated_by; newCardLicenses.push(cardLicense); - }); + } const query = cardLicenseRepo .createQueryBuilder() @@ -126,5 +172,4 @@ export class LicensesRepositoryService { return {}; }); } - } From d0628caa05433c6d7c674a57bf66cd9df784a84b Mon Sep 17 00:00:00 2001 From: "saito.k" Date: Mon, 26 Feb 2024 10:42:26 +0000 Subject: [PATCH 2/4] =?UTF-8?q?Merged=20PR=20767:=20=E3=83=91=E3=83=BC?= =?UTF-8?q?=E3=83=88=E3=83=8A=E3=83=BC=E8=BF=BD=E5=8A=A0=E6=88=90=E5=8A=9F?= =?UTF-8?q?=E6=99=82=E3=81=AB=E4=B8=80=E8=A6=A7=E3=81=AE=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E3=81=8C=E8=A1=8C=E3=82=8F=E3=82=8C=E3=81=A6=E3=81=84=E3=81=AA?= =?UTF-8?q?=E3=81=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 概要 [Task3769: パートナー追加成功時に一覧の更新が行われていない](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/3769) - パートナー追加成功時に一覧の更新を行う ## レビューポイント - 特になし ## 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/Task3769?csf=1&web=1&e=ajJOBd ## 動作確認状況 - ローカルで確認、develop環境で確認など ## 補足 - 相談、参考資料などがあれば --- .../pages/PartnerPage/addPartnerAccountPopup.tsx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/dictation_client/src/pages/PartnerPage/addPartnerAccountPopup.tsx b/dictation_client/src/pages/PartnerPage/addPartnerAccountPopup.tsx index edf782c..48b36a2 100644 --- a/dictation_client/src/pages/PartnerPage/addPartnerAccountPopup.tsx +++ b/dictation_client/src/pages/PartnerPage/addPartnerAccountPopup.tsx @@ -11,6 +11,7 @@ import { selectEmail, selectInputValidationErrors, selectIsLoading, + selectOffset, } from "features/partner/selectors"; import { changeAdminName, @@ -19,7 +20,11 @@ import { changeEmail, cleanupAddPartner, } from "features/partner/partnerSlice"; -import { createPartnerAccountAsync } from "features/partner"; +import { + LIMIT_PARTNER_VIEW_NUM, + createPartnerAccountAsync, + getPartnerInfoAsync, +} from "features/partner"; import close from "../../assets/images/close.svg"; import progress_activit from "../../assets/images/progress_activit.svg"; import { COUNTRY_LIST } from "../SignupPage/constants"; @@ -50,6 +55,7 @@ export const AddPartnerAccountPopup: React.FC = ( const adminName = useSelector(selectAdminName); const email = useSelector(selectEmail); const isLoading = useSelector(selectIsLoading); + const offset = useSelector(selectOffset); // ポップアップを閉じる処理 const closePopup = useCallback(() => { @@ -84,6 +90,12 @@ export const AddPartnerAccountPopup: React.FC = ( setIsPushCreateButton(false); if (meta.requestStatus === "fulfilled") { + dispatch( + getPartnerInfoAsync({ + limit: LIMIT_PARTNER_VIEW_NUM, + offset, + }) + ); closePopup(); } }, [ From 5a78a6668f90ee77a100f25cce45c84cb270dd9b Mon Sep 17 00:00:00 2001 From: "saito.k" Date: Mon, 26 Feb 2024 11:29:22 +0000 Subject: [PATCH 3/4] =?UTF-8?q?Merged=20PR=20769:=20/users/relations?= =?UTF-8?q?=E3=83=AC=E3=82=B9=E3=83=9D=E3=83=B3=E3=82=B9=E3=81=AEWorkTypeI?= =?UTF-8?q?D=E3=82=92ID=E5=90=8D=E3=81=AE=E6=98=87=E9=A0=86=E3=81=AB?= =?UTF-8?q?=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 概要 [Task3783: /users/relationsレスポンスのWorkTypeIDをID名の昇順にする](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/3783) - relationsAPIレスポンスのWorkTypeList内の順番を指定する - テスト修正 ## レビューポイント - 修正内容に不足はないか ## UIの変更 - Before/Afterのスクショなど - スクショ置き場 ## 動作確認状況 - ローカルで確認 ## 補足 - 相談、参考資料などがあれば --- .../common/validators/authorId.validator.ts | 2 +- .../src/features/users/users.service.spec.ts | 29 ++++++++++++------- .../users/users.repository.service.ts | 8 +++++ 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/dictation_server/src/common/validators/authorId.validator.ts b/dictation_server/src/common/validators/authorId.validator.ts index 23afafb..a790edc 100644 --- a/dictation_server/src/common/validators/authorId.validator.ts +++ b/dictation_server/src/common/validators/authorId.validator.ts @@ -15,7 +15,7 @@ import { USER_ROLES } from '../../constants'; @ValidatorConstraint({ name: 'IsAuthorId', async: false }) export class IsAuthorId implements ValidatorConstraintInterface { validate(value: any, args: ValidationArguments) { - const request = args.object as SignupRequest | PostUpdateUserRequest; + const request = args.object as SignupRequest | PostUpdateUserRequest; // requestの存在チェック if (!request) { return false; diff --git a/dictation_server/src/features/users/users.service.spec.ts b/dictation_server/src/features/users/users.service.spec.ts index 8e3cbf5..bb4931c 100644 --- a/dictation_server/src/features/users/users.service.spec.ts +++ b/dictation_server/src/features/users/users.service.spec.ts @@ -170,7 +170,7 @@ describe('UsersService.confirmUser', () => { }); expect(_subject).toBe('Account Registered Notification [U-101]'); expect(_url).toBe('http://localhost:8081/'); - }, 600000); + }); it('トークンの形式が不正な場合、形式不正エラーとなる。', async () => { if (!source) fail(); @@ -2735,17 +2735,21 @@ describe('UsersService.getRelations', () => { const worktype1 = await createWorktype( source, account.id, - 'worktype1', + 'worktypeB', undefined, true, ); await createOptionItems(source, worktype1.id); - const worktype2 = await createWorktype(source, account.id, 'worktype2'); + const worktype2 = await createWorktype(source, account.id, 'worktypeC'); await createOptionItems(source, worktype2.id); + const worktype3 = await createWorktype(source, account.id, 'worktypeA'); + await createOptionItems(source, worktype3.id); + await createWorkflow(source, account.id, user1, worktype1.id); await createWorkflow(source, account.id, user1, worktype2.id); + await createWorkflow(source, account.id, user1, worktype3.id); await createWorkflow(source, account.id, user1); await createWorkflow(source, account.id, user2, worktype1.id); @@ -2754,15 +2758,17 @@ describe('UsersService.getRelations', () => { const workflows = await getWorkflows(source, account.id); workflows.sort((a, b) => a.id - b.id); - expect(workflows.length).toBe(4); + expect(workflows.length).toBe(5); expect(workflows[0].worktype_id).toBe(worktype1.id); expect(workflows[0].author_id).toBe(user1); expect(workflows[1].worktype_id).toBe(worktype2.id); expect(workflows[1].author_id).toBe(user1); - expect(workflows[2].worktype_id).toBe(null); + expect(workflows[2].worktype_id).toBe(worktype3.id); expect(workflows[2].author_id).toBe(user1); - expect(workflows[3].worktype_id).toBe(worktype1.id); - expect(workflows[3].author_id).toBe(user2); + expect(workflows[3].worktype_id).toBe(null); + expect(workflows[3].author_id).toBe(user1); + expect(workflows[4].worktype_id).toBe(worktype1.id); + expect(workflows[4].author_id).toBe(user2); } const context = makeContext(external_id, 'requestId'); @@ -2778,14 +2784,17 @@ describe('UsersService.getRelations', () => { expect(relations.authorIdList[1]).toBe('AUTHOR_2'); const workTypeList = relations.workTypeList; - expect(relations.workTypeList.length).toBe(2); - expect(workTypeList[0].workTypeId).toBe(worktype1.custom_worktype_id); + expect(relations.workTypeList.length).toBe(3); + // Workflowの作成順ではなくcustom_worktype_idの昇順で取得するためWorkTypeListの先頭はworktype3 + expect(workTypeList[0].workTypeId).toBe(worktype3.custom_worktype_id); expect(workTypeList[0].optionItemList.length).toBe(10); expect(workTypeList[0].optionItemList[0].label).toBe(''); expect(workTypeList[0].optionItemList[0].initialValueType).toBe(2); expect(workTypeList[0].optionItemList[0].defaultValue).toBe(''); - expect(workTypeList[1].workTypeId).toBe(worktype2.custom_worktype_id); + expect(workTypeList[1].workTypeId).toBe(worktype1.custom_worktype_id); expect(workTypeList[1].optionItemList.length).toBe(10); + expect(workTypeList[2].workTypeId).toBe(worktype2.custom_worktype_id); + expect(workTypeList[2].optionItemList.length).toBe(10); expect(relations.isEncrypted).toBe(true); expect(relations.encryptionPassword).toBe('password'); diff --git a/dictation_server/src/repositories/users/users.repository.service.ts b/dictation_server/src/repositories/users/users.repository.service.ts index 8c39441..9a70a96 100644 --- a/dictation_server/src/repositories/users/users.repository.service.ts +++ b/dictation_server/src/repositories/users/users.repository.service.ts @@ -918,6 +918,14 @@ export class UsersRepositoryService { option_items: true, }, }, + order: { + worktype: { + custom_worktype_id: 'ASC', + option_items: { + id: 'ASC', + }, + }, + }, comment: `${context.getTrackingId()}_${new Date().toUTCString()}`, }); From 0ab6488f58890239d21400bdb663de7690a99e06 Mon Sep 17 00:00:00 2001 From: "saito.k" Date: Mon, 26 Feb 2024 11:48:02 +0000 Subject: [PATCH 4/4] =?UTF-8?q?Merged=20PR=20779:=20=E3=82=BF=E3=82=B9?= =?UTF-8?q?=E3=82=AF=E4=B8=80=E8=A6=A7=E7=94=BB=E9=9D=A2=E3=81=AEOptionIte?= =?UTF-8?q?m=E3=81=8C=E3=82=BD=E3=83=BC=E3=83=88=E6=9D=A1=E4=BB=B6?= =?UTF-8?q?=E3=81=AB=E3=82=88=E3=81=A3=E3=81=A6=E8=A1=A8=E7=A4=BA=E9=A0=86?= =?UTF-8?q?=E3=81=8C=E3=81=8A=E3=81=8B=E3=81=97=E3=81=8F=E3=81=AA=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 概要 [Task3787: タスク一覧画面のOptionItemがソート条件によって表示順がおかしくなる](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/3787) - タスク一覧取得APIレスポンスにあるOptionItemの順番を固定する(idの昇順) - テスト修正 ## レビューポイント - 特になし ## 動作確認状況 - ローカルで確認 ## 補足 - 相談、参考資料などがあれば --- .../src/features/tasks/tasks.service.spec.ts | 97 +++++++++++++++++++ .../tasks/tasks.repository.service.ts | 13 +++ 2 files changed, 110 insertions(+) diff --git a/dictation_server/src/features/tasks/tasks.service.spec.ts b/dictation_server/src/features/tasks/tasks.service.spec.ts index 0b77c95..1531077 100644 --- a/dictation_server/src/features/tasks/tasks.service.spec.ts +++ b/dictation_server/src/features/tasks/tasks.service.spec.ts @@ -782,6 +782,103 @@ describe('TasksService', () => { expect(task.optionItemList).toEqual(audioOptionItems); } }); + + it('[Author] Authorは自分が作成者のTask一覧を取得できる(ソート条件がJob_number以外)', async () => { + const notificationhubServiceMockValue = + makeDefaultNotificationhubServiceMockValue(); + if (!source) fail(); + const module = await makeTaskTestingModuleWithNotificaiton( + source, + notificationhubServiceMockValue, + ); + if (!module) fail(); + const { id: accountId } = await makeTestSimpleAccount(source); + const { id: userId, external_id } = await makeTestUser(source, { + account_id: accountId, + external_id: 'userId', + role: 'author', + author_id: 'MY_AUTHOR_ID', + }); + + //「バグ 3661: [FB対応]Option Itemにチェックを付けると真っ白な画面になる」の確認のため + // audio_file_idをTaskIdと異なる値にするために、AudioFileを作成 + await createAudioFile( + source, + accountId, + userId, + 'MY_AUTHOR_ID', + '', + '00', + ); + + // Taskを作成 + await createTask( + source, + accountId, + userId, + 'MY_AUTHOR_ID', + 'WORKTYPE1', + '01', + '00000001', + 'Uploaded', + ); + await createTask( + source, + accountId, + userId, + 'MY_AUTHOR_ID', + 'WORKTYPE2', + '01', + '00000002', + 'Uploaded', + ); + + const service = module.get(TasksService); + const offset = 0; + const limit = 20; + const status = ['Uploaded', 'Backup']; + // バグ 3786: [FB対応]タスク一覧画面のOptionItemがソート条件によって表示順がおかしくなる の確認のため + // Job_number以外のソート条件を指定 + const paramName = 'WORK_TYPE'; + const direction = 'DESC'; + + const { tasks, total } = await service.getTasks( + makeContext('trackingId', 'requestId'), + external_id, + [USER_ROLES.AUTHOR], + offset, + limit, + status, + paramName, + direction, + ); + + expect(total).toEqual(2); + { + const task = tasks[0]; + expect(task.jobNumber).toEqual('00000002'); + // ソート条件がJob_number以外でもOptionItemがid順に取得されていることを確認 + const audioOptionItems = Array.from({ length: 10 }).map((_, i) => { + return { + optionItemLabel: `label${i}:audio_file_id${task.audioFileId}`, + optionItemValue: `value${i}:audio_file_id${task.audioFileId}`, + }; + }); + expect(task.optionItemList).toEqual(audioOptionItems); + } + { + const task = tasks[1]; + expect(task.jobNumber).toEqual('00000001'); + // ソート条件がJob_number以外でもOptionItemがid順に取得されていることを確認 + const audioOptionItems = Array.from({ length: 10 }).map((_, i) => { + return { + optionItemLabel: `label${i}:audio_file_id${task.audioFileId}`, + optionItemValue: `value${i}:audio_file_id${task.audioFileId}`, + }; + }); + expect(task.optionItemList).toEqual(audioOptionItems); + } + }); it('[Author] Authorは同一アカウントであっても自分以外のAuhtorのTaskは取得できない', async () => { const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); diff --git a/dictation_server/src/repositories/tasks/tasks.repository.service.ts b/dictation_server/src/repositories/tasks/tasks.repository.service.ts index a95a8ab..e2bbefa 100644 --- a/dictation_server/src/repositories/tasks/tasks.repository.service.ts +++ b/dictation_server/src/repositories/tasks/tasks.repository.service.ts @@ -1462,78 +1462,91 @@ const makeOrder = ( priority: 'DESC', job_number: direction, id: 'ASC', + option_items: { id: 'ASC' }, }; case 'STATUS': return { priority: 'DESC', status: direction, id: 'ASC', + option_items: { id: 'ASC' }, }; case 'TRANSCRIPTION_FINISHED_DATE': return { priority: 'DESC', finished_at: direction, id: 'ASC', + option_items: { id: 'ASC' }, }; case 'TRANSCRIPTION_STARTED_DATE': return { priority: 'DESC', started_at: direction, id: 'ASC', + option_items: { id: 'ASC' }, }; case 'AUTHOR_ID': return { priority: 'DESC', file: { author_id: direction }, id: 'ASC', + option_items: { id: 'ASC' }, }; case 'ENCRYPTION': return { priority: 'DESC', file: { is_encrypted: direction }, id: 'ASC', + option_items: { id: 'ASC' }, }; case 'FILE_LENGTH': return { priority: 'DESC', file: { duration: direction }, id: 'ASC', + option_items: { id: 'ASC' }, }; case 'FILE_NAME': return { priority: 'DESC', file: { file_name: direction }, id: 'ASC', + option_items: { id: 'ASC' }, }; case 'FILE_SIZE': return { priority: 'DESC', file: { file_size: direction }, id: 'ASC', + option_items: { id: 'ASC' }, }; case 'RECORDING_FINISHED_DATE': return { priority: 'DESC', file: { finished_at: direction }, id: 'ASC', + option_items: { id: 'ASC' }, }; case 'RECORDING_STARTED_DATE': return { priority: 'DESC', file: { started_at: direction }, id: 'ASC', + option_items: { id: 'ASC' }, }; case 'UPLOAD_DATE': return { priority: 'DESC', file: { uploaded_at: direction }, id: 'ASC', + option_items: { id: 'ASC' }, }; case 'WORK_TYPE': return { priority: 'DESC', file: { work_type_id: direction }, id: 'ASC', + option_items: { id: 'ASC' }, }; default: // switchのcase漏れが発生した場合に型エラーになるようにする