Skip to content
Snippets Groups Projects
Commit a4b52dba authored by Henry Page's avatar Henry Page :speech_balloon:
Browse files

initial impl

parent 031b871e
Branches
Tags
2 merge requests!664Version 2.1.4,!654Resolve "Cascade soft delete of core entities to queue"
Showing
with 156 additions and 113 deletions
......@@ -8,7 +8,7 @@ version = "2.1.2"
val javaVersion = JavaVersion.VERSION_17
val libradorVersion = "1.2.1"
val libradorVersion = "1.2.2"
val labradoorVersion = "1.3.5"
val queryDslVersion = "4.4.0"
......
......@@ -129,11 +129,11 @@ public class AdminController {
@GetMapping("/running")
public String getRunningLabs(Model model) {
LocalDateTime now = LocalDateTime.now();
var runningEditions = eCache.get(Objects.requireNonNull(
var runningEditions = eCache.getAndIgnoreMissing(Objects.requireNonNull(
eApi.getAllEditionsActiveAtDate(LocalDateTime.now())
.map(EditionSummaryDTO::getId).collectList().block()));
var runningSessions = sCache.get(runningEditions.stream()
var runningSessions = sCache.getAndIgnoreMissing(runningEditions.stream()
.flatMap(e -> e.getSessions().stream())
.filter(s -> s.getEnd().isAfter(now))
.map(SessionSummaryDTO::getId));
......
......@@ -29,6 +29,7 @@ import java.util.function.Predicate;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;
import javax.transaction.Transactional;
import javax.validation.Valid;
import nl.tudelft.labracore.api.*;
......@@ -48,11 +49,7 @@ import nl.tudelft.queue.model.LabRequest;
import nl.tudelft.queue.model.enums.QueueSessionType;
import nl.tudelft.queue.model.labs.Lab;
import nl.tudelft.queue.repository.QueueSessionRepository;
import nl.tudelft.queue.service.EditionService;
import nl.tudelft.queue.service.EditionStatusService;
import nl.tudelft.queue.service.PermissionService;
import nl.tudelft.queue.service.QuestionService;
import nl.tudelft.queue.service.RoleDTOService;
import nl.tudelft.queue.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
......@@ -141,6 +138,9 @@ public class EditionController {
@Autowired
private QuestionService qs;
@Autowired
private LabService ls;
/**
* Gets the page listing all editions. This page incorporates pageables to index many different editions
* and keep the overview small.
......@@ -164,7 +164,8 @@ public class EditionController {
.block();
eCache.register(editions.getContent());
erCache.get(editions.getContent().stream().map(EditionDetailsDTO::getId));
erCache.getAndIgnoreMissing(editions.getContent().stream().map(EditionDetailsDTO::getId));
model.addAttribute("editions",
new PageImpl<>(editions.getContent(), pageable, editions.getTotalElements()));
......@@ -224,7 +225,7 @@ public class EditionController {
if (!ps.canEnrolForEdition(editionId)) {
return "redirect:/editions";
}
model.addAttribute("edition", eCache.getOrThrow(editionId));
model.addAttribute("edition", eCache.getRequired(editionId));
return "edition/enrol";
}
......@@ -256,7 +257,7 @@ public class EditionController {
*/
@GetMapping("/edition/{editionId}")
public String getEditionView(@PathVariable Long editionId, Model model) {
model.addAttribute("edition", eCache.getOrThrow(editionId));
model.addAttribute("edition", eCache.getRequired(editionId));
return "edition/view/info";
}
......@@ -274,7 +275,7 @@ public class EditionController {
public String getEditionParticipantsView(@PathVariable Long editionId, Model model,
@RequestParam(value = "student-search", required = false) String studentSearch,
@PageableDefault(size = 25) Pageable pageable) {
var edition = eCache.getOrThrow(editionId);
var edition = eCache.getRequired(editionId);
var students = roleDTOService.students(edition);
if (studentSearch != null) {
......@@ -299,8 +300,8 @@ public class EditionController {
@GetMapping("/edition/{editionId}/modules")
@PreAuthorize("@permissionService.canViewEdition(#editionId)")
public String getEditionModulesView(@PathVariable Long editionId, Model model) {
var edition = eCache.getOrThrow(editionId);
var modules = mCache.get(edition.getModules().stream().map(ModuleSummaryDTO::getId));
var edition = eCache.getRequired(editionId);
var modules = mCache.getAndIgnoreMissing(edition.getModules().stream().map(ModuleSummaryDTO::getId));
modules.sort(Comparator.comparing(ModuleDetailsDTO::getName));
modules.forEach(m -> {
......@@ -308,14 +309,14 @@ public class EditionController {
m.getAssignments().sort(Comparator.comparing(AssignmentSummaryDTO::getName));
});
sgCache.get(modules.stream()
sgCache.getAndIgnoreMissing(modules.stream()
.flatMap(m -> m.getGroups().stream().map(StudentGroupSmallSummaryDTO::getId)));
model.addAttribute("edition", edition);
model.addAttribute("modules", modules);
model.addAttribute("groups", modules.stream()
.collect(Collectors.toMap(ModuleDetailsDTO::getId,
m -> sgCache.get(m.getGroups().stream().map(StudentGroupSmallSummaryDTO::getId)))));
m -> sgCache.getAndIgnoreMissing(m.getGroups().stream().map(StudentGroupSmallSummaryDTO::getId)))));
return "edition/view/modules";
}
......@@ -331,15 +332,17 @@ public class EditionController {
*/
@GetMapping("/edition/{editionId}/labs")
@PreAuthorize("@permissionService.canViewEdition(#editionId)")
@Transactional
public String getEditionSessionsView(@PathVariable Long editionId,
@RequestParam(required = false, defaultValue = "") List<QueueSessionType> queueSessionTypes,
@RequestParam(required = false, defaultValue = "") List<Long> modules,
Model model) {
var edition = eCache.getOrThrow(editionId);
var edition = eCache.getRequired(editionId);
// Make sure that session details are cached.
var sessions = sCache.get(edition.getSessions().stream()
.map(SessionSummaryDTO::getId));
var sessions = sCache.getAndHandleAll(edition.getSessions().stream()
.map(SessionSummaryDTO::getId), ls.deleteSessionsByIds());
// Find all labs from the sessions, convert to summaries, and filter.
var labs = es.filterLabs(
......@@ -369,7 +372,7 @@ public class EditionController {
@GetMapping("/edition/{editionId}/questions")
@PreAuthorize("@permissionService.canManageQuestions(#editionId)")
public String getEditionQuestions(@PathVariable Long editionId, Model model) {
model.addAttribute("edition", eCache.getOrThrow(editionId));
model.addAttribute("edition", eCache.getRequired(editionId));
model.addAttribute("questions", qApi.getQuestionsByEdition(editionId).collectList().block());
return "edition/view/questions";
......@@ -385,7 +388,7 @@ public class EditionController {
@GetMapping("/edition/{editionId}/participants/create")
@PreAuthorize("@permissionService.canManageParticipants(#editionId)")
public String getAddParticipantPage(@PathVariable Long editionId, Model model) {
model.addAttribute("edition", eCache.getOrThrow(editionId));
model.addAttribute("edition", eCache.getRequired(editionId));
model.addAttribute("role", new QueueRoleCreateDTO(editionId));
return "edition/create/participant";
......@@ -407,7 +410,7 @@ public class EditionController {
RoleCreateDTO create = dto.apply();
if (dto.hasErrors()) {
model.addAttribute("edition", eCache.getOrThrow(editionId));
model.addAttribute("edition", eCache.getRequired(editionId));
model.addAttribute("role", dto);
return "edition/create/participant";
......@@ -442,7 +445,7 @@ public class EditionController {
public String importParticipants(@PathVariable Long editionId,
@RequestParam("file") MultipartFile csv,
RedirectAttributes attributes) {
EditionDetailsDTO edition = eCache.getOrThrow(editionId);
EditionDetailsDTO edition = eCache.getRequired(editionId);
try {
es.addCourseParticipants(csv, edition);
......@@ -467,10 +470,10 @@ public class EditionController {
@PreAuthorize("@permissionService.canManageParticipants(#editionId)")
public String getRemoveParticipantPage(@PathVariable Long editionId, @PathVariable Long personId,
Model model) {
EditionDetailsDTO edition = eCache.getOrThrow(editionId);
EditionDetailsDTO edition = eCache.getRequired(editionId);
model.addAttribute("edition", edition);
model.addAttribute("role", rCache.getOrThrow(new Id()
model.addAttribute("role", rCache.getRequired(new Id()
.personId(personId).editionId(editionId)));
return "edition/remove/participant";
......@@ -517,7 +520,7 @@ public class EditionController {
@PreAuthorize("@permissionService.canLeaveEdition(#editionId)")
public String getParticipantLeavePage(@PathVariable Long editionId,
Model model) {
model.addAttribute("edition", eCache.getOrThrow(editionId));
model.addAttribute("edition", eCache.getRequired(editionId));
return "edition/view/leave";
}
......@@ -549,10 +552,12 @@ public class EditionController {
*/
@GetMapping("/edition/{editionId}/status")
@PreAuthorize("@permissionService.canViewEditionStatus(#editionId)")
@Transactional
public String status(@PathVariable Long editionId,
Model model) {
var edition = eCache.getOrThrow(editionId);
var sessions = sCache.get(edition.getSessions().stream().map(SessionSummaryDTO::getId));
var edition = eCache.getRequired(editionId);
var sessions = sCache.getAndHandleAll(edition.getSessions().stream().map(SessionSummaryDTO::getId), ls.deleteSessionsByIds());
model.addAttribute("edition", edition);
......@@ -561,9 +566,9 @@ public class EditionController {
model.addAttribute("inactiveLabs", getLabSummariesFromSessions(
sessions, s -> !(s.getStart().isBefore(now()) && now().isBefore(s.getEnd()))));
model.addAttribute("assignments", aCache.get(sessions.stream()
model.addAttribute("assignments", aCache.getAndIgnoreMissing(sessions.stream()
.flatMap(s -> s.getAssignments().stream().map(AssignmentSummaryDTO::getId)).distinct()));
model.addAttribute("rooms", rmCache.get(sessions.stream()
model.addAttribute("rooms", rmCache.getAndIgnoreMissing(sessions.stream()
.flatMap(s -> s.getRooms().stream().map(RoomDetailsDTO::getId)).distinct()));
return "edition/view/status";
......@@ -666,7 +671,7 @@ public class EditionController {
@PreAuthorize("@permissionService.canManageQuestions(#editionId)")
public String getEditQuestionPage(@PathVariable Long editionId, @PathVariable Long questionId,
Model model) {
EditionDetailsDTO edition = eCache.getOrThrow(editionId);
EditionDetailsDTO edition = eCache.getRequired(editionId);
model.addAttribute("edition", edition);
model.addAttribute("question", qApi.getQuestionById(questionId).block());
......@@ -708,7 +713,7 @@ public class EditionController {
@PreAuthorize("@permissionService.canManageQuestions(#editionId)")
public String getDeleteQuestionPage(@PathVariable Long editionId, @PathVariable Long questionId,
Model model) {
EditionDetailsDTO edition = eCache.getOrThrow(editionId);
EditionDetailsDTO edition = eCache.getRequired(editionId);
model.addAttribute("edition", edition);
model.addAttribute("question", qApi.getQuestionById(questionId).block());
......
......@@ -34,6 +34,7 @@ import nl.tudelft.queue.cache.PersonCacheManager;
import nl.tudelft.queue.cache.SessionCacheManager;
import nl.tudelft.queue.repository.LabRequestRepository;
import nl.tudelft.queue.repository.QueueSessionRepository;
import nl.tudelft.queue.service.LabService;
import nl.tudelft.queue.service.RequestTableService;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -46,6 +47,8 @@ import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import javax.transaction.Transactional;
@Controller
public class HistoryController {
......@@ -76,6 +79,9 @@ public class HistoryController {
@Autowired
private RequestTableService rts;
@Autowired
private LabService ls;
/**
* Gets the view representing the request history of the currently authenticated student.
*
......@@ -111,14 +117,14 @@ public class HistoryController {
@PathVariable Long editionId,
@PathVariable Long studentId,
@PageableDefault(sort = "createdAt", direction = Sort.Direction.DESC, size = 25) Pageable pageable) {
var edition = eCache.getOrThrow(editionId);
var edition = eCache.getRequired(editionId);
List<Long> groups = sgApi.getGroupsForPersonAndCourse(studentId, edition.getCourse().getId())
.map(StudentGroupSummaryDTO::getId)
.collectList().block();
model.addAttribute("edition", edition);
model.addAttribute("student", pCache.getOrThrow(studentId));
model.addAttribute("student", pCache.getRequired(studentId));
setHistoryModel("/history/edition/" + editionId + "/student/" + studentId,
model, studentId, groups, pageable);
......@@ -136,18 +142,21 @@ public class HistoryController {
* @param groupIds The ids of the groups to find requests for.
* @param pageable The pageable containing the information on the page to show.
*/
private void setHistoryModel(String key, Model model, Long studentId, List<Long> groupIds,
@Transactional
public void setHistoryModel(String key, Model model, Long studentId, List<Long> groupIds,
Pageable pageable) {
var editions = eCache.get(pApi.getRolesForPerson(studentId)
var editions = eCache.getAndIgnoreMissing(pApi.getRolesForPerson(studentId)
.filter(r -> r.getType() == RoleEditionDetailsDTO.TypeEnum.STUDENT)
.map(r -> r.getEdition().getId())
.toStream());
erCache.get(editions.stream().map(EditionDetailsDTO::getId));
erCache.getAndIgnoreMissing(editions.stream().map(EditionDetailsDTO::getId));
var sessionIds = editions.stream()
.flatMap(e -> e.getSessions().stream().map(SessionSummaryDTO::getId))
.collect(Collectors.toList());
sCache.get(sessionIds);
sCache.getAndHandleAll(sessionIds, ls.deleteSessionsByIds());
var labs = qsr.findAllBySessions(sessionIds);
......
......@@ -171,17 +171,17 @@ public class HomeController {
Set.of(TEACHER_RO).contains(role.getType()))
.collect(Collectors.toList());
var editions = eCache.get(roles.stream().map(r -> r.getEdition().getId()))
var editions = eCache.getAndIgnoreMissing(roles.stream().map(r -> r.getEdition().getId()))
.stream()
.collect(Collectors.toMap(EditionDetailsDTO::getId, Function.identity()));
Set<SessionDetailsDTO> sessions = new HashSet<>(sCache.get(editions.values().stream()
Set<SessionDetailsDTO> sessions = new HashSet<>(sCache.getAndHandleAll(editions.values().stream()
.flatMap(e -> e.getSessions().stream())
.filter(s -> s.getEnd().isAfter(now.minusMonths(1)))
.map(SessionSummaryDTO::getId)));
.map(SessionSummaryDTO::getId),missingIds -> ls.deleteSessionsByIds()));
var sharedEditions = editions.values().stream().map(EditionDetailsDTO::getEditionCollections)
.flatMap(List::stream).map(e -> ecCache.getOrThrow(e.getId()))
.flatMap(List::stream).map(e -> ecCache.getRequired(e.getId()))
.collect(Collectors.toSet());
var calendarEntries = ls.convertToCalendarEntries(
......@@ -198,7 +198,7 @@ public class HomeController {
var sharedLabs = sharedEditions.stream().collect(Collectors.toMap(
EditionCollectionDetailsDTO::getId,
s -> es.sortLabs(View.convert(new ArrayList<>(lr.findAllBySessions(
eCache.get(s.getEditions().stream().map(EditionSummaryDTO::getId).toList())
eCache.getAndIgnoreMissing(s.getEditions().stream().map(EditionSummaryDTO::getId).toList())
.stream().map(EditionDetailsDTO::getSessions).flatMap(List::stream)
.map(SessionSummaryDTO::getId).collect(Collectors.toList()))),
QueueSessionSummaryDTO.class)).stream()
......@@ -207,7 +207,7 @@ public class HomeController {
.collect(Collectors.toList())));
if (pd.getDefaultRole() == ADMIN || pd.getDefaultRole() == TEACHER) {
model.addAttribute("allEditions", eCache.get(
model.addAttribute("allEditions", eCache.getAndIgnoreMissing(
Objects.requireNonNullElse(
eApi.getAllEditionsActiveDuringPeriod(
new Period().start(LocalDateTime.now())
......@@ -280,7 +280,7 @@ public class HomeController {
* @param pageable The pageable containing information on how much feedback needs to be shown.
*/
private void fillInFeedbackModel(Long assistantId, Person person, Model model, Pageable pageable) {
var assistant = pCache.getOrThrow(assistantId);
var assistant = pCache.getRequired(assistantId);
Page<Feedback> feedback = assistantId.equals(person.getId())
? fr.findByAssistantAnonymised(assistantId, pageable)
......
......@@ -165,7 +165,7 @@ public class LabController {
.ifPresent(r -> model.addAttribute("selectionResult", r.toViewDTO()));
}
model.addAttribute("modules", mCache.get(qSession.getModules().stream()));
model.addAttribute("modules", mCache.getAndIgnoreMissing(qSession.getModules().stream()));
return "lab/view/" + qSession.getType().name().toLowerCase();
}
......@@ -233,7 +233,7 @@ public class LabController {
Model model) {
setEnqueuePageAttributes(lab, model, person);
model.addAttribute("assignment", aCache.getOrThrow(assignment));
model.addAttribute("assignment", aCache.getRequired(assignment));
return "lab/question";
}
......@@ -254,7 +254,7 @@ public class LabController {
Model model) {
setEnqueuePageAttributes(lab, model, person);
model.addAttribute("assignment", aCache.getOrThrow(assignment));
model.addAttribute("assignment", aCache.getRequired(assignment));
model.addAttribute("question", question);
model.addAttribute("request", new LabRequestCreateDTO());
model.addAttribute("rType", "lab");
......@@ -357,7 +357,7 @@ public class LabController {
public String getLabCreateView(@PathVariable Long editionId,
@RequestParam QueueSessionType type, Model model) {
model.addAttribute("dto", type.newCreateDto());
model.addAttribute("edition", eCache.getOrThrow(editionId));
model.addAttribute("edition", eCache.getRequired(editionId));
model.addAttribute("lType", type);
setSessionEditingPageAttributes(List.of(editionId), model);
......@@ -377,7 +377,7 @@ public class LabController {
@PreAuthorize("@permissionService.canManageSharedSessions(#editionCollectionId)")
public String getSharedLabCreateView(@PathVariable Long editionCollectionId,
@RequestParam QueueSessionType type, Model model) {
var editionCollection = ecCache.getOrThrow(editionCollectionId);
var editionCollection = ecCache.getRequired(editionCollectionId);
model.addAttribute("dto", type.newCreateDto());
model.addAttribute("ec", editionCollection);
......@@ -529,7 +529,7 @@ public class LabController {
@PreAuthorize("@permissionService.canManageSession(#qSession)")
public String deleteSession(@PathEntity QueueSession<?> qSession) {
ls.deleteSession(qSession);
var session = sCache.getOrThrow(qSession.getSession());
var session = sCache.getRequired(qSession.getSession(), id -> ls.deleteSession(qSession));
if (session.getEditionCollection() != null) {
return "redirect:/shared-edition/" + session.getEditionCollection().getId();
......@@ -550,7 +550,7 @@ public class LabController {
@PreAuthorize("@permissionService.canManageSession(#qSession)")
public String getLabCopyView(@PathEntity QueueSession<?> qSession,
Model model) {
var session = sCache.getOrThrow(qSession.getSession());
var session = sCache.getRequired(qSession.getSession(), id -> ls.deleteSession(qSession));
model.addAttribute("dto", qSession.copyLabCreateDTO(session));
model.addAttribute("lType", qSession.getType());
......@@ -688,8 +688,9 @@ public class LabController {
* @param model The model to fill using edition and lab information.
* @param person The person used to fill in the information.
*/
private void setEnqueuePageAttributes(QueueSession<?> qSession, Model model, Person person) {
var session = sCache.getOrThrow(qSession.getSession());
@Transactional
public void setEnqueuePageAttributes(QueueSession<?> qSession, Model model, Person person) {
var session = sCache.getRequired(qSession.getSession(), id -> ls.deleteSession(qSession));
session.getRooms().sort(Comparator.comparing(r -> r.getBuilding().getName() + r.getName()));
model.addAttribute("qSession", qSession.toViewDTO());
......@@ -701,26 +702,26 @@ public class LabController {
var lab = (Lab) qSession;
var isStaffInAll = session.getEditions().stream().allMatch(e -> roleService
.rolesForPersonInEdition(e, person).stream().allMatch(roleService::isStaff));
List<AssignmentDetailsDTO> allowedAssignments = aCache.get(lab.getAllowedRequests().stream()
.map(AllowedRequest::getAssignment).distinct().collect(Collectors.toList()))
List<AssignmentDetailsDTO> allowedAssignments = aCache.getAndHandleAll(lab.getAllowedRequests().stream()
.map(AllowedRequest::getAssignment).distinct().collect(Collectors.toList()), assignmentIds -> lab.getAllowedRequests().removeIf(a -> assignmentIds.contains(a.getAssignment())))
.stream().filter(a -> {
var edition = mCache.getOrThrow(a.getModule().getId()).getEdition();
var edition = mCache.getRequired(a.getModule().getId()).getEdition();
return isStaffInAll || roleService.rolesForPersonInEdition(edition, person).stream()
.noneMatch(roleService::isStaff);
}).toList();
Map<Long, String> assignments = allowedAssignments.stream()
.collect(Collectors.toMap(AssignmentDetailsDTO::getId, a -> {
var edition = mCache.getOrThrow(a.getModule().getId()).getEdition();
var edition = mCache.getRequired(a.getModule().getId()).getEdition();
return session.getEditions().size() == 1
? a.getName()
: eCache.getOrThrow(edition.getId()).getCourse().getName() + " - "
: eCache.getRequired(edition.getId()).getCourse().getName() + " - "
+ a.getName();
}));
Map<Long, Long> notEnqueueAble = allowedAssignments.stream().filter(a -> {
var edition = mCache.getOrThrow(a.getModule().getId()).getEdition();
var edition = mCache.getRequired(a.getModule().getId()).getEdition();
return roleService.rolesForPersonInEdition(edition, person).isEmpty();
}).collect(Collectors.toMap(AssignmentDetailsDTO::getId, a -> {
var edition = mCache.getOrThrow(a.getModule().getId()).getEdition();
var edition = mCache.getRequired(a.getModule().getId()).getEdition();
return edition.getId();
}));
......@@ -730,7 +731,7 @@ public class LabController {
.collect(Collectors.groupingBy(AllowedRequest::getAssignment,
Collectors.mapping(ar -> ar.getType().displayName(), Collectors.toSet()))));
} else {
model.addAttribute("modules", mCache.get(qSession.getModules().stream())
model.addAttribute("modules", mCache.getAndHandle(qSession.getModules().stream(), moduleID -> qSession.getModules().remove(moduleID))
.stream().sorted(Comparator.comparing(ModuleDetailsDTO::getName))
.collect(Collectors.toList()));
}
......@@ -743,14 +744,14 @@ public class LabController {
* @param model The model to fill using edition information.
*/
private void setSessionEditingPageAttributes(List<Long> editionIds, Model model) {
var editions = eCache.get(editionIds);
var editions = eCache.getAndIgnoreMissing(editionIds);
var modules = mCache.get(editions.stream()
var modules = mCache.getAndIgnoreMissing(editions.stream()
.flatMap(e -> e.getModules().stream().map(ModuleSummaryDTO::getId).distinct()));
var assignments = aCache.get(modules.stream()
var assignments = aCache.getAndIgnoreMissing(modules.stream()
.flatMap(m -> m.getAssignments().stream().map(AssignmentSummaryDTO::getId)).distinct());
var clusters = cCache
.get(editions.stream().map(e -> e.getCohort().getId()).distinct())
.getAndIgnoreMissing(editions.stream().map(e -> e.getCohort().getId()).distinct())
.stream().flatMap(cohort -> cohort.getClusters().stream()).distinct()
.sorted(Comparator.comparing(ClusterSummaryDTO::getName)).collect(Collectors.toList());
......@@ -787,13 +788,13 @@ public class LabController {
* @param model The model to fill using lab information.
*/
private void setSessionEditingPageAttributes(QueueSession<?> qSession, Model model) {
var session = sCache.getOrThrow(qSession.getSession());
var session = sCache.getRequired(qSession.getSession(), id -> ls.deleteSession(qSession));
model.addAttribute("lSession", session);
if (session.getEdition() != null) {
model.addAttribute("edition", eCache.getOrThrow(session.getEdition().getId()));
model.addAttribute("edition", eCache.getRequired(session.getEdition().getId()));
} else {
model.addAttribute("ec", ecCache.getOrThrow(session.getEditionCollection().getId()));
model.addAttribute("ec", ecCache.getRequired(session.getEditionCollection().getId()));
}
setSessionEditingPageAttributes(session.getEditions().stream()
......@@ -813,7 +814,7 @@ public class LabController {
Matcher matcher = testPattern.matcher(request.getRequestURI());
if (matcher.matches() && matcher.groupCount() == 1) {
Optional<QueueSession<?>> lab = qsRepository.findById(Long.parseLong(matcher.group(1)));
var session = sCache.getOrThrow(lab.orElseThrow().getSession());
var session = sCache.getRequired(lab.orElseThrow().getSession(), id -> ls.deleteSession(lab.get()));
var edition = session.getEdition().getId();
return "redirect:/edition/" + edition + "/enrol";
}
......
......@@ -131,7 +131,7 @@ public class ModuleController {
* @return The Thymeleaf template to resolve.
*/
private String addCreateModuleAttributes(Long editionId, QueueModuleCreateDTO dto, Model model) {
EditionDetailsDTO edition = eCache.getOrThrow(editionId);
EditionDetailsDTO edition = eCache.getRequired(editionId);
model.addAttribute("edition", edition);
model.addAttribute("dto", dto);
......
......@@ -80,7 +80,7 @@ public class LabRequestCreateDTO extends RequestCreateDTO<LabRequest, Lab> {
errors.rejectValue("onlineMode", "Room or online mode not selected");
}
var session = getBean(SessionCacheManager.class).getOrThrow(this.getSession().getSession());
var session = getBean(SessionCacheManager.class).getRequired(this.getSession().getSession());
if (room != null && session.getRooms().stream().noneMatch(r -> Objects.equals(r.getId(), room))) {
errors.rejectValue("room", "A room with id " + room + " is not available in the lab.");
}
......@@ -99,7 +99,7 @@ public class LabRequestCreateDTO extends RequestCreateDTO<LabRequest, Lab> {
@Override
public Long getModule() {
return getBean(AssignmentCacheManager.class).getOrThrow(assignment)
return getBean(AssignmentCacheManager.class).getRequired(assignment)
.getModule().getId();
}
......
......@@ -43,6 +43,6 @@ public class ExamRequestViewDTO extends View<LabRequest> {
public void postApply() {
super.postApply();
requesterName = getBean(PersonCacheManager.class).getOrThrow(data.getRequester()).getDisplayName();
requesterName = getBean(PersonCacheManager.class).getRequired(data.getRequester()).getDisplayName();
}
}
......@@ -58,7 +58,7 @@ public class ExamTimeSlotViewDTO extends View<ClosableTimeSlot> {
handled = data.countHandledRequests();
// Ensure caching of exam request people and then get exam request views
getBean(PersonCacheManager.class).get(data.getRequests().stream().map(LabRequest::getRequester));
getBean(PersonCacheManager.class).getAndIgnoreMissing(data.getRequests().stream().map(LabRequest::getRequester));
examRequests = View.convert(new ArrayList<>(data.getRequests()), ExamRequestViewDTO.class);
}
......
......@@ -65,7 +65,7 @@ public class FeedbackViewDTO extends View<Feedback> {
}
private String editionName(Long sessionId) {
var session = getBean(SessionCacheManager.class).getOrThrow(sessionId);
var session = getBean(SessionCacheManager.class).getRequired(sessionId);
return (session.getEdition() == null) ? session.getEditionCollection().getName()
: session.getEdition().getName();
......@@ -91,7 +91,7 @@ public class FeedbackViewDTO extends View<Feedback> {
* @return The name of the requesting entity (either the group or the student).
*/
private String requesterEntityName(Long studentGroupId) {
var studentGroup = getBean(StudentGroupCacheManager.class).getOrThrow(studentGroupId);
var studentGroup = getBean(StudentGroupCacheManager.class).getRequired(studentGroupId);
if (studentGroup.getMemberUsernames().size() == 1) {
return studentGroup.getMembers().get(0).getPerson().getDisplayName();
} else {
......
......@@ -72,13 +72,13 @@ public class LabRequestViewDTO extends RequestViewDTO<LabRequest> {
setRoom(null);
}
assignment = getBean(AssignmentCacheManager.class).getOrThrow(data.getAssignment());
assignment = getBean(AssignmentCacheManager.class).getRequired(data.getAssignment());
timeSlot = data.getTimeSlot();
if (super.getEdition() == null) {
var editionId = getBean(ModuleCacheManager.class).getOrThrow(assignment.getModule().getId())
var editionId = getBean(ModuleCacheManager.class).getRequired(assignment.getModule().getId())
.getEdition().getId();
super.setEdition(getBean(EditionCacheManager.class).getOrThrow(editionId));
super.setEdition(getBean(EditionCacheManager.class).getRequired(editionId));
}
var handledEvent = getEvents().stream()
......
......@@ -26,6 +26,7 @@ import java.util.stream.Collectors;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.OneToOne;
import javax.transaction.Transactional;
import javax.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
......@@ -40,6 +41,8 @@ import nl.tudelft.queue.dto.create.constraints.ClusterConstraintCreateDTO;
import nl.tudelft.queue.model.LabRequestConstraint;
import nl.tudelft.queue.model.QueueSession;
import static nl.tudelft.librador.SpringContext.getBean;
@Data
@Entity
@SuperBuilder
......@@ -62,11 +65,12 @@ public class ClusterConstraint extends LabRequestConstraint {
private QueueSession<?> session;
@Override
@Transactional
public boolean canCreateRequest(Long personId) {
// Get the clusters in the list of allowed clusters and check whether the person is in one of these.
// TODO: Optimize this by creating a method for getting cluster ids per person.
return SpringContext.getBean(ClusterCacheManager.class)
.get(clusters.stream()).stream()
return getBean(ClusterCacheManager.class)
.getAndHandle(clusters.stream(), clusterID -> this.clusters.remove(clusterID)).stream()
.anyMatch(cluster -> cluster.getPeople().stream()
.anyMatch(person -> Objects.equals(person.getId(), personId)));
}
......@@ -78,7 +82,7 @@ public class ClusterConstraint extends LabRequestConstraint {
@Override
public String constraintDescription() {
return "in cluster " + SpringContext.getBean(ClusterCacheManager.class).get(new ArrayList<>(clusters))
return "in cluster " + getBean(ClusterCacheManager.class).getAndIgnoreMissing(new ArrayList<>(clusters))
.stream().map(ClusterDetailsDTO::getName).collect(Collectors.joining(", "));
}
......
......@@ -45,6 +45,8 @@ import nl.tudelft.queue.model.Request;
import nl.tudelft.queue.model.SelectionRequest;
import nl.tudelft.queue.model.embeddables.CapacitySessionConfig;
import nl.tudelft.queue.model.enums.QueueSessionType;
import nl.tudelft.queue.service.LabService;
import org.apache.groovy.parser.antlr4.GroovyParser;
@Data
@Entity
......@@ -65,7 +67,7 @@ public class CapacitySession extends QueueSession<SelectionRequest> {
@Override
public boolean allowsRequest(Request<?> request) {
var session = getBean(SessionCacheManager.class).get(getSession());
var session = getBean(SessionCacheManager.class).getRequired(getSession(), id -> getBean(LabService.class).deleteSession(this));
boolean allowed = request instanceof SelectionRequest && super.allowsRequest(request);
if (capacitySessionConfig.getProcedure().isFcfs()) {
......
......@@ -44,7 +44,10 @@ import nl.tudelft.queue.model.enums.CommunicationMethod;
import nl.tudelft.queue.model.enums.OnlineMode;
import nl.tudelft.queue.model.enums.RequestType;
import nl.tudelft.queue.service.LabService;
import org.hibernate.validator.constraints.UniqueElements;
import org.springframework.http.HttpStatus;
import org.springframework.web.server.ResponseStatusException;
@Data
@Entity
......@@ -134,7 +137,12 @@ public abstract class Lab extends QueueSession<LabRequest> {
@Override
public boolean allowsRequest(Request<?> request) {
var session = getBean(SessionCacheManager.class).getOrThrow(getSession());
var session = getBean(SessionCacheManager.class).get(getSession())
.orElseThrow(() -> {
getBean(LabService.class).deleteSession(this);
return new ResponseStatusException(HttpStatus.NOT_FOUND, "Session" + getSession() + "was deleted in the meantime");
});
return request instanceof LabRequest && super.allowsRequest(request)
&& allowsRequest((LabRequest) request)
......
......@@ -19,6 +19,7 @@ package nl.tudelft.queue.repository;
import java.util.List;
import lombok.Builder;
import nl.tudelft.queue.model.QQueueSession;
import nl.tudelft.queue.model.QueueSession;
......
......@@ -63,6 +63,9 @@ public class CapacitySessionService {
@Autowired
private PersonCacheManager pCache;
@Autowired
private LabService ls;
private SessionCacheManager sCache;
private StudentGroupCacheManager sgCache;
......@@ -74,7 +77,7 @@ public class CapacitySessionService {
* @return The number of students in the group.
*/
private int countStudentMembers(Long sgId) {
return (int) sgCache.getOrThrow(sgId).getMembers().stream()
return (int) sgCache.getRequired(sgId).getMembers().stream()
.filter(role -> role.getType() == RolePersonLayer1DTO.TypeEnum.STUDENT)
.count();
}
......@@ -245,7 +248,7 @@ public class CapacitySessionService {
* @return The number of people that should be selected.
*/
private int getAmountToSelect(CapacitySession lab, List<SelectionRequest> alreadySelectedRequests) {
var session = sCache.getOrThrow(lab.getSession());
var session = sCache.getRequired(lab.getSession(), id -> ls.deleteSession(lab));
// Count the number of requests that have already been selected in case someone gets manually selected.
int countAlreadySelected = (int) alreadySelectedRequests.stream()
......@@ -263,21 +266,6 @@ public class CapacitySessionService {
return amountToSelect;
}
/**
* Initializes all caches that are used when running a selection. Pre-fetches all data required for a lab
* so that no more fetched need to be done during the algorithm.
*
* @param labs The labs that selections will be run over.
*/
private void initializeCaches(List<CapacitySession> labs) {
sCache = new SessionCacheManager(sApi);
sgCache = new StudentGroupCacheManager(sgApi, pCache);
sCache.get(labs.stream().map(CapacitySession::getSession));
sgCache.get(labs.stream().flatMap(lab -> lab.getRequests().stream())
.map(SelectionRequest::getStudentGroup));
}
/**
* Divides the given list of requests that were selected to come over the rooms that are available for the
* lab automatically. Student groups are assigned to a room in the order in which they were selected until
......@@ -288,7 +276,7 @@ public class CapacitySessionService {
*/
@Transactional
public void divideSelectedRequests(CapacitySession qSession, List<SelectionRequest> selectedRequests) {
var session = sCache.getOrThrow(qSession.getSession());
var session = sCache.getRequired(qSession.getSession(), id -> ls.deleteSession(qSession));
// For every room in the session, initialize a count
Map<RoomDetailsDTO, Integer> occupancy = new HashMap<>();
......@@ -329,6 +317,22 @@ public class CapacitySessionService {
}
}
/**
* Initializes all caches that are used when running a selection. Pre-fetches all data required for a lab
* so that no more fetched need to be done during the algorithm.
*
* @param labs The labs that selections will be run over.
*/
@Transactional
public void initializeCaches(List<CapacitySession> labs) {
sCache = new SessionCacheManager(sApi);
sgCache = new StudentGroupCacheManager(sgApi, pCache);
sCache.getAndHandleAll(labs.stream().map(CapacitySession::getSession), ls.deleteSessionsByIds());
sgCache.getAndIgnoreMissing(labs.stream().flatMap(lab -> lab.getRequests().stream())
.map(SelectionRequest::getStudentGroup));
}
/**
* Runs every minute on the 3rd second of the minute. This method finds all capacity-labs that have to
* have their requests picked. For each of these labs, it selects students up to the capacity of the rooms
......@@ -380,7 +384,7 @@ public class CapacitySessionService {
}
// If we have a fcfs lab we should select new students immediatly.
if (session.getCapacitySessionConfig().getProcedure().isFcfs()) {
for (RoomDetailsDTO room : sCache.getOrThrow(session.getSession()).getRooms()) {
for (RoomDetailsDTO room : sCache.getRequired(session.getSession(), id -> ls.deleteSession(session)).getRooms()) {
session.getRequests().stream()
.filter(selectionRequest -> !selectionRequest.getEventInfo().getStatus().isSelected())
.peek((r) -> r.setRoom(room.getId()))
......
......@@ -39,9 +39,12 @@ import nl.tudelft.queue.model.enums.RequestType;
import nl.tudelft.queue.model.labs.Lab;
import nl.tudelft.queue.repository.LabRequestRepository;
import nl.tudelft.queue.repository.QueueSessionRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.transaction.Transactional;
@Service
public class EditionStatusService {
@Autowired
......@@ -59,6 +62,11 @@ public class EditionStatusService {
@Autowired
private PersonCacheManager pCache;
@Autowired
private LabService ls;
/**
* Creates the buckets used for counting frequencies of events occurring. Buckets are based on the minimum
* time of day a lab in the given list of labs starts and the maximum time of day such a lab ends. The
......@@ -74,9 +82,10 @@ public class EditionStatusService {
* @param nBuckets The number of buckets to create.
* @return A treeset of interval start times.
*/
@Transactional
public TreeSet<Long> createBucketsOverCourse(List<Lab> labs,
int nBuckets) {
var sessions = sCache.get(labs.stream().map(Lab::getSession));
var sessions = sCache.getAndHandleAll(labs.stream().map(Lab::getSession), ls.deleteSessionsByIds());
long min = sessions.stream()
.map(l -> l.getStart().getLong(SECOND_OF_DAY))
......@@ -214,7 +223,7 @@ public class EditionStatusService {
*/
public Map<String, Long> countRequestsPerAssignment(List<Long> assignments,
List<LabRequest> requests) {
return aCache.get(assignments).stream()
return aCache.getAndIgnoreMissing(assignments).stream()
.collect(Collectors.toMap(
AssignmentDetailsDTO::getName,
a -> countWhere(requests, r -> r.getAssignment().equals(a.getId()))));
......@@ -230,7 +239,7 @@ public class EditionStatusService {
* occurs in the list of requests.
*/
public Map<String, Long> countRequestsPerRoom(List<Long> rooms, List<LabRequest> requests) {
return rCache.get(rooms).stream()
return rCache.getAndIgnoreMissing(rooms).stream()
.distinct()
.collect(Collectors.toMap(
RoomDetailsDTO::getName,
......@@ -289,7 +298,7 @@ public class EditionStatusService {
.distinct()
.filter(Objects::nonNull)
.collect(Collectors.toList());
Map<Long, String> names = pCache.get(ids)
Map<Long, String> names = pCache.getAndIgnoreMissing(ids)
.stream()
.collect(Collectors.toMap(
PersonSummaryDTO::getId,
......
......@@ -58,7 +58,7 @@ public class FeedbackService {
* given request.
*/
public List<PersonSummaryDTO> assistantsInvolvedInRequest(Long requestId) {
return pCache.get(rr.findById(requestId).stream()
return pCache.getAndIgnoreMissing(rr.findById(requestId).stream()
.flatMap(request -> request.getEventInfo().involvedAssistants().stream()));
}
......
......@@ -49,7 +49,7 @@ public class JitsiService {
UUID uuid = UUID.randomUUID();
// Lookup the username of the requester and add it to the UUID to make a room name
return pCache.getOrThrow(request.getRequester()).getUsername() + "-" +
return pCache.getRequired(request.getRequester()).getUsername() + "-" +
uuid.toString().substring(0, 8);
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment