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]); 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_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 */} 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 af5ac04..0eb2c6f 100644 --- a/dictation_server/src/features/accounts/accounts.service.spec.ts +++ b/dictation_server/src/features/accounts/accounts.service.spec.ts @@ -145,7 +145,7 @@ describe('createAccount', () => { }, }); - let _subject = ''; + let _subject: string = ''; let _url: string | undefined = ''; overrideSendgridService(service, { sendMail: async ( @@ -6205,7 +6205,7 @@ describe('アカウント情報更新', () => { const module = await makeTestingModule(source); if (!module) fail(); const service = module.get(AccountsService); - let _subject = ''; + let _subject: string = ''; let _url: string | undefined = ''; overrideSendgridService(service, { sendMail: async ( diff --git a/dictation_server/src/features/users/types/types.ts b/dictation_server/src/features/users/types/types.ts index 195e9c7..1c17c52 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()