Merge remote-tracking branch 'origin/patch-1.0.2' into development

Conflicts:
	src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamDAOImpl.java
	src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ClientEventController.java
	fixes in Moodle LMS binding
This commit is contained in:
anhefti 2020-10-06 09:08:04 +02:00
commit 3fd064055a
5 changed files with 23 additions and 24 deletions

View file

@ -29,6 +29,14 @@ public interface ExamDAO extends ActivatableEntityDAO<Exam, Exam>, BulkActionSup
* @return Result referring to the GrantEntity of the exam or to an error when happened */ * @return Result referring to the GrantEntity of the exam or to an error when happened */
Result<GrantEntity> examGrantEntityByPK(final Long id); Result<GrantEntity> 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<GrantEntity> examGrantEntityByClientConnection(Long connectionId);
/** Get all active Exams for a given institution. /** Get all active Exams for a given institution.
* *
* @param institutionId the identifier of the institution * @param institutionId the identifier of the institution
@ -56,12 +64,6 @@ public interface ExamDAO extends ActivatableEntityDAO<Exam, Exam>, BulkActionSup
key = "#exam.id") key = "#exam.id")
Result<Exam> save(Exam exam); Result<Exam> 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<Exam> byClientConnection(Long connectionId);
/** Use this to get identifiers of all exams in a specified state for a specified institution. /** 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 * @param institutionId the institution identifier. May be null for all institutions

View file

@ -94,12 +94,11 @@ public class ExamDAOImpl implements ExamDAO {
@Override @Override
@Transactional(readOnly = true) @Transactional(readOnly = true)
public Result<Exam> byClientConnection(final Long connectionId) { public Result<GrantEntity> examGrantEntityByClientConnection(final Long connectionId) {
return Result.tryCatch(() -> this.clientConnectionRecordMapper return Result.tryCatch(() -> this.clientConnectionRecordMapper
.selectByPrimaryKey(connectionId)) .selectByPrimaryKey(connectionId))
.flatMap(ccRecord -> recordById(ccRecord.getExamId())) .flatMap(ccRecord -> recordById(ccRecord.getExamId()))
.flatMap(this::toDomainModelCached) .map(record -> toDomainModel(record, null).getOrThrow());
.onError(TransactionHandler::rollback);
} }
@Override @Override
@ -708,14 +707,6 @@ public class ExamDAOImpl implements ExamDAO {
exam.getDescription()); exam.getDescription());
} }
private Result<Exam> 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<Exam> toDomainModel(final ExamRecord record) { private Result<Exam> toDomainModel(final ExamRecord record) {
return toDomainModel( return toDomainModel(
record.getLmsSetupId(), record.getLmsSetupId(),

View file

@ -18,7 +18,6 @@ import java.util.function.Supplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.coyote.http11.Constants;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.util.LinkedMultiValueMap; 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.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference; 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.api.JSONMapper;
import ch.ethz.seb.sebserver.gbl.async.AsyncService; import ch.ethz.seb.sebserver.gbl.async.AsyncService;
import ch.ethz.seb.sebserver.gbl.model.exam.Chapters; 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 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_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_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"; 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<QuizData> collectAllQuizzes(final MoodleAPIRestTemplate restTemplate) { private ArrayList<QuizData> 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) return collectAllCourses(restTemplate)
.stream() .stream()
.reduce( .reduce(
@ -239,7 +241,7 @@ public class MoodleCourseAccess extends CourseAccess {
final List<QuizData> courseAndQuiz = courseData.quizzes final List<QuizData> courseAndQuiz = courseData.quizzes
.stream() .stream()
.map(courseQuizData -> { .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)); additionalAttrs.put(QuizData.ATTR_ADDITIONAL_TIME_LIMIT, String.valueOf(courseQuizData.time_limit));
return new QuizData( return new QuizData(
getInternalQuizId(courseQuizData.id, courseData.short_name, courseData.idnumber), getInternalQuizId(courseQuizData.id, courseData.short_name, courseData.idnumber),

View file

@ -244,9 +244,13 @@ public class ExamSessionServiceImpl implements ExamSessionService {
.putIfAbsent(Exam.FILTER_ATTR_ACTIVE, Constants.TRUE_STRING) .putIfAbsent(Exam.FILTER_ATTR_ACTIVE, Constants.TRUE_STRING)
.putIfAbsent(Exam.FILTER_ATTR_STATUS, ExamStatus.RUNNING.name()); .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) return this.examDAO.allMatching(filterMap, predicate)
.map(col -> col.stream() .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) .filter(Objects::nonNull)
.collect(Collectors.toList())); .collect(Collectors.toList()));
} }

View file

@ -205,7 +205,7 @@ public class ClientEventController extends ReadonlyEntityController<ClientEvent,
@Override @Override
protected GrantEntity toGrantEntity(final ClientEvent entity) { protected GrantEntity toGrantEntity(final ClientEvent entity) {
return this.examDao return this.examDao
.byPK(entity.connectionId) .examGrantEntityByClientConnection(entity.connectionId)
.get(); .get();
} }