diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ExamDAO.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ExamDAO.java index fd6d1391..f651b48f 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ExamDAO.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ExamDAO.java @@ -24,11 +24,19 @@ public interface ExamDAO extends ActivatableEntityDAO, BulkActionSup /** Get a GrantEntity for the exam of specified id (PK) * This is actually a Exam instance but with no course data loaded. - * + * * @param id The id of the exam (PK) * @return Result referring to the GrantEntity of the exam or to an error when happened */ Result examGrantEntityByPK(final Long id); + /** Get an Exam GrantEntity by a given ClientConnection id. + * This is actually a Exam instance but with no course data loaded. + * + * @param connectionId the connection identifier + * @return a Result containing the Exam GrantEntity by a given ClientConnection id or refer to an error if + * happened */ + Result examGrantEntityByClientConnection(Long connectionId); + /** Get all active Exams for a given institution. * * @param institutionId the identifier of the institution @@ -56,12 +64,6 @@ public interface ExamDAO extends ActivatableEntityDAO, BulkActionSup key = "#exam.id") Result save(Exam exam); - /** Get an Exam by a given ClientConnection id. - * - * @param connectionId the connection identifier - * @return a Result containing the Exam by a given ClientConnection id or refer to an error if happened */ - Result byClientConnection(Long connectionId); - /** Use this to get identifiers of all exams in a specified state for a specified institution. * * @param institutionId the institution identifier. May be null for all institutions diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamDAOImpl.java index d36c9b66..6232e355 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamDAOImpl.java @@ -94,12 +94,11 @@ public class ExamDAOImpl implements ExamDAO { @Override @Transactional(readOnly = true) - public Result byClientConnection(final Long connectionId) { + public Result examGrantEntityByClientConnection(final Long connectionId) { return Result.tryCatch(() -> this.clientConnectionRecordMapper .selectByPrimaryKey(connectionId)) .flatMap(ccRecord -> recordById(ccRecord.getExamId())) - .flatMap(this::toDomainModelCached) - .onError(TransactionHandler::rollback); + .map(record -> toDomainModel(record, null).getOrThrow()); } @Override @@ -708,14 +707,6 @@ public class ExamDAOImpl implements ExamDAO { exam.getDescription()); } - private Result toDomainModelCached(final ExamRecord record) { - return Result.tryCatch(() -> this.lmsAPIService - .getLmsAPITemplate(record.getLmsSetupId()) - .getOrThrow()) - .flatMap(template -> template.getQuizFromCache(record.getExternalId())) - .flatMap(quizData -> this.toDomainModel(record, quizData)); - } - private Result toDomainModel(final ExamRecord record) { return toDomainModel( record.getLmsSetupId(), diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/MoodleCourseAccess.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/MoodleCourseAccess.java index c0a002dc..bf1f8c0f 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/MoodleCourseAccess.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/MoodleCourseAccess.java @@ -18,7 +18,6 @@ import java.util.function.Supplier; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; -import org.apache.coyote.http11.Constants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.LinkedMultiValueMap; @@ -29,6 +28,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.type.TypeReference; +import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.api.JSONMapper; import ch.ethz.seb.sebserver.gbl.async.AsyncService; import ch.ethz.seb.sebserver.gbl.model.exam.Chapters; @@ -48,7 +48,7 @@ public class MoodleCourseAccess extends CourseAccess { private static final Logger log = LoggerFactory.getLogger(MoodleCourseAccess.class); - private static final String MOODLE_QUIZ_START_URL_PATH = "mod/quiz/view.php?id="; + private static final String MOODLE_QUIZ_START_URL_PATH = "mod/quiz/view.php?q="; private static final String MOODLE_COURSE_API_FUNCTION_NAME = "core_course_get_courses"; private static final String MOODLE_USER_PROFILE_API_FUNCTION_NAME = "core_user_get_users_by_field"; private static final String MOODLE_QUIZ_API_FUNCTION_NAME = "mod_quiz_get_quizzes_by_courses"; @@ -161,7 +161,9 @@ public class MoodleCourseAccess extends CourseAccess { } private ArrayList collectAllQuizzes(final MoodleAPIRestTemplate restTemplate) { - final String urlPrefix = this.lmsSetup.lmsApiUrl + MOODLE_QUIZ_START_URL_PATH; + final String urlPrefix = (this.lmsSetup.lmsApiUrl.endsWith(Constants.URL_PATH_SEPARATOR)) + ? this.lmsSetup.lmsApiUrl + MOODLE_QUIZ_START_URL_PATH + : this.lmsSetup.lmsApiUrl + Constants.URL_PATH_SEPARATOR + MOODLE_QUIZ_START_URL_PATH; return collectAllCourses(restTemplate) .stream() .reduce( @@ -239,7 +241,7 @@ public class MoodleCourseAccess extends CourseAccess { final List courseAndQuiz = courseData.quizzes .stream() .map(courseQuizData -> { - final String startURI = uriPrefix + courseQuizData.course_module; + final String startURI = uriPrefix + courseQuizData.id; additionalAttrs.put(QuizData.ATTR_ADDITIONAL_TIME_LIMIT, String.valueOf(courseQuizData.time_limit)); return new QuizData( getInternalQuizId(courseQuizData.id, courseData.short_name, courseData.idnumber), diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ExamSessionServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ExamSessionServiceImpl.java index 470a7554..4927e3d1 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ExamSessionServiceImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ExamSessionServiceImpl.java @@ -244,9 +244,13 @@ public class ExamSessionServiceImpl implements ExamSessionService { .putIfAbsent(Exam.FILTER_ATTR_ACTIVE, Constants.TRUE_STRING) .putIfAbsent(Exam.FILTER_ATTR_STATUS, ExamStatus.RUNNING.name()); + // NOTE: we evict the exam from the cache (if present) to ensure user is seeing always the current state of the Exam return this.examDAO.allMatching(filterMap, predicate) .map(col -> col.stream() - .map(exam -> this.examSessionCacheService.getRunningExam(exam.id)) + .map(exam -> { + this.examSessionCacheService.evict(exam); + return this.examSessionCacheService.getRunningExam(exam.id); + }) .filter(Objects::nonNull) .collect(Collectors.toList())); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ClientEventController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ClientEventController.java index dcbb0b45..07d5f6b8 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ClientEventController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ClientEventController.java @@ -205,7 +205,7 @@ public class ClientEventController extends ReadonlyEntityController