Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 35 additions & 4 deletions src/main/java/org/pkwmtt/timetable/TimetableController.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
import org.pkwmtt.exceptions.SpecifiedGeneralGroupDoesntExistsException;
import org.pkwmtt.exceptions.SpecifiedSubGroupDoesntExistsException;
import org.pkwmtt.exceptions.WebPageContentNotAvailableException;
import org.pkwmtt.timetable.dto.CustomSubjectFilterDTO;
import org.pkwmtt.timetable.dto.TimetableDTO;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;

import static java.util.Objects.isNull;
Expand All @@ -29,13 +31,42 @@ public class TimetableController {
* @throws WebPageContentNotAvailableException .
*/
@GetMapping("/{generalGroupName}")
public ResponseEntity<TimetableDTO> getGeneralGroupSchedule (@PathVariable String generalGroupName, @RequestParam(required = false, name = "sub") List<String> subgroups)
public ResponseEntity<TimetableDTO> getGeneralGroupSchedule (@PathVariable String generalGroupName,
@RequestParam(required = false, name = "sub") List<String> subgroups)
throws WebPageContentNotAvailableException, SpecifiedGeneralGroupDoesntExistsException, SpecifiedSubGroupDoesntExistsException, JsonProcessingException {
var areSubgroupsProvided = !(isNull(subgroups) || subgroups.isEmpty());

if (isNull(subgroups) || subgroups.isEmpty()) {
return ResponseEntity.ok(cachedService.getGeneralGroupSchedule(generalGroupName));
return
areSubgroupsProvided ?
ResponseEntity.ok(service.getFilteredGeneralGroupSchedule(
generalGroupName,
subgroups,
new ArrayList<>()
))
: ResponseEntity.ok(cachedService.getGeneralGroupSchedule(generalGroupName));
}

@PostMapping(value = "/{generalGroupName}", consumes = "application/json", produces = "application/json")
public ResponseEntity<TimetableDTO> getGeneralGroupScheduleWithCustomSubjects (@PathVariable String generalGroupName,
@RequestParam(required = false, name = "sub") List<String> subgroups,
@RequestBody(required = false) List<CustomSubjectFilterDTO> customSubjects)
throws WebPageContentNotAvailableException, SpecifiedGeneralGroupDoesntExistsException, SpecifiedSubGroupDoesntExistsException, JsonProcessingException {
var areSubgroupsProvided = !(isNull(subgroups) || subgroups.isEmpty());
var areCustomSubjectsProvided = !(isNull(customSubjects) || customSubjects.isEmpty());

if (areSubgroupsProvided) {
if (!areCustomSubjectsProvided) {
customSubjects = new ArrayList<>();
}

return ResponseEntity.ok(service.getFilteredGeneralGroupSchedule(
generalGroupName,
subgroups,
customSubjects
));

}
return ResponseEntity.ok(service.getFilteredGeneralGroupSchedule(generalGroupName, subgroups));
return ResponseEntity.ok(cachedService.getGeneralGroupSchedule(generalGroupName));
}

/**
Expand Down
17 changes: 6 additions & 11 deletions src/main/java/org/pkwmtt/timetable/TimetableExceptionHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,10 @@
public class TimetableExceptionHandler {
@ExceptionHandler(WebPageContentNotAvailableException.class)
@ResponseStatus(HttpStatus.SERVICE_UNAVAILABLE)
public ResponseEntity<ErrorResponseDTO> handleWebPageContentNotAvailableException (WebPageContentNotAvailableException e) {
public ResponseEntity<ErrorResponseDTO> handleWebPageContentNotAvailableException (
WebPageContentNotAvailableException e) {
log.error("SERVICE_UNAVAILABLE # " + e.getMessage());
return new ResponseEntity<>(
new ErrorResponseDTO(e.getMessage()),
HttpStatus.SERVICE_UNAVAILABLE
);
return new ResponseEntity<>(new ErrorResponseDTO(e.getMessage()), HttpStatus.SERVICE_UNAVAILABLE);
}

@ExceptionHandler(JsonProcessingException.class)
Expand All @@ -32,11 +30,11 @@ public ResponseEntity<ErrorResponseDTO> handleJsonProcessingException (JsonProce
log.error("INTERNAL_SERVER_ERROR # " + e.getMessage());
return new ResponseEntity<>(
new ErrorResponseDTO("Json Processing Failed"),
HttpStatus.INTERNAL_SERVER_ERROR
HttpStatus.INTERNAL_SERVER_ERROR
);
}

@ExceptionHandler({SpecifiedGeneralGroupDoesntExistsException.class, SpecifiedSubGroupDoesntExistsException.class})
@ExceptionHandler({SpecifiedGeneralGroupDoesntExistsException.class, SpecifiedSubGroupDoesntExistsException.class, IllegalArgumentException.class})
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ResponseEntity<ErrorResponseDTO> handleSpecifiedGeneralGroupDoesntExistsException (Exception e) {
return new ResponseEntity<>(new ErrorResponseDTO(e.getMessage()), HttpStatus.BAD_REQUEST);
Expand All @@ -46,9 +44,6 @@ public ResponseEntity<ErrorResponseDTO> handleSpecifiedGeneralGroupDoesntExistsE
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ResponseEntity<ErrorResponseDTO> handleIllegalAccessException (IllegalAccessException e) {
log.error("INTERNAL_SERVER_ERROR # " + e.getMessage());
return new ResponseEntity<>(
new ErrorResponseDTO(e.getMessage()),
HttpStatus.INTERNAL_SERVER_ERROR
);
return new ResponseEntity<>(new ErrorResponseDTO(e.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
163 changes: 148 additions & 15 deletions src/main/java/org/pkwmtt/timetable/TimetableService.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,17 @@
import org.pkwmtt.exceptions.SpecifiedGeneralGroupDoesntExistsException;
import org.pkwmtt.exceptions.SpecifiedSubGroupDoesntExistsException;
import org.pkwmtt.exceptions.WebPageContentNotAvailableException;
import org.pkwmtt.timetable.dto.CustomSubjectFilterDTO;
import org.pkwmtt.timetable.dto.DayOfWeekDTO;
import org.pkwmtt.timetable.dto.SubjectDTO;
import org.pkwmtt.timetable.dto.TimetableDTO;
import org.pkwmtt.timetable.enums.TypeOfWeek;
import org.pkwmtt.timetable.objects.CustomSubjectDetails;
import org.pkwmtt.timetable.parser.TimetableParserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
Expand Down Expand Up @@ -71,38 +76,166 @@ public List<String> getAvailableSubGroups (String generalGroupName)
* Retrieves timetable and filters entries based on subgroups parameters
*
* @param generalGroupName name of the general group
* @param sub subgroups list
* @param subgroup subgroups list
* @return filtered timetable
* @throws WebPageContentNotAvailableException if source data can't be retrieved
*/
public TimetableDTO getFilteredGeneralGroupSchedule (String generalGroupName, List<String> sub)
public TimetableDTO getFilteredGeneralGroupSchedule (String generalGroupName,
List<String> subgroup,
List<CustomSubjectFilterDTO> customSubjectFilters)
throws WebPageContentNotAvailableException, SpecifiedGeneralGroupDoesntExistsException, JsonProcessingException {

//Uppercase name to assure match
generalGroupName = generalGroupName.toUpperCase();

//Check if specified subgroup is available for this generalGroup
var subgroups = getAvailableSubGroups(generalGroupName);
for (var group : sub) {
if (!subgroups.contains(group)) {
throw new SpecifiedSubGroupDoesntExistsException(group);
}
}
//Check if specified subgroup is available for general group or else throw
checkSubGroupAvailability(generalGroupName, subgroup);

//Get user's schedule
List<DayOfWeekDTO> schedule = cachedService.getGeneralGroupSchedule(generalGroupName).getData();

//Get schedule to extract customSubject details
List<CustomSubjectDetails> customSubjects =
createListOfCustomSchedulesDetails(generalGroupName, customSubjectFilters, schedule);

for (var day : schedule) {
sub.forEach(day::filterByGroup);
return filterSchedule(schedule, subgroup, generalGroupName, customSubjects);
}

private List<CustomSubjectDetails> createListOfCustomSchedulesDetails (String generalGroupName,
List<CustomSubjectFilterDTO> customSubjectFilters,
List<DayOfWeekDTO> schedule) {
List<CustomSubjectDetails> customSubjectsDetails = new ArrayList<>();
customSubjectFilters.forEach(customFilter -> {

//Get schedule for specified filter
List<DayOfWeekDTO> customSubjectSchedule = customFilter
.getGeneralGroup()
.equals(generalGroupName) ? schedule : cachedService
.getGeneralGroupSchedule(customFilter.getGeneralGroup())
.getData();

//Add detail like classroom and rowId
//Go by days: Monday, Tuesday etc...
for (int i = 0; i < customSubjectSchedule.size(); i++) {
//Find subjects matching filters
customSubjectsDetails.addAll(
searchDayOfWeekAndAddCustomSubjectsDetails(
customSubjectSchedule.get(i).getEven(), customFilter, i,
TypeOfWeek.EVEN
));

customSubjectsDetails.addAll(
searchDayOfWeekAndAddCustomSubjectsDetails(
customSubjectSchedule.get(i).getOdd(), customFilter, i,
TypeOfWeek.ODD
));
}
});
return customSubjectsDetails;
}

private List<CustomSubjectDetails> searchDayOfWeekAndAddCustomSubjectsDetails (List<SubjectDTO> day,
CustomSubjectFilterDTO customFilter,
int dayIndex,
TypeOfWeek typeOfWeek) {
var matches = day.stream()
//Filter by matching name and subgroup from customFilter
.filter(item -> (item.getName().contains(customFilter.getName()) && item
.getName()
.contains(customFilter.getSubGroup()))).toList();

if (!matches.isEmpty()) {
return matches
.stream()
.map((item) -> new CustomSubjectDetails(item, customFilter.getSubGroup(), dayIndex, typeOfWeek))
.toList();
}
return new ArrayList<>();
}

private TimetableDTO filterSchedule (List<DayOfWeekDTO> schedule,
List<String> subgroups,
String generalGroupName,
List<CustomSubjectDetails> customSubjectsDetails) {
//Go through user's schedule day by day
for (int i = 0; i < schedule.size(); i++) {
var day = schedule.get(i);

//delete subjects colliding with custom subjects by name
deleteSubjectsCollidingWithCustomFilters(customSubjectsDetails, day);
//Filter by user's subgroups
filterDayByUsersSubgroups(subgroups, customSubjectsDetails, day, i);
}

schedule.forEach(DayOfWeekDTO::deleteSubjectTypesFromNames);

return new TimetableDTO(generalGroupName, schedule);
}

/**
* @return List of general group's names
*/
private void filterDayByUsersSubgroups (List<String> subgroups,
List<CustomSubjectDetails> customSubjectsDetails,
DayOfWeekDTO day, int dayIndex) {
subgroups.forEach(subgroup -> {
if (customSubjectsDetails.isEmpty()) {
day.filterByGroup(subgroup);
return;
}

var customSubjectsByDay = customSubjectsDetails.stream()
//Compare day of week and subgroup
.filter(subject -> subject.getSubGroup().charAt(0) == subgroup.charAt(0)) // match subgroup
.filter(subject -> subject.getDayOfWeekNumber() == dayIndex) // match day of week
.toList();

day.filterByGroup(subgroup, customSubjectsByDay);
});
}

private void deleteSubjectsCollidingWithCustomFilters (List<CustomSubjectDetails> customSubjectsDetails,
DayOfWeekDTO day) {
for (CustomSubjectDetails customSubjectDetail : customSubjectsDetails) {
customSubjectDetail.getSubject().deleteTypeAndUnnecessaryCharactersFromName();

day.setEven(
day
.getEven()
.stream()
.filter(
subject -> !(subject
.getName()
.contains(customSubjectDetail.getSubject().getName())
&& subjectsAreSameType(subject, customSubjectDetail))
).toList());

day.setOdd(day
.getOdd()
.stream()
.filter(
subject -> !(subject.getName().contains(customSubjectDetail.getSubject().getName())
&& subjectsAreSameType(subject, customSubjectDetail))
).toList());

}
}

private boolean subjectsAreSameType (SubjectDTO subject, CustomSubjectDetails customSubjectDetails) {
var subjectType = TimetableParserService.extractSubjectTypeFromName(subject.getName());
var customSubjectType = TimetableParserService.extractSubjectTypeFromName(
customSubjectDetails.getSubGroup());
return subjectType.equals(customSubjectType);

}

private void checkSubGroupAvailability (String generalGroupName, List<String> subgroup)
throws JsonProcessingException {
//Check if specified subgroup is available for this generalGroup
var subgroups = getAvailableSubGroups(generalGroupName);
for (var group : subgroup) {
if (!subgroups.contains(group)) {
throw new SpecifiedSubGroupDoesntExistsException(group);
}
}
}

public List<String> getGeneralGroupList () throws WebPageContentNotAvailableException {
return cachedService.getGeneralGroupsMap().keySet().stream().sorted().collect(Collectors.toList());
}
Expand Down
14 changes: 14 additions & 0 deletions src/main/java/org/pkwmtt/timetable/dto/CustomSubjectFilterDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.pkwmtt.timetable.dto;

import lombok.Data;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Data
@RequiredArgsConstructor
@Getter
public class CustomSubjectFilterDTO {
private final String name;
private final String generalGroup;
private final String subGroup;
}
Loading