Merge branch 'develop' into ccb
# Conflicts: # dictation_server/src/features/accounts/accounts.service.spec.ts
This commit is contained in:
commit
cdef84e269
@ -43,14 +43,18 @@ const App = (): JSX.Element => {
|
|||||||
|
|
||||||
// Language読み取り
|
// Language読み取り
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const language = document.cookie
|
const { cookie } = document;
|
||||||
.trim()
|
|
||||||
.split(";")
|
|
||||||
.map((x) => x.split("="))
|
|
||||||
.find((x) => x.length === 2 && x[0] === "language");
|
|
||||||
|
|
||||||
if (language) {
|
if (cookie) {
|
||||||
i18n.changeLanguage(language[1]);
|
const cookieArray = cookie.split(";");
|
||||||
|
const language = cookieArray.find((x) =>
|
||||||
|
// 先頭の空白を削除してから判定
|
||||||
|
x.trim().startsWith("language=")
|
||||||
|
);
|
||||||
|
|
||||||
|
if (language) {
|
||||||
|
i18n.changeLanguage(language.split("=")[1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [i18n]);
|
}, [i18n]);
|
||||||
|
|
||||||
|
|||||||
@ -45,7 +45,7 @@ export const worktypeSlice = createSlice({
|
|||||||
action: PayloadAction<{ worktypeId: string }>
|
action: PayloadAction<{ worktypeId: string }>
|
||||||
) => {
|
) => {
|
||||||
const { worktypeId } = action.payload;
|
const { worktypeId } = action.payload;
|
||||||
state.apps.worktypeId = worktypeId;
|
state.apps.worktypeId = worktypeId.toUpperCase();
|
||||||
},
|
},
|
||||||
changeDescription: (
|
changeDescription: (
|
||||||
state,
|
state,
|
||||||
@ -65,7 +65,12 @@ export const worktypeSlice = createSlice({
|
|||||||
optionItem.defaultValueType !== OPTION_ITEMS_DEFAULT_VALUE_TYPE.DEFAULT
|
optionItem.defaultValueType !== OPTION_ITEMS_DEFAULT_VALUE_TYPE.DEFAULT
|
||||||
) {
|
) {
|
||||||
optionItem.initialValue = "";
|
optionItem.initialValue = "";
|
||||||
|
} else {
|
||||||
|
// defaultValueTypeがDefaultの場合はinitialValueを大文字にする
|
||||||
|
optionItem.initialValue = optionItem.initialValue.toUpperCase();
|
||||||
}
|
}
|
||||||
|
// itemLabelを大文字にする
|
||||||
|
optionItem.itemLabel = optionItem.itemLabel.toUpperCase();
|
||||||
|
|
||||||
// idが一致するoptionItemを削除して、新しいoptionItemを追加する。一致するidがない場合は何もしない
|
// idが一致するoptionItemを削除して、新しいoptionItemを追加する。一致するidがない場合は何もしない
|
||||||
const optionItems = state.apps.optionItems?.filter(
|
const optionItems = state.apps.optionItems?.filter(
|
||||||
|
|||||||
@ -50,16 +50,6 @@ export const FilePropertyPopup: React.FC<FilePropertyPopupProps> = (props) => {
|
|||||||
<dd>{selectedFileTask?.fileSize ?? ""}</dd>
|
<dd>{selectedFileTask?.fileSize ?? ""}</dd>
|
||||||
<dt>{t(getTranslationID("dictationPage.label.fileLength"))}</dt>
|
<dt>{t(getTranslationID("dictationPage.label.fileLength"))}</dt>
|
||||||
<dd>{selectedFileTask?.audioDuration ?? ""}</dd>
|
<dd>{selectedFileTask?.audioDuration ?? ""}</dd>
|
||||||
<dt>{t(getTranslationID("dictationPage.label.authorId"))}</dt>
|
|
||||||
<dd>{selectedFileTask?.authorId ?? ""}</dd>
|
|
||||||
<dt>{t(getTranslationID("dictationPage.label.workType"))}</dt>
|
|
||||||
<dd>{selectedFileTask?.workType ?? ""}</dd>
|
|
||||||
<dt>{t(getTranslationID("dictationPage.label.priority"))}</dt>
|
|
||||||
<dd>
|
|
||||||
{selectedFileTask?.priority === "01"
|
|
||||||
? PRIORITY.HIGH
|
|
||||||
: PRIORITY.NORMAL}
|
|
||||||
</dd>
|
|
||||||
<dt>
|
<dt>
|
||||||
{t(getTranslationID("dictationPage.label.recordingStartedDate"))}
|
{t(getTranslationID("dictationPage.label.recordingStartedDate"))}
|
||||||
</dt>
|
</dt>
|
||||||
@ -68,8 +58,6 @@ export const FilePropertyPopup: React.FC<FilePropertyPopupProps> = (props) => {
|
|||||||
{t(getTranslationID("dictationPage.label.recordingFinishedDate"))}
|
{t(getTranslationID("dictationPage.label.recordingFinishedDate"))}
|
||||||
</dt>
|
</dt>
|
||||||
<dd>{selectedFileTask?.audioFinishedDate ?? ""}</dd>
|
<dd>{selectedFileTask?.audioFinishedDate ?? ""}</dd>
|
||||||
<dt>{t(getTranslationID("dictationPage.label.uploadDate"))}</dt>
|
|
||||||
<dd>{selectedFileTask?.audioUploadedDate ?? ""}</dd>
|
|
||||||
<dt>{t(getTranslationID("dictationPage.label.encryption"))}</dt>
|
<dt>{t(getTranslationID("dictationPage.label.encryption"))}</dt>
|
||||||
<dd>
|
<dd>
|
||||||
{selectedFileTask?.isEncrypted ? (
|
{selectedFileTask?.isEncrypted ? (
|
||||||
@ -78,6 +66,16 @@ export const FilePropertyPopup: React.FC<FilePropertyPopupProps> = (props) => {
|
|||||||
""
|
""
|
||||||
)}
|
)}
|
||||||
</dd>
|
</dd>
|
||||||
|
<dt>{t(getTranslationID("dictationPage.label.priority"))}</dt>
|
||||||
|
<dd>
|
||||||
|
{selectedFileTask?.priority === "01"
|
||||||
|
? PRIORITY.HIGH
|
||||||
|
: PRIORITY.NORMAL}
|
||||||
|
</dd>
|
||||||
|
<dt>{t(getTranslationID("dictationPage.label.authorId"))}</dt>
|
||||||
|
<dd>{selectedFileTask?.authorId ?? ""}</dd>
|
||||||
|
<dt>{t(getTranslationID("dictationPage.label.workType"))}</dt>
|
||||||
|
<dd>{selectedFileTask?.workType ?? ""}</dd>
|
||||||
<dt>{t(getTranslationID("dictationPage.label.optionItem1"))}</dt>
|
<dt>{t(getTranslationID("dictationPage.label.optionItem1"))}</dt>
|
||||||
<dd>{selectedFileTask?.optionItemList[0].optionItemValue}</dd>
|
<dd>{selectedFileTask?.optionItemList[0].optionItemValue}</dd>
|
||||||
<dt>{t(getTranslationID("dictationPage.label.optionItem2"))}</dt>
|
<dt>{t(getTranslationID("dictationPage.label.optionItem2"))}</dt>
|
||||||
@ -107,6 +105,10 @@ export const FilePropertyPopup: React.FC<FilePropertyPopupProps> = (props) => {
|
|||||||
<dd>{selectedFileTask?.jobNumber ?? ""}</dd>
|
<dd>{selectedFileTask?.jobNumber ?? ""}</dd>
|
||||||
<dt>{t(getTranslationID("dictationPage.label.status"))}</dt>
|
<dt>{t(getTranslationID("dictationPage.label.status"))}</dt>
|
||||||
<dd>{selectedFileTask?.status ?? ""}</dd>
|
<dd>{selectedFileTask?.status ?? ""}</dd>
|
||||||
|
<dt>{t(getTranslationID("dictationPage.label.uploadDate"))}</dt>
|
||||||
|
<dd>{selectedFileTask?.audioUploadedDate ?? ""}</dd>
|
||||||
|
<dt>{t(getTranslationID("dictationPage.label.transcriptionist"))}</dt>
|
||||||
|
<dd>{selectedFileTask?.typist?.name ?? ""}</dd>
|
||||||
<dt>
|
<dt>
|
||||||
{t(
|
{t(
|
||||||
getTranslationID("dictationPage.label.transcriptionStartedDate")
|
getTranslationID("dictationPage.label.transcriptionStartedDate")
|
||||||
@ -119,8 +121,6 @@ export const FilePropertyPopup: React.FC<FilePropertyPopupProps> = (props) => {
|
|||||||
)}
|
)}
|
||||||
</dt>
|
</dt>
|
||||||
<dd>{selectedFileTask?.transcriptionFinishedDate ?? ""}</dd>
|
<dd>{selectedFileTask?.transcriptionFinishedDate ?? ""}</dd>
|
||||||
<dt>{t(getTranslationID("dictationPage.label.transcriptionist"))}</dt>
|
|
||||||
<dd>{selectedFileTask?.typist?.name ?? ""}</dd>
|
|
||||||
<dd className={`${styles.full} ${styles.alignRight}`}>
|
<dd className={`${styles.full} ${styles.alignRight}`}>
|
||||||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
|
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
|
||||||
<a onClick={closePopup} className={`${styles.buttonText}`}>
|
<a onClick={closePopup} className={`${styles.buttonText}`}>
|
||||||
|
|||||||
36
dictation_server/src/common/validators/authorId.validator.ts
Normal file
36
dictation_server/src/common/validators/authorId.validator.ts
Normal file
@ -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,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -19,7 +19,7 @@ export class IsRecorderAllowedCharacters
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 正規表現でWorktypeIDのチェックを行う
|
// 正規表現でWorktypeIDのチェックを行う
|
||||||
// 以下の禁則文字を除く半角英数記号
|
// 以下の禁則文字を除く大文字英数記号
|
||||||
// \ (backslash)
|
// \ (backslash)
|
||||||
// / (forward slash)
|
// / (forward slash)
|
||||||
// : (colon)
|
// : (colon)
|
||||||
@ -31,7 +31,7 @@ export class IsRecorderAllowedCharacters
|
|||||||
// | (vertical bar)
|
// | (vertical bar)
|
||||||
// . (period)
|
// . (period)
|
||||||
const regex =
|
const regex =
|
||||||
/^(?!.*\\)(?!.*\/)(?!.*:)(?!.*\*)(?!.*\?)(?!.*")(?!.*<)(?!.*>)(?!.*\|)(?!.*\.)[ -~]+$/;
|
/^(?!.*\\)(?!.*\/)(?!.*:)(?!.*\*)(?!.*\?)(?!.*")(?!.*<)(?!.*>)(?!.*\|)(?!.*\.)[A-Z0-9 !#$%&'()+,\-;=@\[\]^_`{}~]*$/;
|
||||||
return regex.test(value);
|
return regex.test(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -145,7 +145,7 @@ describe('createAccount', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
let _subject = '';
|
let _subject: string = '';
|
||||||
let _url: string | undefined = '';
|
let _url: string | undefined = '';
|
||||||
overrideSendgridService(service, {
|
overrideSendgridService(service, {
|
||||||
sendMail: async (
|
sendMail: async (
|
||||||
@ -6205,7 +6205,7 @@ describe('アカウント情報更新', () => {
|
|||||||
const module = await makeTestingModule(source);
|
const module = await makeTestingModule(source);
|
||||||
if (!module) fail();
|
if (!module) fail();
|
||||||
const service = module.get<AccountsService>(AccountsService);
|
const service = module.get<AccountsService>(AccountsService);
|
||||||
let _subject = '';
|
let _subject: string = '';
|
||||||
let _url: string | undefined = '';
|
let _url: string | undefined = '';
|
||||||
overrideSendgridService(service, {
|
overrideSendgridService(service, {
|
||||||
sendMail: async (
|
sendMail: async (
|
||||||
|
|||||||
@ -18,6 +18,7 @@ import {
|
|||||||
} from '../../../common/validators/encryptionPassword.validator';
|
} from '../../../common/validators/encryptionPassword.validator';
|
||||||
import { IsRoleAuthorDataValid } from '../../../common/validators/roleAuthor.validator';
|
import { IsRoleAuthorDataValid } from '../../../common/validators/roleAuthor.validator';
|
||||||
import { Type } from 'class-transformer';
|
import { Type } from 'class-transformer';
|
||||||
|
import { IsAuthorIdValid } from '../../../common/validators/authorId.validator';
|
||||||
|
|
||||||
export class ConfirmRequest {
|
export class ConfirmRequest {
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
@ -90,6 +91,7 @@ export class SignupRequest {
|
|||||||
|
|
||||||
@ApiProperty({ required: false })
|
@ApiProperty({ required: false })
|
||||||
@IsRoleAuthorDataValid()
|
@IsRoleAuthorDataValid()
|
||||||
|
@IsAuthorIdValid()
|
||||||
authorId?: string;
|
authorId?: string;
|
||||||
|
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
@ -225,6 +227,7 @@ export class PostUpdateUserRequest {
|
|||||||
|
|
||||||
@ApiProperty({ required: false })
|
@ApiProperty({ required: false })
|
||||||
@IsRoleAuthorDataValid()
|
@IsRoleAuthorDataValid()
|
||||||
|
@IsAuthorIdValid()
|
||||||
authorId?: string;
|
authorId?: string;
|
||||||
|
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user