Web: Studio: SSO: Added validation

This commit is contained in:
Dmitry Kulak 2022-02-14 12:42:59 +03:00
parent 18edef78ba
commit 14282d7a6f
7 changed files with 138 additions and 2 deletions

View File

@ -11,6 +11,7 @@
"CustomEntryTooltip": "Надпись для кнопки, которая используется для входа на портал с помощью сервиса Single Sign-on",
"DecryptStatements": "Расшифровывать утверждения",
"DownloadMetadataXML": "Скачать XML-файл метаданных поставщика сервиса",
"EmptyFieldErrorMessage": "Поле не заполнено",
"EndpointURL": "URL-адрес конечной точки единого входа IdP:",
"EndpointURLTooltip": "URL-адрес, используемый для единого входа на стороне поставщика учетных записей",
"FirstName": "Имя",
@ -49,5 +50,8 @@
"TurnOnSSOCaption": "Включите эту опцию, если вы хотите автоматически добавить на портал пользователей из сервиса SSO",
"TurnOnSSOTooltip": "Включите эту опцию, если вы хотите автоматически добавить на портал пользователей из сервиса SSO",
"UploadXML": "Для автоматического заполнения необходимых полей загрузите метаданные из XML-файла",
"UploadXMLPlaceholder": "URL адрес XML-файла метаданных"
"UploadXMLPlaceholder": "URL адрес XML-файла метаданных",
"emailErrorMessage": "Неверный формат электронной почты",
"phoneErrorMessage": "Неверный формат номера телефона",
"urlErrorMessage": "Недопустимый URL-адрес"
}

View File

@ -29,6 +29,7 @@ const FieldMapping = ({ FormStore, t }) => {
labelText={t("FirstName")}
name="firstName"
placeholder="givenName"
t={t}
tabIndex={16}
/>
@ -37,6 +38,7 @@ const FieldMapping = ({ FormStore, t }) => {
labelText={t("LastName")}
name="lastName"
placeholder="sn"
t={t}
tabIndex={17}
/>
@ -45,6 +47,7 @@ const FieldMapping = ({ FormStore, t }) => {
labelText={t("Common:Email")}
name="email"
placeholder="sn"
t={t}
tabIndex={18}
/>
@ -53,6 +56,7 @@ const FieldMapping = ({ FormStore, t }) => {
labelText={t("Location")}
name="location"
placeholder="sn"
t={t}
tabIndex={19}
/>
@ -61,6 +65,7 @@ const FieldMapping = ({ FormStore, t }) => {
labelText={t("Title")}
name="title"
placeholder="sn"
t={t}
tabIndex={20}
/>
@ -69,6 +74,7 @@ const FieldMapping = ({ FormStore, t }) => {
labelText={t("Common:Phone")}
name="phone"
placeholder="sn"
t={t}
tabIndex={21}
/>

View File

@ -23,6 +23,7 @@ const IdpSettings = ({ FormStore, t }) => {
labelText={t("CustomEntryButton")}
name="spLoginLabel"
placeholder="Single Sign-on"
t={t}
tabIndex={4}
tooltipContent={t("CustomEntryTooltip")}
/>
@ -32,6 +33,7 @@ const IdpSettings = ({ FormStore, t }) => {
labelText={t("ProviderURL")}
name="entityId"
placeholder="https://www.test.com"
t={t}
tabIndex={5}
tooltipContent={t("ProviderURLTooltip")}
/>

View File

@ -17,6 +17,7 @@ const ProviderMetadata = ({ FormStore, t }) => {
labelText={t("SPEntityId")}
name="sp_entityId"
placeholder="https://www.test.com"
t={t}
tabIndex={25}
tooltipContent={t("SPEntityIdTooltip")}
/>
@ -26,6 +27,7 @@ const ProviderMetadata = ({ FormStore, t }) => {
labelText={t("SPAssertionConsumerURL")}
name="sp_assertionConsumerUrl"
placeholder="https://www.test.com"
t={t}
tabIndex={26}
tooltipContent={t("SPAssertionConsumerURLTooltip")}
/>
@ -35,6 +37,7 @@ const ProviderMetadata = ({ FormStore, t }) => {
labelText={t("SPSingleLogoutURL")}
name="sp_singleLogoutUrl"
placeholder="https://www.test.com"
t={t}
tabIndex={27}
tooltipContent={t("SPSingleLogoutURLTooltip")}
/>

View File

@ -11,11 +11,14 @@ const SimpleFormField = ({
labelText,
name,
placeholder,
t,
tabIndex,
tooltipContent,
}) => {
return (
<FieldContainer
errorMessage={t(FormStore[`${name}ErrorMessage`])}
hasError={FormStore[`${name}HasError`]}
inlineHelpButton
isVertical
labelText={labelText}
@ -25,6 +28,7 @@ const SimpleFormField = ({
{children}
<SimpleTextInput
FormStore={FormStore}
hasError={FormStore[`${name}errorMessage`]}
name={name}
placeholder={placeholder}
tabIndex={tabIndex}

View File

@ -6,6 +6,7 @@ import TextInput from "@appserver/components/text-input";
const SimpleTextInput = ({
FormStore,
hasError,
maxWidth,
name,
placeholder,
@ -15,7 +16,9 @@ const SimpleTextInput = ({
<StyledInputWrapper maxWidth={maxWidth}>
<TextInput
className="field-input"
hasError={hasError}
name={name}
onBlur={FormStore.onBlur}
onChange={FormStore.onTextInputChange}
placeholder={placeholder}
scale

View File

@ -1,5 +1,22 @@
import { makeAutoObservable } from "mobx";
const regExps = {
// source: https://regexr.com/3ok5o
url: new RegExp(
"([a-z]{1,2}tps?):\\/\\/((?:(?!(?:\\/|#|\\?|&)).)+)(?:(\\/(?:(?:(?:(?!(?:#|\\?|&)).)+\\/))?))?(?:((?:(?!(?:\\.|$|\\?|#)).)+))?(?:(\\.(?:(?!(?:\\?|$|#)).)+))?(?:(\\?(?:(?!(?:$|#)).)+))?(?:(#.+))?"
),
// source: https://regexr.com/2rhq7
email: new RegExp(
"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?"
),
// source: https://regexr.com/38pvb
phone: new RegExp(
"^\\s*(?:\\+?(\\d{1,3}))?([-. (]*(\\d{3})[-. )]*)?((\\d{3})[-. ]*(\\d{2,4})(?:[-.x ]*(\\d+))?)\\s*$"
),
};
class SsoFormStore {
uploadXmlUrl = "";
@ -51,12 +68,69 @@ class SsoFormStore {
sp_assertionConsumerUrl = "";
sp_singleLogoutUrl = "";
//hide parts of form
// hide parts of form
ServiceProviderSettings = true;
ShowAdditionalParameters = true;
SPMetadata = true;
isModalVisible = false;
// touched fields
uploadXmlUrlTouched = false;
spLoginLabelTouched = false;
entityIdTouched = false;
ssoUrlTouched = false;
sloUrlTouched = false;
firstNameTouched = false;
lastNameTouched = false;
emailTouched = false;
locationTouched = false;
titleTouched = false;
phoneTouched = false;
sp_entityIdTouched = false;
sp_assertionConsumerUrlTouched = false;
sp_singleLogoutUrlTouched = false;
// errors
uploadXmlUrlHasError = false;
spLoginLabelHasError = false;
entityIdHasError = false;
ssoUrlHasError = false;
sloUrlHasError = false;
firstNameHasError = false;
lastNameHasError = false;
emailHasError = false;
locationHasError = false;
titleHasError = false;
phoneHasError = false;
sp_entityIdHasError = false;
sp_assertionConsumerUrlHasError = false;
sp_singleLogoutUrlHasError = false;
// error messages
uploadXmlUrlErrorMessage = null;
spLoginLabelErrorMessage = null;
entityIdErrorMessage = null;
ssoUrlErrorMessage = null;
sloUrlErrorMessage = null;
firstNameErrorMessage = null;
lastNameErrorMessage = null;
emailErrorMessage = null;
locationErrorMessage = null;
titleErrorMessage = null;
phoneErrorMessage = null;
sp_entityIdErrorMessage = null;
sp_assertionConsumerUrlErrorMessage = null;
sp_singleLogoutUrlErrorMessage = null;
constructor() {
makeAutoObservable(this);
}
@ -96,6 +170,46 @@ class SsoFormStore {
onAddCertificate = () => {
console.log("новый сертификат:", this.newIdpCertificate);
this.isModalVisible = false;
this.newIdpCertificate = "";
};
onBlur = (e) => {
const field = e.target.name;
const fieldTouched = `${field}Touched`;
const fieldError = `${field}HasError`;
const fieldErrorMessage = `${field}ErrorMessage`;
const value = e.target.value;
this[fieldTouched] = true;
const validateResult = this.validate(value, this.getFieldType(field));
if (typeof validateResult !== "string") {
this[fieldError] = false;
this[fieldErrorMessage] = null;
} else {
this[fieldError] = true;
this[fieldErrorMessage] = validateResult;
}
};
getFieldType = (field) => {
if (field.toLowerCase().includes("url")) return "url";
if (field.includes("entityId")) return "url";
if (field.includes("email")) return "email";
if (field.includes("phone")) return "phone";
return "string";
};
validate = (string, type) => {
string = string.trim();
if (string.length === 0) return "EmptyFieldErrorMessage";
if (type === "string") return true;
return regExps[type].test(string) ? true : `${type}ErrorMessage`;
};
}