Merge pull request #376 from ONLYOFFICE/bugfix/profile-form-validation
Bugfix/profile form validation
This commit is contained in:
commit
596ff52ed4
@ -92,6 +92,9 @@ class SettingsStore {
|
|||||||
};
|
};
|
||||||
debugInfo = false;
|
debugInfo = false;
|
||||||
|
|
||||||
|
userFormValidation = /^[\p{L}\p{M}'\-]+$/gu;
|
||||||
|
folderFormValidation = new RegExp('[*+:"<>?|\\\\/]', "gim");
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
makeAutoObservable(this);
|
makeAutoObservable(this);
|
||||||
}
|
}
|
||||||
|
@ -182,15 +182,15 @@ export default function withContent(WrappedContent) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
renameTitle = (e) => {
|
renameTitle = (e) => {
|
||||||
const { t } = this.props;
|
const { t, folderFormValidation } = this.props;
|
||||||
|
|
||||||
let title = e.target.value;
|
let title = e.target.value;
|
||||||
//const chars = '*+:"<>?|/'; TODO: think how to solve problem with interpolation escape values in i18n translate
|
//const chars = '*+:"<>?|/'; TODO: think how to solve problem with interpolation escape values in i18n translate
|
||||||
const regexp = new RegExp('[*+:"<>?|\\\\/]', "gim");
|
|
||||||
if (title.match(regexp)) {
|
if (title.match(folderFormValidation)) {
|
||||||
toastr.warning(t("ContainsSpecCharacter"));
|
toastr.warning(t("ContainsSpecCharacter"));
|
||||||
}
|
}
|
||||||
title = title.replace(regexp, "_");
|
title = title.replace(folderFormValidation, "_");
|
||||||
return this.setState({ itemTitle: title });
|
return this.setState({ itemTitle: title });
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -324,7 +324,11 @@ export default function withContent(WrappedContent) {
|
|||||||
id: fileActionId,
|
id: fileActionId,
|
||||||
} = filesStore.fileActionStore;
|
} = filesStore.fileActionStore;
|
||||||
const { replaceFileStream, setEncryptionAccess } = auth;
|
const { replaceFileStream, setEncryptionAccess } = auth;
|
||||||
const { culture, isDesktopClient } = auth.settingsStore;
|
const {
|
||||||
|
culture,
|
||||||
|
isDesktopClient,
|
||||||
|
folderFormValidation,
|
||||||
|
} = auth.settingsStore;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
setIsLoading,
|
setIsLoading,
|
||||||
@ -346,6 +350,7 @@ export default function withContent(WrappedContent) {
|
|||||||
homepage: config.homepage,
|
homepage: config.homepage,
|
||||||
viewer: auth.userStore.user,
|
viewer: auth.userStore.user,
|
||||||
viewAs,
|
viewAs,
|
||||||
|
folderFormValidation,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
)(observer(WithContent));
|
)(observer(WithContent));
|
||||||
|
@ -29,6 +29,7 @@ const PureConnectDialogContainer = (props) => {
|
|||||||
setConnectDialogVisible,
|
setConnectDialogVisible,
|
||||||
personal,
|
personal,
|
||||||
getSubfolders,
|
getSubfolders,
|
||||||
|
folderFormValidation,
|
||||||
} = props;
|
} = props;
|
||||||
const {
|
const {
|
||||||
corporate,
|
corporate,
|
||||||
@ -80,12 +81,11 @@ const PureConnectDialogContainer = (props) => {
|
|||||||
setIsTitleValid(true);
|
setIsTitleValid(true);
|
||||||
let title = e.target.value;
|
let title = e.target.value;
|
||||||
//const chars = '*+:"<>?|/'; TODO: think how to solve problem with interpolation escape values in i18n translate
|
//const chars = '*+:"<>?|/'; TODO: think how to solve problem with interpolation escape values in i18n translate
|
||||||
const regexp = new RegExp('[*+:"<>?|\\\\/]', "gim");
|
|
||||||
|
|
||||||
if (title.match(regexp)) {
|
if (title.match(folderFormValidation)) {
|
||||||
toastr.warning(t("Home:ContainsSpecCharacter"));
|
toastr.warning(t("Home:ContainsSpecCharacter"));
|
||||||
}
|
}
|
||||||
title = title.replace(regexp, "_");
|
title = title.replace(folderFormValidation, "_");
|
||||||
|
|
||||||
setCustomerTitleValue(title);
|
setCustomerTitleValue(title);
|
||||||
};
|
};
|
||||||
@ -340,7 +340,11 @@ export default inject(
|
|||||||
openConnectWindow,
|
openConnectWindow,
|
||||||
fetchThirdPartyProviders,
|
fetchThirdPartyProviders,
|
||||||
} = settingsStore.thirdPartyStore;
|
} = settingsStore.thirdPartyStore;
|
||||||
const { getOAuthToken, personal } = auth.settingsStore;
|
const {
|
||||||
|
getOAuthToken,
|
||||||
|
personal,
|
||||||
|
folderFormValidation,
|
||||||
|
} = auth.settingsStore;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
treeFolders,
|
treeFolders,
|
||||||
@ -364,6 +368,7 @@ export default inject(
|
|||||||
providers,
|
providers,
|
||||||
visible,
|
visible,
|
||||||
item,
|
item,
|
||||||
|
folderFormValidation,
|
||||||
|
|
||||||
getOAuthToken,
|
getOAuthToken,
|
||||||
getSubfolders,
|
getSubfolders,
|
||||||
|
@ -19,5 +19,7 @@
|
|||||||
"TemporaryPassword": "Vorübergehendes Kennwort",
|
"TemporaryPassword": "Vorübergehendes Kennwort",
|
||||||
"TermsOfUsePopupHelperLink": "Erfahren Sie mehr über die Nutzungsbedingungen",
|
"TermsOfUsePopupHelperLink": "Erfahren Sie mehr über die Nutzungsbedingungen",
|
||||||
"UpdatingProcess": "Wird aktualisiert...",
|
"UpdatingProcess": "Wird aktualisiert...",
|
||||||
"WriteComment": "Kommentar hinzufügen"
|
"WriteComment": "Kommentar hinzufügen",
|
||||||
|
"ErrorInvalidUserLastName": "Ungültiger Nachname",
|
||||||
|
"ErrorInvalidUserFirstName": "Ungültiger Vorname"
|
||||||
}
|
}
|
||||||
|
@ -20,5 +20,7 @@
|
|||||||
"TemporaryPassword": "Temporary password",
|
"TemporaryPassword": "Temporary password",
|
||||||
"TermsOfUsePopupHelperLink": "Read more about terms of use",
|
"TermsOfUsePopupHelperLink": "Read more about terms of use",
|
||||||
"UpdatingProcess": "Updating...",
|
"UpdatingProcess": "Updating...",
|
||||||
"WriteComment": "Add comment"
|
"WriteComment": "Add comment",
|
||||||
|
"ErrorInvalidUserLastName": "Invalid last name",
|
||||||
|
"ErrorInvalidUserFirstName": "Invalid first name"
|
||||||
}
|
}
|
||||||
|
@ -19,5 +19,7 @@
|
|||||||
"TemporaryPassword": "Mot de passe temporaire",
|
"TemporaryPassword": "Mot de passe temporaire",
|
||||||
"TermsOfUsePopupHelperLink": "Savoir plus à propos de termes d'utilisation ",
|
"TermsOfUsePopupHelperLink": "Savoir plus à propos de termes d'utilisation ",
|
||||||
"UpdatingProcess": "Mis à jour...",
|
"UpdatingProcess": "Mis à jour...",
|
||||||
"WriteComment": "Ajouter un commentaire"
|
"WriteComment": "Ajouter un commentaire",
|
||||||
|
"ErrorInvalidUserLastName": "Prénom invalide",
|
||||||
|
"ErrorInvalidUserFirstName": "Nom invalide"
|
||||||
}
|
}
|
||||||
|
@ -19,5 +19,7 @@
|
|||||||
"TemporaryPassword": "Password temporanea",
|
"TemporaryPassword": "Password temporanea",
|
||||||
"TermsOfUsePopupHelperLink": "Maggiori dettagli sui termini di utilizzo",
|
"TermsOfUsePopupHelperLink": "Maggiori dettagli sui termini di utilizzo",
|
||||||
"UpdatingProcess": "Caricamento in corso...",
|
"UpdatingProcess": "Caricamento in corso...",
|
||||||
"WriteComment": "Aggiungi commento"
|
"WriteComment": "Aggiungi commento",
|
||||||
|
"ErrorInvalidUserLastName": "Cognome non valido",
|
||||||
|
"ErrorInvalidUserFirstName": "Nome non valido"
|
||||||
}
|
}
|
||||||
|
@ -19,5 +19,7 @@
|
|||||||
"TemporaryPassword": "Senha temporária",
|
"TemporaryPassword": "Senha temporária",
|
||||||
"TermsOfUsePopupHelperLink": "Leia mais sobre os termos de uso",
|
"TermsOfUsePopupHelperLink": "Leia mais sobre os termos de uso",
|
||||||
"UpdatingProcess": "Atualizando...",
|
"UpdatingProcess": "Atualizando...",
|
||||||
"WriteComment": "Adicionar comentário"
|
"WriteComment": "Adicionar comentário",
|
||||||
|
"ErrorInvalidUserLastName": "Sobrenome inválido",
|
||||||
|
"ErrorInvalidUserFirstName": "Primeiro nome inválido"
|
||||||
}
|
}
|
||||||
|
@ -20,5 +20,7 @@
|
|||||||
"TemporaryPassword": "Временный пароль",
|
"TemporaryPassword": "Временный пароль",
|
||||||
"TermsOfUsePopupHelperLink": "Подробнее об условиях использования",
|
"TermsOfUsePopupHelperLink": "Подробнее об условиях использования",
|
||||||
"UpdatingProcess": "Обновление...",
|
"UpdatingProcess": "Обновление...",
|
||||||
"WriteComment": "Добавить комментарий"
|
"WriteComment": "Добавить комментарий",
|
||||||
|
"ErrorInvalidUserLastName": "Недопустимая фамилия",
|
||||||
|
"ErrorInvalidUserFirstName": "Недопустимое имя"
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ class TextField extends React.Component {
|
|||||||
isRequired,
|
isRequired,
|
||||||
hasError,
|
hasError,
|
||||||
labelText,
|
labelText,
|
||||||
|
errorMessage,
|
||||||
|
|
||||||
inputName,
|
inputName,
|
||||||
inputValue,
|
inputValue,
|
||||||
@ -32,6 +33,7 @@ class TextField extends React.Component {
|
|||||||
<FieldContainer
|
<FieldContainer
|
||||||
isRequired={isRequired}
|
isRequired={isRequired}
|
||||||
hasError={hasError}
|
hasError={hasError}
|
||||||
|
errorMessage={errorMessage}
|
||||||
labelText={labelText}
|
labelText={labelText}
|
||||||
tooltipContent={tooltipContent}
|
tooltipContent={tooltipContent}
|
||||||
helpButtonHeaderContent={helpButtonHeaderContent}
|
helpButtonHeaderContent={helpButtonHeaderContent}
|
||||||
|
@ -242,8 +242,19 @@ class CreateUserForm extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onInputChange = (event) => {
|
onInputChange = (event) => {
|
||||||
|
const { userFormValidation } = this.props;
|
||||||
var stateCopy = Object.assign({}, this.state);
|
var stateCopy = Object.assign({}, this.state);
|
||||||
stateCopy.profile[event.target.name] = event.target.value;
|
const value = event.target.value;
|
||||||
|
const title = event.target.name;
|
||||||
|
|
||||||
|
if (!value.match(userFormValidation)) {
|
||||||
|
stateCopy.errors[title] = true;
|
||||||
|
} else {
|
||||||
|
if (this.state.errors[title]) stateCopy.errors[title] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
stateCopy.profile[title] = value;
|
||||||
|
|
||||||
this.setState(stateCopy);
|
this.setState(stateCopy);
|
||||||
this.setIsEdit();
|
this.setIsEdit();
|
||||||
};
|
};
|
||||||
@ -262,8 +273,20 @@ class CreateUserForm extends React.Component {
|
|||||||
this.setIsEdit();
|
this.setIsEdit();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
scrollToErrorForm = () => {
|
||||||
|
const element = this.mainFieldsContainerRef.current;
|
||||||
|
const parent = element.closest(".scroll-body");
|
||||||
|
(parent || window).scrollTo(0, element.offsetTop);
|
||||||
|
};
|
||||||
|
|
||||||
validate = () => {
|
validate = () => {
|
||||||
const { profile, errors: stateErrors } = this.state;
|
const { profile, errors: stateErrors } = this.state;
|
||||||
|
|
||||||
|
if (stateErrors.firstName || stateErrors.lastName) {
|
||||||
|
this.scrollToErrorForm();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const errors = {
|
const errors = {
|
||||||
firstName: !profile.firstName.trim(),
|
firstName: !profile.firstName.trim(),
|
||||||
lastName: !profile.lastName.trim(),
|
lastName: !profile.lastName.trim(),
|
||||||
@ -274,9 +297,7 @@ class CreateUserForm extends React.Component {
|
|||||||
errors.firstName || errors.lastName || errors.email || errors.password;
|
errors.firstName || errors.lastName || errors.email || errors.password;
|
||||||
|
|
||||||
if (hasError) {
|
if (hasError) {
|
||||||
const element = this.mainFieldsContainerRef.current;
|
this.scrollToErrorForm();
|
||||||
const parent = element.closest(".scroll-body");
|
|
||||||
(parent || window).scrollTo(0, element.offsetTop);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({ errors: errors });
|
this.setState({ errors: errors });
|
||||||
@ -436,6 +457,9 @@ class CreateUserForm extends React.Component {
|
|||||||
const pattern = getUserContactsPattern();
|
const pattern = getUserContactsPattern();
|
||||||
const contacts = getUserContacts(profile.contacts);
|
const contacts = getUserContacts(profile.contacts);
|
||||||
|
|
||||||
|
const notEmptyFirstName = Boolean(profile.firstName.trim());
|
||||||
|
const notEmptyLastName = Boolean(profile.lastName.trim());
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<MainContainer>
|
<MainContainer>
|
||||||
@ -470,6 +494,9 @@ class CreateUserForm extends React.Component {
|
|||||||
<TextField
|
<TextField
|
||||||
isRequired={true}
|
isRequired={true}
|
||||||
hasError={errors.firstName}
|
hasError={errors.firstName}
|
||||||
|
{...(notEmptyFirstName && {
|
||||||
|
errorMessage: t("ErrorInvalidUserFirstName"),
|
||||||
|
})}
|
||||||
labelText={`${t("FirstName")}:`}
|
labelText={`${t("FirstName")}:`}
|
||||||
inputName="firstName"
|
inputName="firstName"
|
||||||
inputValue={profile.firstName}
|
inputValue={profile.firstName}
|
||||||
@ -481,6 +508,9 @@ class CreateUserForm extends React.Component {
|
|||||||
<TextField
|
<TextField
|
||||||
isRequired={true}
|
isRequired={true}
|
||||||
hasError={errors.lastName}
|
hasError={errors.lastName}
|
||||||
|
{...(notEmptyLastName && {
|
||||||
|
errorMessage: t("ErrorInvalidUserLastName"),
|
||||||
|
})}
|
||||||
labelText={`${t("Common:LastName")}:`}
|
labelText={`${t("Common:LastName")}:`}
|
||||||
inputName="lastName"
|
inputName="lastName"
|
||||||
inputValue={profile.lastName}
|
inputValue={profile.lastName}
|
||||||
@ -687,6 +717,7 @@ export default withRouter(
|
|||||||
setCroppedAvatar: peopleStore.avatarEditorStore.setCroppedAvatar,
|
setCroppedAvatar: peopleStore.avatarEditorStore.setCroppedAvatar,
|
||||||
updateProfileInUsers: peopleStore.usersStore.updateProfileInUsers,
|
updateProfileInUsers: peopleStore.usersStore.updateProfileInUsers,
|
||||||
updateCreatedAvatar: peopleStore.targetUserStore.updateCreatedAvatar,
|
updateCreatedAvatar: peopleStore.targetUserStore.updateCreatedAvatar,
|
||||||
|
userFormValidation: auth.settingsStore.userFormValidation,
|
||||||
}))(
|
}))(
|
||||||
observer(
|
observer(
|
||||||
withTranslation(["ProfileAction", "Common", "Translations"])(
|
withTranslation(["ProfileAction", "Common", "Translations"])(
|
||||||
|
@ -238,8 +238,19 @@ class UpdateUserForm extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onInputChange(event) {
|
onInputChange(event) {
|
||||||
|
const { userFormValidation } = this.props;
|
||||||
var stateCopy = Object.assign({}, this.state);
|
var stateCopy = Object.assign({}, this.state);
|
||||||
stateCopy.profile[event.target.name] = event.target.value;
|
const value = event.target.value;
|
||||||
|
const title = event.target.name;
|
||||||
|
|
||||||
|
if (!value.match(userFormValidation)) {
|
||||||
|
stateCopy.errors[title] = true;
|
||||||
|
} else {
|
||||||
|
if (this.state.errors[title]) stateCopy.errors[title] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
stateCopy.profile[title] = value;
|
||||||
|
|
||||||
this.setState(stateCopy);
|
this.setState(stateCopy);
|
||||||
this.setIsEdit();
|
this.setIsEdit();
|
||||||
}
|
}
|
||||||
@ -278,21 +289,30 @@ class UpdateUserForm extends React.Component {
|
|||||||
this.setIsEdit();
|
this.setIsEdit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scrollToErrorForm = () => {
|
||||||
|
const element = this.mainFieldsContainerRef.current;
|
||||||
|
const parent = element.closest(".scroll-body");
|
||||||
|
(parent || window).scrollTo(0, element.offsetTop);
|
||||||
|
};
|
||||||
validate() {
|
validate() {
|
||||||
const { profile } = this.state;
|
const { profile, errors } = this.state;
|
||||||
const errors = {
|
|
||||||
|
if (errors.firstName || errors.lastName) {
|
||||||
|
this.scrollToErrorForm();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const errorsObj = {
|
||||||
firstName: !profile.firstName.trim(),
|
firstName: !profile.firstName.trim(),
|
||||||
lastName: !profile.lastName.trim(),
|
lastName: !profile.lastName.trim(),
|
||||||
};
|
};
|
||||||
const hasError = errors.firstName || errors.lastName;
|
const hasError = errorsObj.firstName || errorsObj.lastName;
|
||||||
|
|
||||||
if (hasError) {
|
if (hasError) {
|
||||||
const element = this.mainFieldsContainerRef.current;
|
this.scrollToErrorForm();
|
||||||
const parent = element.closest(".scroll-body");
|
|
||||||
(parent || window).scrollTo(0, element.offsetTop);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({ errors: errors });
|
this.setState({ errors: errorsObj });
|
||||||
return !hasError;
|
return !hasError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -615,6 +635,8 @@ class UpdateUserForm extends React.Component {
|
|||||||
|
|
||||||
const pattern = getUserContactsPattern();
|
const pattern = getUserContactsPattern();
|
||||||
const contacts = getUserContacts(profile.contacts);
|
const contacts = getUserContacts(profile.contacts);
|
||||||
|
const notEmptyFirstName = Boolean(profile.firstName.trim());
|
||||||
|
const notEmptyLastName = Boolean(profile.lastName.trim());
|
||||||
//TODO: inject guestsCaption in 'ProfileTypePopupHelper' key instead of hardcoded 'Guests'
|
//TODO: inject guestsCaption in 'ProfileTypePopupHelper' key instead of hardcoded 'Guests'
|
||||||
const tooltipTypeContent = (
|
const tooltipTypeContent = (
|
||||||
<>
|
<>
|
||||||
@ -790,6 +812,9 @@ class UpdateUserForm extends React.Component {
|
|||||||
isRequired={true}
|
isRequired={true}
|
||||||
hasError={errors.firstName}
|
hasError={errors.firstName}
|
||||||
labelText={`${t("FirstName")}:`}
|
labelText={`${t("FirstName")}:`}
|
||||||
|
{...(notEmptyFirstName && {
|
||||||
|
errorMessage: t("ErrorInvalidUserFirstName"),
|
||||||
|
})}
|
||||||
inputName="firstName"
|
inputName="firstName"
|
||||||
inputValue={profile.firstName}
|
inputValue={profile.firstName}
|
||||||
inputIsDisabled={isLoading}
|
inputIsDisabled={isLoading}
|
||||||
@ -802,6 +827,9 @@ class UpdateUserForm extends React.Component {
|
|||||||
<TextField
|
<TextField
|
||||||
isRequired={true}
|
isRequired={true}
|
||||||
hasError={errors.lastName}
|
hasError={errors.lastName}
|
||||||
|
{...(notEmptyLastName && {
|
||||||
|
errorMessage: t("ErrorInvalidUserLastName"),
|
||||||
|
})}
|
||||||
labelText={`${t("Common:LastName")}:`}
|
labelText={`${t("Common:LastName")}:`}
|
||||||
inputName="lastName"
|
inputName="lastName"
|
||||||
inputValue={profile.lastName}
|
inputValue={profile.lastName}
|
||||||
@ -1020,6 +1048,7 @@ export default withRouter(
|
|||||||
isEditTargetUser: peopleStore.targetUserStore.isEditTargetUser,
|
isEditTargetUser: peopleStore.targetUserStore.isEditTargetUser,
|
||||||
personal: auth.settingsStore.personal,
|
personal: auth.settingsStore.personal,
|
||||||
setUserIsUpdate: auth.userStore.setUserIsUpdate,
|
setUserIsUpdate: auth.userStore.setUserIsUpdate,
|
||||||
|
userFormValidation: auth.settingsStore.userFormValidation,
|
||||||
}))(
|
}))(
|
||||||
observer(
|
observer(
|
||||||
withTranslation(["ProfileAction", "Common", "Translations"])(
|
withTranslation(["ProfileAction", "Common", "Translations"])(
|
||||||
|
Loading…
Reference in New Issue
Block a user