Merge branch 'master' of github.com:ONLYOFFICE/CommunityServer-AspNetCore

This commit is contained in:
Alexey Safronov 2019-09-16 10:55:43 +03:00
commit 39d2d91b04
14 changed files with 273 additions and 57 deletions

View File

@ -5,7 +5,7 @@ import { Avatar, Button, Textarea, Text, toastr, ModalDialog, TextInput, AvatarE
import { withTranslation } from 'react-i18next';
import { toEmployeeWrapper, getUserRole, getUserContactsPattern, getUserContacts, mapGroupsToGroupSelectorOptions, mapGroupSelectorOptionsToGroups, filterGroupSelectorOptions } from "../../../../../store/people/selectors";
import { updateProfile, updateAvatar } from '../../../../../store/profile/actions';
import { sendInstructionsToChangePassword } from "../../../../../store/services/api";
import { sendInstructionsToChangePassword, sendInstructionsToChangeEmail } from "../../../../../store/services/api";
import { MainContainer, AvatarContainer, MainFieldsContainer } from './FormFields/Form'
import TextField from './FormFields/TextField'
import TextChangeField from './FormFields/TextChangeField'
@ -80,7 +80,7 @@ class UpdateUserForm extends React.Component {
header: "",
body: "",
buttons: [],
newEmail: "",
newEmail: profile.email,
},
selector: {
visible: false,
@ -157,6 +157,10 @@ class UpdateUserForm extends React.Component {
}
onEmailChange(event) {
const emailRegex = /.+@.+\..+/;
const newEmail = event.target.value || this.state.dialog.newEmail;
const hasError = !emailRegex.test(newEmail);
const dialog = {
visible: true,
header: "Change email",
@ -167,8 +171,9 @@ class UpdateUserForm extends React.Component {
id="new-email"
scale={true}
isAutoFocussed={true}
value={event.target.value}
value={newEmail}
onChange={this.onEmailChange}
hasError={hasError}
/>
</Text.Body>
),
@ -179,16 +184,21 @@ class UpdateUserForm extends React.Component {
size="medium"
primary={true}
onClick={this.onSendEmailChangeInstructions}
isDisabled={hasError}
/>
],
newEmail: event.target.value
newEmail: newEmail
};
this.setState({ dialog: dialog })
}
onSendEmailChangeInstructions() {
toastr.success("Context action: Change email");
this.onDialogClose();
sendInstructionsToChangeEmail(this.state.profile.id, this.state.dialog.newEmail)
.then((res) => {
res.data.error ? toastr.error(res.data.error.message) : toastr.success(res.data.response)
})
.catch((error) => toastr.error(error.message))
.finally(this.onDialogClose);
}
onPasswordChange() {
@ -215,7 +225,9 @@ class UpdateUserForm extends React.Component {
onSendPasswordChangeInstructions() {
sendInstructionsToChangePassword(this.state.profile.email)
.then((res) => toastr.success(res.data.response))
.then((res) => {
res.data.error ? toastr.error(res.data.error.message) : toastr.success(res.data.response)
})
.catch((error) => toastr.error(error.message))
.finally(this.onDialogClose);
}
@ -248,7 +260,7 @@ class UpdateUserForm extends React.Component {
}
onDialogClose() {
const dialog = { visible: false };
const dialog = { visible: false, newEmail: this.state.profile.email };
this.setState({ dialog: dialog })
}

View File

@ -122,10 +122,16 @@ export function sendInstructionsToDelete() {
export function sendInstructionsToChangePassword(email) {
return IS_FAKE
? fakeApi.sendInstructionsToChangePassword(email)
? fakeApi.sendInstructionsToChangePassword()
: axios.post(`${API_URL}/people/password.json`, { email });
}
export function sendInstructionsToChangeEmail(userId, email) {
return IS_FAKE
? fakeApi.sendInstructionsToChangeEmail()
: axios.post(`${API_URL}/people/email.json`, { userId, email });
}
export function deleteUser(userId) {
return IS_FAKE
? fakeApi.deleteUser(userId)

View File

@ -527,6 +527,10 @@ export function sendInstructionsToChangePassword() {
return fakeResponse("Instruction has been sent successfully");
}
export function sendInstructionsToChangeEmail() {
return fakeResponse("Instruction has been sent successfully");
}
export function getGroup(groupId) {
return fakeResponse({
id: "06448c0a-7f10-4c6d-9ad4-f94de2235778",

View File

@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Net;
@ -643,7 +641,7 @@ namespace ASC.Employee.Core.Controllers
defaultBr.Read(defaultData, 0, (int)defaultUserPhoto.Length);
defaultBr.Close();
CheckImgFormat(data);
//CheckImgFormat(data);
if (model.Autosave)
{
@ -730,7 +728,7 @@ namespace ASC.Employee.Core.Controllers
br.Read(data, 0, (int)userPhoto.Length);
br.Close();
CheckImgFormat(data);
//CheckImgFormat(data);
if (model.Autosave)
{
@ -903,6 +901,54 @@ namespace ASC.Employee.Core.Controllers
return new EmployeeWraperFull(GetUserInfo(userid.ToString()), ApiContext);
}
[Create("email", false)]
public string SendEmailChangeInstructions(UpdateMemberModel model)
{
Guid.TryParse(model.UserId, out Guid userid);
if (userid == Guid.Empty) throw new ArgumentNullException("userid");
var email = (model.Email ?? "").Trim();
if (string.IsNullOrEmpty(email)) throw new Exception(Resource.ErrorEmailEmpty);
if (!email.TestEmailRegex()) throw new Exception(Resource.ErrorNotCorrectEmail);
var viewer = CoreContext.UserManager.GetUsers(Tenant.TenantId, SecurityContext.CurrentAccount.ID);
var user = CoreContext.UserManager.GetUsers(Tenant.TenantId, userid);
if (user == null)
throw new Exception(Resource.ErrorUserNotFound);
if (viewer == null || (user.IsOwner(Tenant) && viewer.ID != user.ID))
throw new Exception(Resource.ErrorAccessDenied);
var existentUser = CoreContext.UserManager.GetUserByEmail(Tenant.TenantId, email);
if (existentUser.ID != Constants.LostUser.ID)
throw new Exception(CustomNamingPeople.Substitute<Resource>("ErrorEmailAlreadyExists"));
if (!viewer.IsAdmin(Tenant))
{
StudioNotifyService.SendEmailChangeInstructions(Tenant.TenantId, user, email);
}
else
{
if (email == user.Email)
throw new Exception(Resource.ErrorEmailsAreTheSame);
user.Email = email;
user.ActivationStatus = EmployeeActivationStatus.NotActivated;
CoreContext.UserManager.SaveUserInfo(Tenant, user);
StudioNotifyService.SendEmailActivationInstructions(Tenant.TenantId, user, email);
}
MessageService.Send(MessageAction.UserSentEmailChangeInstructions, user.DisplayUserName(false));
return string.Format(Resource.MessageEmailChangeInstuctionsSentOnEmail, email);
}
private UserInfo GetUserInfo(string userNameOrId)
{
UserInfo user;
@ -1334,29 +1380,30 @@ namespace ASC.Employee.Core.Controllers
UserPhotoManager.SaveOrUpdatePhoto(Tenant, user.ID, imageByteArray);
}
private static void CheckImgFormat(byte[] data)
{
ImageFormat imgFormat;
//not working under unix
//private static void CheckImgFormat(byte[] data)
//{
// ImageFormat imgFormat;
try
{
using var stream = new MemoryStream(data);
using var img = new Bitmap(stream);
imgFormat = img.RawFormat;
}
catch (OutOfMemoryException)
{
throw new ImageSizeLimitException();
}
catch (ArgumentException error)
{
throw new UnknownImageFormatException(error);
}
// try
// {
// using var stream = new MemoryStream(data);
// using var img = new Bitmap(stream);
// imgFormat = img.RawFormat;
// }
// catch (OutOfMemoryException)
// {
// throw new ImageSizeLimitException();
// }
// catch (ArgumentException error)
// {
// throw new UnknownImageFormatException(error);
// }
if (!imgFormat.Equals(ImageFormat.Png) && !imgFormat.Equals(ImageFormat.Jpeg))
{
throw new UnknownImageFormatException();
}
}
// if (!imgFormat.Equals(ImageFormat.Png) && !imgFormat.Equals(ImageFormat.Jpeg))
// {
// throw new UnknownImageFormatException();
// }
//}
}
}

View File

@ -1,6 +1,6 @@
{
"name": "asc-web-components",
"version": "1.0.80",
"version": "1.0.81",
"description": "Ascensio System SIA component library",
"license": "AGPL-3.0",
"main": "dist/asc-web-components.js",

View File

@ -58,6 +58,11 @@ const baseDayProps = {
size: "base"
};
const selectedDate = new Date("09/12/2019");
const openToDate = new Date("09/12/2019");
const minDate = new Date("01/01/1970");
const maxDate = new Date("01/01/2020");
describe("Weekdays tests:", () => {
it("Weekdays renders without error", () => {
const wrapper = mount(<Weekdays {...baseWeekdaysProps} />);
@ -127,13 +132,11 @@ describe("Calendar tests:", () => {
expect(wrapper).toExist();
});
/*
it("Calendar has rendered content.", () => {
const wrapper = mount(<NewCalendar {...baseCalendarProps} />);
//expect(wrapper.find('span')).toExist();
expect(wrapper.find("div")).toExist();
expect(wrapper.find("ul")).not.toExist();
});
*/
it("Calendar not re-render test", () => {
const wrapper = shallow(<NewCalendar {...baseCalendarProps} />).instance();
@ -144,6 +147,48 @@ describe("Calendar tests:", () => {
expect(shouldUpdate).toBe(false);
});
it("Calendar selectedDate test", () => {
const wrapper = mount(
<NewCalendar {...baseCalendarProps} selectedDate={selectedDate} />
);
expect(wrapper.props().selectedDate).toEqual(selectedDate);
});
it("Calendar openToDate test", () => {
const wrapper = mount(
<NewCalendar {...baseCalendarProps} openToDate={openToDate} />
);
expect(wrapper.props().openToDate).toEqual(openToDate);
});
it("Calendar minDate test", () => {
const wrapper = mount(
<NewCalendar {...baseCalendarProps} minDate={minDate} />
);
expect(wrapper.props().minDate).toEqual(minDate);
});
it("Calendar maxDate test", () => {
const wrapper = mount(
<NewCalendar {...baseCalendarProps} maxDate={maxDate} />
);
expect(wrapper.props().maxDate).toEqual(maxDate);
});
it("Calendar themeColor test", () => {
const wrapper = mount(
<NewCalendar {...baseCalendarProps} themeColor={"#fff"} />
);
expect(wrapper.props().themeColor).toEqual("#fff");
});
it("Calendar locale test", () => {
const wrapper = mount(
<NewCalendar {...baseCalendarProps} locale={"en-GB"} />
);
expect(wrapper.prop("locale")).toEqual("en-GB");
});
it("Calendar disabled when isDisabled is passed", () => {
const wrapper = mount(
<NewCalendar {...baseCalendarProps} isDisabled={true} />

View File

@ -600,7 +600,9 @@ class Calendar extends Component {
openToDate,
minDate,
maxDate,
isDisabled
isDisabled,
locale,
themeColor
} = this.props;
const { hasError, optionsDays } = this.state;
@ -612,7 +614,9 @@ class Calendar extends Component {
this.compareDates(maxDate, nextProps.maxDate) === 0 &&
isDisabled === nextProps.isDisabled &&
hasError === nextState.hasError &&
optionsDays === nextState.optionsDays
optionsDays === nextState.optionsDays &&
locale === nextProps.locale &&
themeColor === nextProps.themeColor
) {
return false;
}

View File

@ -1,20 +1,82 @@
import React from 'react';
import { mount } from 'enzyme';
import DatePicker from '.';
describe('<DatePicker />', () => {
it('renders without error', () => {
const wrapper = mount(
<DatePicker
onChange={date => {
console.log('Selected date', date);
}}
selectedDate={new Date()}
minDate={new Date("1970/01/01")}
maxDate={new Date(new Date().getFullYear() + 1 + "/01/01")}
/>
);
import React from "react";
import { mount, shallow } from "enzyme";
import DatePicker from "./";
import moment from "moment";
const selectedDate = new Date("09/12/2019");
const minDate = new Date("01/01/1970");
const maxDate = new Date("01/01/2020");
describe("DatePicker tests", () => {
it("DatePicker renders without error", () => {
const wrapper = mount(<DatePicker />);
expect(wrapper).toExist();
});
it("DatePicker disabled when isDisabled is passed", () => {
const wrapper = mount(<DatePicker isDisabled={true} />);
expect(wrapper.prop("isDisabled")).toEqual(true);
});
it("DatePicker opened when inOpen is passed", () => {
const wrapper = mount(<DatePicker inOpen={true} />);
expect(wrapper.prop("inOpen")).toEqual(true);
});
it("DatePicker hasError is passed", () => {
const wrapper = mount(<DatePicker hasError={true} />);
expect(wrapper.prop("hasError")).toEqual(true);
});
it("DatePicker disabled when isReadOnly is passed", () => {
const wrapper = mount(<DatePicker isReadOnly={true} />);
expect(wrapper.prop("isReadOnly")).toEqual(true);
});
it("DatePicker minDate test", () => {
const wrapper = mount(<DatePicker minDate={minDate} />);
expect(wrapper.props().minDate).toEqual(minDate);
});
it("DatePicker maxDate test", () => {
const wrapper = mount(<DatePicker maxDate={maxDate} />);
expect(wrapper.props().maxDate).toEqual(maxDate);
});
it("DatePicker selectedDate test", () => {
const wrapper = mount(<DatePicker selectedDate={selectedDate} />);
expect(wrapper.props().selectedDate).toEqual(selectedDate);
});
it("DatePicker locale test", () => {
const wrapper = mount(<DatePicker locale={"en-GB"} />);
expect(wrapper.prop("locale")).toEqual("en-GB");
});
it("DatePicker themeColor test", () => {
const wrapper = mount(<DatePicker themeColor={"#fff"} />);
expect(wrapper.props().themeColor).toEqual("#fff");
});
it("DatePicker call onChange when changing value", () => {
const onChange = jest.fn(event => {
expect(event.target.value).toEqual("03/03/2000");
});
const event = { target: { value: moment("2000-03-03") } };
const wrapper = mount(<DatePicker onChange={onChange} />);
wrapper.simulate("change", event);
});
it("DatePicker test click event", () => {
const onClick = jest.fn(event => {
expect(event.inOpen).toEqual(true);
});
const wrapper = shallow(<DatePicker onClick={onClick} />);
wrapper.simulate("click");
});
it("DatePicker onFocus test", () => {
const onFocus = jest.fn;
const wrapper = mount(<DatePicker onFocus={onFocus} />);
wrapper.simulate("focus");
});
});

View File

@ -94,6 +94,9 @@
<data name="ErrorEmailEmpty" xml:space="preserve">
<value>Das Feld für die E-Mail-Adresse ist leer</value>
</data>
<data name="ErrorEmailsAreTheSame" xml:space="preserve">
<value>Die aktuelle E-Mail-Adresse und die neue sind gleich</value>
</data>
<data name="ErrorEmptyUploadFileSelected" xml:space="preserve">
<value>Die hochgeladene Datei konnte nicht gefunden werden</value>
</data>
@ -154,6 +157,9 @@
<data name="LdapSettingsTooManyOperations" xml:space="preserve">
<value>Zu viele LDAP-Operationen.</value>
</data>
<data name="MessageEmailChangeInstuctionsSentOnEmail" xml:space="preserve">
<value>Die Hinweise für die Änderung der E-Mail-Adresse wurden erfolgreich gesendet</value>
</data>
<data name="MessageYourPasswordSuccessfullySendedToEmail" xml:space="preserve">
<value>Die Hinweise für die Änderung des Kennworts wurden an die folgende E-Mail-Adresse versandt: {0}</value>
</data>

View File

@ -94,6 +94,9 @@
<data name="ErrorEmailEmpty" xml:space="preserve">
<value>Campo de correo electrónico está vacío</value>
</data>
<data name="ErrorEmailsAreTheSame" xml:space="preserve">
<value>El correo electrónico actual y el nuevo correo electrónico son iguales</value>
</data>
<data name="ErrorEmptyUploadFileSelected" xml:space="preserve">
<value>Imposible encontrar el archivo subido</value>
</data>
@ -154,6 +157,9 @@
<data name="LdapSettingsTooManyOperations" xml:space="preserve">
<value>Demasiado muchas operaciones LDAP.</value>
</data>
<data name="MessageEmailChangeInstuctionsSentOnEmail" xml:space="preserve">
<value>Las instrucciones para cambiar el correo electrónico se han enviado con éxito</value>
</data>
<data name="MessageYourPasswordSuccessfullySendedToEmail" xml:space="preserve">
<value>La contraseña de usuario ha sido enviada al e-mail {0}</value>
</data>

View File

@ -94,6 +94,9 @@
<data name="ErrorEmailEmpty" xml:space="preserve">
<value>Le champ Email est vide</value>
</data>
<data name="ErrorEmailsAreTheSame" xml:space="preserve">
<value>L'adresse email actuelle et la nouvelle adresse sont les mêmes</value>
</data>
<data name="ErrorEmptyUploadFileSelected" xml:space="preserve">
<value>Le fichier chargé ne peut pas être trouvé</value>
</data>
@ -156,6 +159,9 @@
<data name="LdapSettingsTooManyOperations" xml:space="preserve">
<value>Trop d'opérations LDAP.</value>
</data>
<data name="MessageEmailChangeInstuctionsSentOnEmail" xml:space="preserve">
<value>Les instructions de changement d'émail ont été envoyées avec succès</value>
</data>
<data name="MessageYourPasswordSuccessfullySendedToEmail" xml:space="preserve">
<value>Les instructions de changement de mot de passe ont été envoyées à {0}</value>
</data>

View File

@ -94,6 +94,9 @@
<data name="ErrorEmailEmpty" xml:space="preserve">
<value>Il campo Email è vuoto</value>
</data>
<data name="ErrorEmailsAreTheSame" xml:space="preserve">
<value>L'indirizzo email corrente coincide con quello nuovo.</value>
</data>
<data name="ErrorEmptyUploadFileSelected" xml:space="preserve">
<value>E' impossibile trovare il file caricato</value>
</data>
@ -154,6 +157,9 @@
<data name="LdapSettingsTooManyOperations" xml:space="preserve">
<value>Troppe operazioni LDAP</value>
</data>
<data name="MessageEmailChangeInstuctionsSentOnEmail" xml:space="preserve">
<value>Le istruzioni di modifica dell'email sono state inviate correttamente</value>
</data>
<data name="MessageYourPasswordSuccessfullySendedToEmail" xml:space="preserve">
<value>Le istruzioni di modifica della password sono state inviate all'indirizzo email {0}.</value>
</data>

View File

@ -94,6 +94,9 @@
<data name="ErrorEmailEmpty" xml:space="preserve">
<value>Email field is empty</value>
</data>
<data name="ErrorEmailsAreTheSame" xml:space="preserve">
<value>The current email and the new email are the same</value>
</data>
<data name="ErrorEmptyUploadFileSelected" xml:space="preserve">
<value>The uploaded file could not be found</value>
</data>
@ -154,6 +157,9 @@
<data name="LdapSettingsTooManyOperations" xml:space="preserve">
<value>Too many LDAP operations.</value>
</data>
<data name="MessageEmailChangeInstuctionsSentOnEmail" xml:space="preserve">
<value>The email change instructions have been successfuly sent</value>
</data>
<data name="MessageYourPasswordSuccessfullySendedToEmail" xml:space="preserve">
<value>The password change instructions have been sent to the {0} email address.</value>
</data>

View File

@ -94,6 +94,9 @@
<data name="ErrorEmailEmpty" xml:space="preserve">
<value>Не заполнено поле адреса электронной почты</value>
</data>
<data name="ErrorEmailsAreTheSame" xml:space="preserve">
<value>Текущий адрес электронной почты совпадает с новым адресом</value>
</data>
<data name="ErrorEmptyUploadFileSelected" xml:space="preserve">
<value>Загружаемый файл не найден</value>
</data>
@ -154,6 +157,9 @@
<data name="LdapSettingsTooManyOperations" xml:space="preserve">
<value>Слишком много операций LDAP.</value>
</data>
<data name="MessageEmailChangeInstuctionsSentOnEmail" xml:space="preserve">
<value>Инструкции по изменению электронной почты были успешно отправлены</value>
</data>
<data name="MessageYourPasswordSuccessfullySendedToEmail" xml:space="preserve">
<value>Инструкции по изменению пароля были высланы на email {0}</value>
</data>