package org.synyx.urlaubsverwaltung.web.application;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.synyx.urlaubsverwaltung.core.application.domain.Application;
import org.synyx.urlaubsverwaltung.core.application.domain.ApplicationStatus;
import org.synyx.urlaubsverwaltung.core.application.service.ApplicationService;
import org.synyx.urlaubsverwaltung.core.department.DepartmentService;
import org.synyx.urlaubsverwaltung.core.person.Person;
import org.synyx.urlaubsverwaltung.core.person.Role;
import org.synyx.urlaubsverwaltung.core.workingtime.WorkDaysService;
import org.synyx.urlaubsverwaltung.security.SecurityRules;
import org.synyx.urlaubsverwaltung.security.SessionService;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* Controller for showing applications for leave in a certain state.
*
* @author Aljona Murygina - murygina@synyx.de
*/
@Controller
@RequestMapping("/web")
public class ApplicationForLeaveController {
@Autowired
private ApplicationService applicationService;
@Autowired
private WorkDaysService calendarService;
@Autowired
private DepartmentService departmentService;
@Autowired
private SessionService sessionService;
/**
* Show waiting applications for leave.
*
* @return waiting applications for leave page
*/
@PreAuthorize(SecurityRules.IS_PRIVILEGED_USER)
@RequestMapping(value = "/application", method = RequestMethod.GET)
public String showWaiting(Model model) {
List<ApplicationForLeave> applicationsForLeave = getAllRelevantApplicationsForLeave();
model.addAttribute("applications", applicationsForLeave);
return "application/app_list";
}
private List<ApplicationForLeave> getAllRelevantApplicationsForLeave() {
Person user = sessionService.getSignedInUser();
boolean isHeadOf = user.hasRole(Role.DEPARTMENT_HEAD);
boolean isSecondStage = user.hasRole(Role.SECOND_STAGE_AUTHORITY);
boolean isBoss = user.hasRole(Role.BOSS);
boolean isOffice = user.hasRole(Role.OFFICE);
if (isBoss || isOffice) {
// Boss and Office can see all waiting and temporary allowed applications leave
return getApplicationsForLeaveForBossOrOffice();
}
if (isHeadOf) {
// Department head can see only waiting applications for leave of certain department(s)
return getApplicationsForLeaveForDepartmentHead(user);
}
if (isSecondStage) {
// Department head can see waiting and temporary allowed applications for leave of certain department(s)
return getApplicationsForLeaveForSecondStageAuthority(user);
}
return Collections.<ApplicationForLeave>emptyList();
}
private List<ApplicationForLeave> getApplicationsForLeaveForBossOrOffice() {
List<Application> applications = new ArrayList<>();
List<Application> waitingApplications = applicationService.getApplicationsForACertainState(
ApplicationStatus.WAITING);
List<Application> temporaryAllowedApplications = applicationService.getApplicationsForACertainState(
ApplicationStatus.TEMPORARY_ALLOWED);
applications.addAll(waitingApplications);
applications.addAll(temporaryAllowedApplications);
return applications.stream()
.map(application -> new ApplicationForLeave(application, calendarService))
.sorted(dateComparator())
.collect(Collectors.toList());
}
private Comparator<ApplicationForLeave> dateComparator() {
return (o1, o2) -> o1.getStartDate().compareTo(o2.getStartDate());
}
private List<ApplicationForLeave> getApplicationsForLeaveForDepartmentHead(Person head) {
List<Application> waitingApplications = applicationService.getApplicationsForACertainState(
ApplicationStatus.WAITING);
List<Person> members = departmentService.getManagedMembersOfDepartmentHead(head);
return waitingApplications.stream()
.filter(includeDepartmentApplications(members))
.filter(withoutOwnApplications(head))
.filter(withoutSecondStageAuthorityApplications())
.map(application -> new ApplicationForLeave(application, calendarService))
.sorted(dateComparator())
.collect(Collectors.toList());
}
private List<ApplicationForLeave> getApplicationsForLeaveForSecondStageAuthority(Person secondStage) {
List<Application> applications = new ArrayList<>();
List<Application> waitingApplications = applicationService.getApplicationsForACertainState(
ApplicationStatus.WAITING);
List<Application> temporaryAllowedApplications = applicationService.getApplicationsForACertainState(
ApplicationStatus.TEMPORARY_ALLOWED);
applications.addAll(waitingApplications);
applications.addAll(temporaryAllowedApplications);
List<Person> members = departmentService.getMembersForSecondStageAuthority(secondStage);
return applications.stream()
.filter(includeDepartmentApplications(members))
.filter(withoutOwnApplications(secondStage))
.map(application -> new ApplicationForLeave(application, calendarService))
.sorted(dateComparator())
.collect(Collectors.toList());
}
private Predicate<Application> withoutOwnApplications(Person head) {
return application -> !application.getPerson().equals(head);
}
private Predicate<Application> withoutSecondStageAuthorityApplications() {
return application -> !application.getPerson().getPermissions().contains(Role.SECOND_STAGE_AUTHORITY);
}
private Predicate<Application> includeDepartmentApplications(List<Person> members) {
return application -> members.contains(application.getPerson());
}
}