From b4df229de4cd4bd15b63573c870020f1e05db994 Mon Sep 17 00:00:00 2001 From: "saito.k" Date: Mon, 19 Feb 2024 01:09:39 +0000 Subject: [PATCH 1/3] =?UTF-8?q?Merged=20PR=20751:=20[FB=E5=AF=BE=E5=BF=9C]?= =?UTF-8?q?WorkTypeID=E3=82=92=E5=A4=A7=E6=96=87=E5=AD=97=E5=9B=BA?= =?UTF-8?q?=E5=AE=9A=E3=81=AB=E3=81=97=E3=81=9F=E3=81=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 概要 [Task3733: 対応する](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/3733) - 大文字のみの入力に強制する - WorkTypeID - OptionItem - APIの大文字固定のパラメータにバリデーションを付与する - AuthorID - WorkTypeID - OptionItem ## レビューポイント - 大文字に変換する処理をreducerに寄せたが問題ないか - バリデータを付けるパラメータに漏れはないか ## 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/Task3733?csf=1&web=1&e=zNB1Hi ## 動作確認状況 - ローカルで確認 ## 補足 - 相談、参考資料などがあれば --- .../workflow/worktype/worktypeSlice.ts | 7 +++- .../common/validators/authorId.validator.ts | 36 +++++++++++++++++++ .../common/validators/worktype.validator.ts | 4 +-- .../accounts/accounts.service.spec.ts | 12 ++++--- .../licenses/licenses.service.spec.ts | 20 ++++++++--- .../src/features/tasks/test/utility.ts | 9 +++-- .../src/features/users/types/types.ts | 3 ++ .../repositories/user_groups/errors/types.ts | 2 +- 8 files changed, 74 insertions(+), 19 deletions(-) create mode 100644 dictation_server/src/common/validators/authorId.validator.ts diff --git a/dictation_client/src/features/workflow/worktype/worktypeSlice.ts b/dictation_client/src/features/workflow/worktype/worktypeSlice.ts index 224e7e3..3a358ca 100644 --- a/dictation_client/src/features/workflow/worktype/worktypeSlice.ts +++ b/dictation_client/src/features/workflow/worktype/worktypeSlice.ts @@ -45,7 +45,7 @@ export const worktypeSlice = createSlice({ action: PayloadAction<{ worktypeId: string }> ) => { const { worktypeId } = action.payload; - state.apps.worktypeId = worktypeId; + state.apps.worktypeId = worktypeId.toUpperCase(); }, changeDescription: ( state, @@ -65,7 +65,12 @@ export const worktypeSlice = createSlice({ optionItem.defaultValueType !== OPTION_ITEMS_DEFAULT_VALUE_TYPE.DEFAULT ) { optionItem.initialValue = ""; + } else { + // defaultValueTypeがDefaultの場合はinitialValueを大文字にする + optionItem.initialValue = optionItem.initialValue.toUpperCase(); } + // itemLabelを大文字にする + optionItem.itemLabel = optionItem.itemLabel.toUpperCase(); // idが一致するoptionItemを削除して、新しいoptionItemを追加する。一致するidがない場合は何もしない const optionItems = state.apps.optionItems?.filter( diff --git a/dictation_server/src/common/validators/authorId.validator.ts b/dictation_server/src/common/validators/authorId.validator.ts new file mode 100644 index 0000000..02ad278 --- /dev/null +++ b/dictation_server/src/common/validators/authorId.validator.ts @@ -0,0 +1,36 @@ +import { + ValidatorConstraint, + ValidatorConstraintInterface, + ValidationArguments, + ValidationOptions, + registerDecorator, +} from 'class-validator'; + +// 大文字英数字とアンダースコアのみを許可するバリデータ +@ValidatorConstraint({ name: 'IsAuthorId', async: false }) +export class IsAuthorId implements ValidatorConstraintInterface { + validate(value: any, args: ValidationArguments) { + return /^[A-Z0-9_]*$/.test(value); + } + defaultMessage(args: ValidationArguments) { + return `${args.property} should be uppercase alphanumeric and underscore only`; + } +} + +/** + * 大文字英数字のみを許可するバリデータ + * @param [validationOptions] + * @returns + */ +export function IsAuthorIdValid(validationOptions?: ValidationOptions) { + return function (object: object, propertyName: string) { + registerDecorator({ + name: 'IsAuthorId', + target: object.constructor, + propertyName: propertyName, + constraints: [], + options: validationOptions, + validator: IsAuthorId, + }); + }; +} diff --git a/dictation_server/src/common/validators/worktype.validator.ts b/dictation_server/src/common/validators/worktype.validator.ts index 761e9fa..6a97a50 100644 --- a/dictation_server/src/common/validators/worktype.validator.ts +++ b/dictation_server/src/common/validators/worktype.validator.ts @@ -19,7 +19,7 @@ export class IsRecorderAllowedCharacters } // 正規表現でWorktypeIDのチェックを行う - // 以下の禁則文字を除く半角英数記号 + // 以下の禁則文字を除く大文字英数記号 // \ (backslash) // / (forward slash) // : (colon) @@ -31,7 +31,7 @@ export class IsRecorderAllowedCharacters // | (vertical bar) // . (period) const regex = - /^(?!.*\\)(?!.*\/)(?!.*:)(?!.*\*)(?!.*\?)(?!.*")(?!.*<)(?!.*>)(?!.*\|)(?!.*\.)[ -~]+$/; + /^(?!.*\\)(?!.*\/)(?!.*:)(?!.*\*)(?!.*\?)(?!.*")(?!.*<)(?!.*>)(?!.*\|)(?!.*\.)[A-Z0-9 !#$%&'()+,\-;=@\[\]^_`{}~]*$/; return regex.test(value); } diff --git a/dictation_server/src/features/accounts/accounts.service.spec.ts b/dictation_server/src/features/accounts/accounts.service.spec.ts index d661635..29c5899 100644 --- a/dictation_server/src/features/accounts/accounts.service.spec.ts +++ b/dictation_server/src/features/accounts/accounts.service.spec.ts @@ -134,8 +134,8 @@ describe('createAccount', () => { }, }); - let _subject: string = ""; - let _url: string | undefined = ""; + let _subject: string = ''; + let _url: string | undefined = ''; overrideSendgridService(service, { sendMail: async ( context: Context, @@ -197,7 +197,9 @@ describe('createAccount', () => { // 想定通りのメールが送られているか確認 expect(_subject).toBe('User Registration Notification [U-102]'); - expect(_url?.startsWith('http://localhost:8081/mail-confirm?verify=')).toBeTruthy(); + expect( + _url?.startsWith('http://localhost:8081/mail-confirm?verify='), + ).toBeTruthy(); }); it('アカウントを作成がAzure AD B2Cへの通信失敗によって失敗すると500エラーが発生する', async () => { @@ -5727,8 +5729,8 @@ describe('アカウント情報更新', () => { const module = await makeTestingModule(source); if (!module) fail(); const service = module.get(AccountsService); - let _subject: string = ""; - let _url: string | undefined = ""; + let _subject: string = ''; + let _url: string | undefined = ''; overrideSendgridService(service, { sendMail: async ( context: Context, diff --git a/dictation_server/src/features/licenses/licenses.service.spec.ts b/dictation_server/src/features/licenses/licenses.service.spec.ts index cdc56b2..69b6530 100644 --- a/dictation_server/src/features/licenses/licenses.service.spec.ts +++ b/dictation_server/src/features/licenses/licenses.service.spec.ts @@ -18,14 +18,21 @@ import { } from './test/utility'; import { UsersService } from '../users/users.service'; import { Context, makeContext } from '../../common/log'; -import { ADB2C_SIGN_IN_TYPE, LICENSE_ALLOCATED_STATUS, LICENSE_TYPE } from '../../constants'; +import { + ADB2C_SIGN_IN_TYPE, + LICENSE_ALLOCATED_STATUS, + LICENSE_TYPE, +} from '../../constants'; import { makeHierarchicalAccounts, makeTestSimpleAccount, makeTestUser, } from '../../common/test/utility'; import { LicensesRepositoryService } from '../../repositories/licenses/licenses.repository.service'; -import { overrideAdB2cService, overrideSendgridService } from '../../common/test/overrides'; +import { + overrideAdB2cService, + overrideSendgridService, +} from '../../common/test/overrides'; import { truncateAllTable } from '../../common/test/init'; describe('ライセンス注文', () => { @@ -672,7 +679,10 @@ describe('ライセンス割り当て', () => { const module = await makeTestingModule(source); if (!module) fail(); - const { id: dealerId } = await makeTestSimpleAccount(source, { company_name: "DEALER_COMPANY", tier: 4 }); + const { id: dealerId } = await makeTestSimpleAccount(source, { + company_name: 'DEALER_COMPANY', + tier: 4, + }); const { id: dealerAdminId } = await makeTestUser(source, { account_id: dealerId, external_id: 'userId_admin', @@ -682,7 +692,7 @@ describe('ライセンス割り当て', () => { const { id: accountId } = await makeTestSimpleAccount(source, { parent_account_id: dealerId, - tier: 5 + tier: 5, }); const { id: userId } = await makeTestUser(source, { account_id: accountId, @@ -740,7 +750,7 @@ describe('ライセンス割り当て', () => { }, ], })); - } + }, }); overrideSendgridService(service, { diff --git a/dictation_server/src/features/tasks/test/utility.ts b/dictation_server/src/features/tasks/test/utility.ts index 9931b6b..0f21df0 100644 --- a/dictation_server/src/features/tasks/test/utility.ts +++ b/dictation_server/src/features/tasks/test/utility.ts @@ -138,9 +138,8 @@ export const createTask = async ( label: `label${i}:audio_file_id${audioFileIdentifiers[0].id}`, value: `value${i}:audio_file_id${audioFileIdentifiers[0].id}`, }; - } - ); - + }); + await datasource.getRepository(AudioOptionItem).insert(audioOptionItems); const audioFile = audioFileIdentifiers.pop() as AudioFile; @@ -161,7 +160,7 @@ export const createTask = async ( return { taskId: task.id, audioFileId: audioFile.id }; }; -export const createAudioFile = async( +export const createAudioFile = async ( datasource: DataSource, account_id: number, owner_user_id: number, @@ -189,7 +188,7 @@ export const createAudioFile = async( }); const audioFile = audioFileIdentifiers.pop() as AudioFile; return { audioFileId: audioFile.id }; -} +}; /** * diff --git a/dictation_server/src/features/users/types/types.ts b/dictation_server/src/features/users/types/types.ts index 7cd4e44..6f4edf9 100644 --- a/dictation_server/src/features/users/types/types.ts +++ b/dictation_server/src/features/users/types/types.ts @@ -18,6 +18,7 @@ import { } from '../../../common/validators/encryptionPassword.validator'; import { IsRoleAuthorDataValid } from '../../../common/validators/roleAuthor.validator'; import { Type } from 'class-transformer'; +import { IsAuthorIdValid } from '../../../common/validators/authorId.validator'; export class ConfirmRequest { @ApiProperty() @@ -90,6 +91,7 @@ export class SignupRequest { @ApiProperty({ required: false }) @IsRoleAuthorDataValid() + @IsAuthorIdValid() authorId?: string; @ApiProperty() @@ -225,6 +227,7 @@ export class PostUpdateUserRequest { @ApiProperty({ required: false }) @IsRoleAuthorDataValid() + @IsAuthorIdValid() authorId?: string; @ApiProperty() diff --git a/dictation_server/src/repositories/user_groups/errors/types.ts b/dictation_server/src/repositories/user_groups/errors/types.ts index 4a215a7..a499a27 100644 --- a/dictation_server/src/repositories/user_groups/errors/types.ts +++ b/dictation_server/src/repositories/user_groups/errors/types.ts @@ -18,4 +18,4 @@ export class TypistGroupNameAlreadyExistError extends Error { super(message); this.name = 'TypistGroupNameAlreadyExistError'; } -} \ No newline at end of file +} From b7db9c5fad19ee25ebaab8f49fe2353f865b51e0 Mon Sep 17 00:00:00 2001 From: "saito.k" Date: Mon, 19 Feb 2024 01:49:23 +0000 Subject: [PATCH 2/3] =?UTF-8?q?Merged=20PR=20752:=20[FB=E5=AF=BE=E5=BF=9C]?= =?UTF-8?q?Edge=E3=81=A7=E8=A1=A8=E7=A4=BA=E8=A8=80=E8=AA=9E=E3=81=8C?= =?UTF-8?q?=E5=88=87=E3=82=8A=E6=9B=BF=E3=82=8F=E3=82=89=E3=81=AA=E3=81=84?= =?UTF-8?q?=E3=81=93=E3=81=A8=E3=81=8C=E3=81=82=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 概要 [Task3728: 原因調査&調査結果をPBIに記載する](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/3728) - cookieから言語情報取得時にほかのcookieが存在していると、うまく取得できなくなってしまう - https://into-the-program.com/javascript-cant-get-value-cookie-name-array/ - この方法でほかのcookieがある場合でも半角スペースを排除して正しく取得できるようにした。 ## レビューポイント - 特になし ## 動作確認状況 - ローカルで確認 ## 補足 - 相談、参考資料などがあれば --- dictation_client/src/App.tsx | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/dictation_client/src/App.tsx b/dictation_client/src/App.tsx index 1d47893..f08dfd1 100644 --- a/dictation_client/src/App.tsx +++ b/dictation_client/src/App.tsx @@ -43,14 +43,18 @@ const App = (): JSX.Element => { // Language読み取り useLayoutEffect(() => { - const language = document.cookie - .trim() - .split(";") - .map((x) => x.split("=")) - .find((x) => x.length === 2 && x[0] === "language"); + const { cookie } = document; - if (language) { - i18n.changeLanguage(language[1]); + if (cookie) { + const cookieArray = cookie.split(";"); + const language = cookieArray.find((x) => + // 先頭の空白を削除してから判定 + x.trim().startsWith("language=") + ); + + if (language) { + i18n.changeLanguage(language.split("=")[1]); + } } }, [i18n]); From 4caa23ba3c950474f981b33e249cc39447533305 Mon Sep 17 00:00:00 2001 From: "saito.k" Date: Mon, 19 Feb 2024 02:17:37 +0000 Subject: [PATCH 3/3] =?UTF-8?q?Merged=20PR=20755:=20[FB=E5=AF=BE=E5=BF=9C]?= =?UTF-8?q?File=20Property=E8=A1=A8=E7=A4=BA=E3=81=AB=E3=81=A4=E3=81=84?= =?UTF-8?q?=E3=81=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 概要 [Task3735: 対応](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/3735) - FilePropertyの表示順を変更する - カテゴリ(General、Job)はそのままで、OMDS様の希望する並び順にする ## レビューポイント - 並び順の変更にミスはないか ## 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/Task3735?csf=1&web=1&e=r3IhXL ## 動作確認状況 - ローカルで確認 ## 補足 - 相談、参考資料などがあれば --- .../pages/DictationPage/filePropertyPopup.tsx | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/dictation_client/src/pages/DictationPage/filePropertyPopup.tsx b/dictation_client/src/pages/DictationPage/filePropertyPopup.tsx index 1a4104c..979bbf1 100644 --- a/dictation_client/src/pages/DictationPage/filePropertyPopup.tsx +++ b/dictation_client/src/pages/DictationPage/filePropertyPopup.tsx @@ -50,16 +50,6 @@ export const FilePropertyPopup: React.FC = (props) => {
{selectedFileTask?.fileSize ?? ""}
{t(getTranslationID("dictationPage.label.fileLength"))}
{selectedFileTask?.audioDuration ?? ""}
-
{t(getTranslationID("dictationPage.label.authorId"))}
-
{selectedFileTask?.authorId ?? ""}
-
{t(getTranslationID("dictationPage.label.workType"))}
-
{selectedFileTask?.workType ?? ""}
-
{t(getTranslationID("dictationPage.label.priority"))}
-
- {selectedFileTask?.priority === "01" - ? PRIORITY.HIGH - : PRIORITY.NORMAL} -
{t(getTranslationID("dictationPage.label.recordingStartedDate"))}
@@ -68,8 +58,6 @@ export const FilePropertyPopup: React.FC = (props) => { {t(getTranslationID("dictationPage.label.recordingFinishedDate"))}
{selectedFileTask?.audioFinishedDate ?? ""}
-
{t(getTranslationID("dictationPage.label.uploadDate"))}
-
{selectedFileTask?.audioUploadedDate ?? ""}
{t(getTranslationID("dictationPage.label.encryption"))}
{selectedFileTask?.isEncrypted ? ( @@ -78,6 +66,16 @@ export const FilePropertyPopup: React.FC = (props) => { "" )}
+
{t(getTranslationID("dictationPage.label.priority"))}
+
+ {selectedFileTask?.priority === "01" + ? PRIORITY.HIGH + : PRIORITY.NORMAL} +
+
{t(getTranslationID("dictationPage.label.authorId"))}
+
{selectedFileTask?.authorId ?? ""}
+
{t(getTranslationID("dictationPage.label.workType"))}
+
{selectedFileTask?.workType ?? ""}
{t(getTranslationID("dictationPage.label.optionItem1"))}
{selectedFileTask?.optionItemList[0].optionItemValue}
{t(getTranslationID("dictationPage.label.optionItem2"))}
@@ -107,6 +105,10 @@ export const FilePropertyPopup: React.FC = (props) => {
{selectedFileTask?.jobNumber ?? ""}
{t(getTranslationID("dictationPage.label.status"))}
{selectedFileTask?.status ?? ""}
+
{t(getTranslationID("dictationPage.label.uploadDate"))}
+
{selectedFileTask?.audioUploadedDate ?? ""}
+
{t(getTranslationID("dictationPage.label.transcriptionist"))}
+
{selectedFileTask?.typist?.name ?? ""}
{t( getTranslationID("dictationPage.label.transcriptionStartedDate") @@ -119,8 +121,6 @@ export const FilePropertyPopup: React.FC = (props) => { )}
{selectedFileTask?.transcriptionFinishedDate ?? ""}
-
{t(getTranslationID("dictationPage.label.transcriptionist"))}
-
{selectedFileTask?.typist?.name ?? ""}
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}