SEBSERV-341 and SEBSERV-343

This commit is contained in:
anhefti 2022-07-20 11:53:29 +02:00
parent 921595c3b0
commit 224507d849
6 changed files with 76 additions and 97 deletions

View file

@ -30,7 +30,6 @@ import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam.ExamStatus;
import ch.ethz.seb.sebserver.gbl.model.exam.ExamConfigurationMap;
import ch.ethz.seb.sebserver.gbl.model.exam.QuizData;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
@ -89,7 +88,7 @@ public class ExamList implements TemplateComposer {
private final TableFilterAttribute institutionFilter;
private final TableFilterAttribute lmsFilter;
private final TableFilterAttribute nameFilter =
new TableFilterAttribute(CriteriaType.TEXT, QuizData.FILTER_ATTR_NAME);
new TableFilterAttribute(CriteriaType.TEXT, Domain.EXAM.ATTR_QUIZ_NAME);
private final TableFilterAttribute stateFilter;
private final TableFilterAttribute typeFilter;
@ -177,21 +176,21 @@ public class ExamList implements TemplateComposer {
.sortable())
.withColumn(new ColumnDefinition<>(
QuizData.QUIZ_ATTR_NAME,
Domain.EXAM.ATTR_QUIZ_NAME,
COLUMN_TITLE_NAME_KEY,
Exam::getName)
.withFilter(this.nameFilter)
.sortable())
.withColumn(new ColumnDefinition<>(
QuizData.QUIZ_ATTR_START_TIME,
Domain.EXAM.ATTR_QUIZ_START_TIME,
new LocTextKey(
EXAM_LIST_COLUMN_START_TIME,
i18nSupport.getUsersTimeZoneTitleSuffix()),
Exam::getStartTime)
.withFilter(new TableFilterAttribute(
CriteriaType.DATE,
QuizData.FILTER_ATTR_START_TIME,
Domain.EXAM.ATTR_QUIZ_START_TIME,
Utils.toDateTimeUTC(Utils.getMillisecondsNow())
.minusYears(1)
.toString()))

View file

@ -282,10 +282,11 @@ public class PaginationServiceImpl implements PaginationService {
final Map<String, String> examTableMap = new HashMap<>();
examTableMap.put(Entity.FILTER_ATTR_INSTITUTION, institutionNameRef);
examTableMap.put(Domain.EXAM.ATTR_LMS_SETUP_ID, lmsSetupNameRef);
// NOTE: This seems not to work and I was not able to figure out why.
// Now the type sorting is done within secondary sort for exams.
//examTableMap.put(Domain.EXAM.ATTR_TYPE, "'" + ExamRecordDynamicSqlSupport.type.name() + "'");
examTableMap.put(Domain.EXAM.ATTR_QUIZ_NAME, ExamRecordDynamicSqlSupport.quizName.name());
examTableMap.put(Domain.EXAM.ATTR_QUIZ_START_TIME, ExamRecordDynamicSqlSupport.quizStartTime.name());
examTableMap.put(Domain.EXAM.ATTR_QUIZ_END_TIME, ExamRecordDynamicSqlSupport.quizEndTime.name());
examTableMap.put(Domain.EXAM.ATTR_STATUS, ExamRecordDynamicSqlSupport.status.name());
examTableMap.put(Domain.EXAM.ATTR_TYPE, ExamRecordDynamicSqlSupport.type.name());
this.sortColumnMapping.put(ExamRecordDynamicSqlSupport.examRecord.name(), examTableMap);
this.defaultSortColumn.put(ExamRecordDynamicSqlSupport.examRecord.name(), Domain.EXAM.ATTR_ID);

View file

@ -19,6 +19,7 @@ import org.springframework.util.MultiValueMap;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
import ch.ethz.seb.sebserver.gbl.model.exam.ExamConfigurationMap;
@ -108,7 +109,7 @@ public class FilterMap extends POSTMapper {
}
public DateTime getExamFromTime() {
return Utils.toDateTime(getString(QuizData.FILTER_ATTR_START_TIME));
return Utils.toDateTime(getString(Domain.EXAM.ATTR_QUIZ_START_TIME));
}
public DateTime getSEBClientConfigFromTime() {

View file

@ -25,7 +25,6 @@ import java.util.stream.Collectors;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.mybatis.dynamic.sql.update.UpdateDSL;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Lazy;
@ -121,42 +120,16 @@ public class ExamDAOImpl implements ExamDAO {
return Result.tryCatch(() -> {
final Predicate<Exam> examDataFilter = createPredicate(filterMap);
return this.examRecordDAO
.allMatching(filterMap, null)
.flatMap(this::toDomainModel)
.getOrThrow()
.stream()
.filter(examDataFilter.and(predicate))
.filter(predicate)
.collect(Collectors.toList());
});
}
private Predicate<Exam> createPredicate(final FilterMap filterMap) {
final String name = filterMap.getQuizName();
final DateTime from = filterMap.getExamFromTime();
final Predicate<Exam> quizDataFilter = exam -> {
if (StringUtils.isNotBlank(name)) {
if (!exam.name.contains(name)) {
return false;
}
}
if (from != null && exam.startTime != null) {
// always show exams that has not ended yet
if (exam.endTime == null || exam.endTime.isAfter(from)) {
return true;
}
if (exam.startTime.isBefore(from)) {
return false;
}
}
return true;
};
return quizDataFilter;
}
@Override
public Result<Exam> updateState(final Long examId, final ExamStatus status, final String updateId) {
return this.examRecordDAO
@ -268,13 +241,12 @@ public class ExamDAOImpl implements ExamDAO {
.stream().map(s -> s.name())
.collect(Collectors.toList())
: null;
final Predicate<Exam> examDataFilter = createPredicate(filterMap);
return this.examRecordDAO
.allMatching(filterMap, stateNames)
.flatMap(this::toDomainModel)
.getOrThrow()
.stream()
.filter(examDataFilter.and(predicate))
.filter(predicate)
.collect(Collectors.toList());
});
}

View file

@ -172,8 +172,6 @@ public class ExamRecordDAO {
ExamRecordDynamicSqlSupport.active,
isEqualToWhenPresent(filterMap.getActiveAsInt()));
//
whereClause = whereClause
.and(
ExamRecordDynamicSqlSupport.institutionId,
@ -209,6 +207,10 @@ public class ExamRecordDAO {
.and(
ExamRecordDynamicSqlSupport.quizName,
isLikeWhenPresent(filterMap.getSQLWildcard(EXAM.ATTR_QUIZ_NAME)))
.and(
ExamRecordDynamicSqlSupport.quizEndTime,
isGreaterThanOrEqualToWhenPresent(filterMap.getExamFromTime()),
or(ExamRecordDynamicSqlSupport.quizEndTime, isNull()))
.build()
.execute();
@ -465,20 +467,20 @@ public class ExamRecordDAO {
.execute();
// check those in not running state (and not archived) and are within the time-frame or on wrong side of the time-frame
// if finished but up-coming
// if finished but up-coming or running
final SqlCriterion<String> finished = or(
ExamRecordDynamicSqlSupport.status,
isEqualTo(ExamStatus.FINISHED.name()),
and(
ExamRecordDynamicSqlSupport.quizStartTime,
ExamRecordDynamicSqlSupport.quizEndTime,
SqlBuilder.isGreaterThanOrEqualToWhenPresent(now.plus(leadTime))));
// if up-coming but finished
// if up-coming but running or finished
final SqlCriterion<String> upcoming = or(
ExamRecordDynamicSqlSupport.status,
isEqualTo(ExamStatus.UP_COMING.name()),
and(
ExamRecordDynamicSqlSupport.quizEndTime,
ExamRecordDynamicSqlSupport.quizStartTime,
SqlBuilder.isLessThanWhenPresent(now.minus(followupTime))),
finished);

View file

@ -17,13 +17,12 @@ import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.mybatis.dynamic.sql.SqlTable;
import org.springframework.http.MediaType;
import org.springframework.util.MultiValueMap;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
@ -39,14 +38,13 @@ import ch.ethz.seb.sebserver.gbl.api.APIMessage.APIMessageException;
import ch.ethz.seb.sebserver.gbl.api.APIMessage.ErrorMessage;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType;
import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.Domain.EXAM;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gbl.model.PageSortOrder;
import ch.ethz.seb.sebserver.gbl.model.exam.Chapters;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam.ExamType;
import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringServiceSettings;
import ch.ethz.seb.sebserver.gbl.model.exam.QuizData;
import ch.ethz.seb.sebserver.gbl.model.exam.SEBRestriction;
@ -120,50 +118,56 @@ public class ExamAdministrationController extends EntityController<Exam, Exam> {
return ExamRecordDynamicSqlSupport.examRecord;
}
@RequestMapping(
method = RequestMethod.GET,
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
@Override
public Page<Exam> getPage(
@RequestParam(
name = API.PARAM_INSTITUTION_ID,
required = true,
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId,
@RequestParam(name = Page.ATTR_PAGE_NUMBER, required = false) final Integer pageNumber,
@RequestParam(name = Page.ATTR_PAGE_SIZE, required = false) final Integer pageSize,
@RequestParam(name = Page.ATTR_SORT, required = false) final String sort,
@RequestParam final MultiValueMap<String, String> allRequestParams,
final HttpServletRequest request) {
checkReadPrivilege(institutionId);
this.authorization.check(
PrivilegeType.READ,
EntityType.EXAM,
institutionId);
if (StringUtils.isBlank(sort) ||
(this.paginationService.isNativeSortingSupported(ExamRecordDynamicSqlSupport.examRecord, sort))) {
return super.getPage(institutionId, pageNumber, pageSize, sort, allRequestParams, request);
} else {
final Collection<Exam> exams = this.examDAO
.allMatching(new FilterMap(
allRequestParams,
request.getQueryString()),
this::hasReadAccess)
.getOrThrow();
return this.paginationService.buildPageFromList(
pageNumber,
pageSize,
sort,
exams,
pageSort(sort));
}
}
// @RequestMapping(
// method = RequestMethod.GET,
// consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
// produces = MediaType.APPLICATION_JSON_VALUE)
// @Override
// public Page<Exam> getPage(
// @RequestParam(
// name = API.PARAM_INSTITUTION_ID,
// required = true,
// defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId,
// @RequestParam(name = Page.ATTR_PAGE_NUMBER, required = false) final Integer pageNumber,
// @RequestParam(name = Page.ATTR_PAGE_SIZE, required = false) final Integer pageSize,
// @RequestParam(name = Page.ATTR_SORT, required = false) final String sort,
// @RequestParam final MultiValueMap<String, String> allRequestParams,
// final HttpServletRequest request) {
//
// checkReadPrivilege(institutionId);
// this.authorization.check(
// PrivilegeType.READ,
// EntityType.EXAM,
// institutionId);
//
// if (StringUtils.isBlank(sort) ||
// (this.paginationService.isNativeSortingSupported(ExamRecordDynamicSqlSupport.examRecord, sort))) {
//
// System.out.println("*********************** sort, filter on DB");
//
// return super.getPage(institutionId, pageNumber, pageSize, sort, allRequestParams, request);
//
// } else {
//
// System.out.println("*********************** sort, filter on List");
//
// return super.getPage(institutionId, pageNumber, pageSize, sort, allRequestParams, request);
//
//// final Collection<Exam> exams = this.examDAO
//// .allMatching(new FilterMap(
//// allRequestParams,
//// request.getQueryString()),
//// this::hasReadAccess)
//// .getOrThrow();
////
//// return this.paginationService.buildPageFromList(
//// pageNumber,
//// pageSize,
//// sort,
//// exams,
//// pageSort(sort));
// }
// }
@RequestMapping(
path = API.MODEL_ID_VAR_PATH_SEGMENT
@ -586,13 +590,13 @@ public class ExamAdministrationController extends EntityController<Exam, Exam> {
}
if (sortBy.equals(Exam.FILTER_ATTR_NAME) || sortBy.equals(QuizData.QUIZ_ATTR_NAME)) {
list.sort(Comparator.comparing(exam -> exam.name));
list.sort(Comparator.comparing(exam -> (exam.name != null) ? exam.name : StringUtils.EMPTY));
}
if (sortBy.equals(Exam.FILTER_ATTR_TYPE)) {
list.sort(Comparator.comparing(exam -> exam.type));
list.sort(Comparator.comparing(exam -> (exam.type != null) ? exam.type : ExamType.UNDEFINED));
}
if (sortBy.equals(QuizData.FILTER_ATTR_START_TIME) || sortBy.equals(QuizData.QUIZ_ATTR_START_TIME)) {
list.sort(Comparator.comparing(exam -> exam.startTime));
list.sort(Comparator.comparing(exam -> (exam.startTime != null) ? exam.startTime : new DateTime(0)));
}
if (PageSortOrder.DESCENDING == PageSortOrder.getSortOrder(sort)) {