package org.synyx.urlaubsverwaltung.web.person;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import org.synyx.urlaubsverwaltung.core.person.MailNotification;
import org.synyx.urlaubsverwaltung.core.person.Person;
import org.synyx.urlaubsverwaltung.core.person.PersonService;
import org.synyx.urlaubsverwaltung.core.person.Role;
import org.synyx.urlaubsverwaltung.web.MailAddressValidationUtil;
import java.util.Collection;
import java.util.Optional;
/**
* This class validate if master data of a {@link Person} is filled correctly.
*
* @author Aljona Murygina
*/
@Component
class PersonValidator implements Validator {
private static final String ERROR_MANDATORY_FIELD = "error.entry.mandatory";
private static final String ERROR_LENGTH = "error.entry.tooManyChars";
private static final String ERROR_EMAIL = "error.entry.mail";
private static final String ERROR_LOGIN_UNIQUE = "person.form.data.login.error";
private static final String ERROR_PERMISSIONS_MANDATORY = "person.form.permissions.error.mandatory";
private static final String ERROR_PERMISSIONS_INACTIVE_ROLE = "person.form.permissions.error.inactive";
private static final String ERROR_PERMISSIONS_USER_ROLE = "person.form.permissions.error.user";
private static final String ERROR_PERMISSIONS_COMBINATION = "person.form.permissions.error.combination";
private static final String ERROR_NOTIFICATIONS_COMBINATION = "person.form.notifications.error.combination";
private static final String ATTRIBUTE_LOGIN_NAME = "loginName";
private static final String ATTRIBUTE_FIRST_NAME = "firstName";
private static final String ATTRIBUTE_LAST_NAME = "lastName";
private static final String ATTRIBUTE_EMAIL = "email";
private static final String ATTRIBUTE_PERMISSIONS = "permissions";
private static final int MAX_CHARS = 50;
private final PersonService personService;
@Autowired
PersonValidator(PersonService personService) {
this.personService = personService;
}
@Override
public boolean supports(Class<?> clazz) {
return Person.class.equals(clazz);
}
@Override
public void validate(Object target, Errors errors) {
Person person = (Person) target;
if (person.getId() == null) {
validateLogin(person.getLoginName(), errors);
}
validateName(person.getFirstName(), ATTRIBUTE_FIRST_NAME, errors);
validateName(person.getLastName(), ATTRIBUTE_LAST_NAME, errors);
validateEmail(person.getEmail(), errors);
validatePermissions(person, errors);
validateNotifications(person, errors);
}
void validateLogin(String login, Errors errors) {
validateName(login, ATTRIBUTE_LOGIN_NAME, errors);
if (!errors.hasFieldErrors(ATTRIBUTE_LOGIN_NAME)) {
// validate unique login name
Optional<Person> person = personService.getPersonByLogin(login);
if (person.isPresent()) {
errors.rejectValue(ATTRIBUTE_LOGIN_NAME, ERROR_LOGIN_UNIQUE);
}
}
}
void validateName(String name, String field, Errors errors) {
if (StringUtils.hasText(name)) {
if (!validateStringLength(name)) {
errors.rejectValue(field, ERROR_LENGTH);
}
} else {
errors.rejectValue(field, ERROR_MANDATORY_FIELD);
}
}
void validateEmail(String email, Errors errors) {
if (StringUtils.hasText(email)) {
if (!validateStringLength(email)) {
errors.rejectValue(ATTRIBUTE_EMAIL, ERROR_LENGTH);
}
if (!MailAddressValidationUtil.hasValidFormat(email)) {
errors.rejectValue(ATTRIBUTE_EMAIL, ERROR_EMAIL);
}
} else {
errors.rejectValue(ATTRIBUTE_EMAIL, ERROR_MANDATORY_FIELD);
}
}
private boolean validateStringLength(String string) {
return string.length() <= MAX_CHARS;
}
void validatePermissions(Person person, Errors errors) {
Collection<Role> roles = person.getPermissions();
if (roles == null || roles.isEmpty()) {
errors.rejectValue(ATTRIBUTE_PERMISSIONS, ERROR_PERMISSIONS_MANDATORY);
return;
}
// if role inactive set, then only this role may be selected
if (roles.contains(Role.INACTIVE) && roles.size() != 1) {
errors.rejectValue(ATTRIBUTE_PERMISSIONS, ERROR_PERMISSIONS_INACTIVE_ROLE);
return;
}
// user role must always be selected for active user
if (!roles.contains(Role.INACTIVE) && !roles.contains(Role.USER)) {
errors.rejectValue(ATTRIBUTE_PERMISSIONS, ERROR_PERMISSIONS_USER_ROLE);
return;
}
validateCombinationOfRoles(roles, errors);
}
private void validateCombinationOfRoles(Collection<Role> roles, Errors errors) {
if (roles.contains(Role.DEPARTMENT_HEAD) && (roles.contains(Role.BOSS) || roles.contains(Role.OFFICE))) {
errors.rejectValue(ATTRIBUTE_PERMISSIONS, ERROR_PERMISSIONS_COMBINATION);
return;
}
if (roles.contains(Role.SECOND_STAGE_AUTHORITY) && (roles.contains(Role.BOSS) || roles.contains(Role.OFFICE))) {
errors.rejectValue(ATTRIBUTE_PERMISSIONS, ERROR_PERMISSIONS_COMBINATION);
}
}
void validateNotifications(Person person, Errors errors) {
Collection<Role> roles = person.getPermissions();
Collection<MailNotification> notifications = person.getNotifications();
if (roles != null) {
validateCombinationOfNotificationAndRole(roles, notifications, Role.DEPARTMENT_HEAD,
MailNotification.NOTIFICATION_DEPARTMENT_HEAD, errors);
validateCombinationOfNotificationAndRole(roles, notifications, Role.SECOND_STAGE_AUTHORITY,
MailNotification.NOTIFICATION_SECOND_STAGE_AUTHORITY, errors);
validateCombinationOfNotificationAndRole(roles, notifications, Role.BOSS,
MailNotification.NOTIFICATION_BOSS, errors);
validateCombinationOfNotificationAndRole(roles, notifications, Role.OFFICE,
MailNotification.NOTIFICATION_OFFICE, errors);
}
}
private void validateCombinationOfNotificationAndRole(Collection<Role> roles,
Collection<MailNotification> notifications, Role role, MailNotification notification, Errors errors) {
if (notifications.contains(notification) && !roles.contains(role)) {
errors.rejectValue("notifications", ERROR_NOTIFICATIONS_COMBINATION);
}
}
}