SEBSERV-301

This commit is contained in:
anhefti 2022-12-23 09:01:32 +01:00
parent 2434fce036
commit b5cb387061
4 changed files with 46 additions and 98 deletions

View file

@ -75,7 +75,9 @@ public class ExamSEBRestrictionSettings {
private final static LocTextKey SEB_RESTRICTION_FORM_BROWSER_KEYS =
new LocTextKey("sebserver.exam.form.sebrestriction.browserExamKeys");
private final static LocTextKey SEB_RESTRICTION_FORM_MOODLE_ALT_BEK_KEY =
new LocTextKey("sebserver.exam.form.sebrestriction.ALT_BEK_KEY");
new LocTextKey("sebserver.exam.form.sebrestriction.MOODLE_ALT_BEK_KEY");
private final static LocTextKey SEB_RESTRICTION_FORM_MOODLE_BEK_KEY =
new LocTextKey("sebserver.exam.form.sebrestriction.MOODLE_BEK_KEY");
private final static LocTextKey SEB_RESTRICTION_FORM_EDX_WHITE_LIST_PATHS =
new LocTextKey("sebserver.exam.form.sebrestriction.WHITELIST_PATHS");
private final static LocTextKey SEB_RESTRICTION_FORM_EDX_PERMISSIONS =
@ -259,7 +261,9 @@ public class ExamSEBRestrictionSettings {
.addField(FormBuilder.text(
SEBRestriction.ATTR_BROWSER_KEYS,
SEB_RESTRICTION_FORM_BROWSER_KEYS,
(lmsType == lmsType.MOODLE_PLUGIN)
? SEB_RESTRICTION_FORM_MOODLE_BEK_KEY
: SEB_RESTRICTION_FORM_BROWSER_KEYS,
StringUtils.join(sebRestriction.getBrowserExamKeys(), Constants.CARRIAGE_RETURN))
.asArea())

View file

@ -58,7 +58,7 @@ public class ExamSessionControlTask implements DisposableBean {
final WebserviceInfo webserviceInfo,
@Value("${sebserver.webservice.api.exam.time-prefix:3600000}") final Long examTimePrefix,
@Value("${sebserver.webservice.api.exam.time-suffix:3600000}") final Long examTimeSuffix,
@Value("${sebserver.webservice.api.exam.update-interval:1 * * * * *}") final String examTaskCron,
@Value("${sebserver.webservice.api.exam.update-interval:60000}") final String examTaskCron,
@Value("${sebserver.webservice.api.exam.update-ping:5000}") final Long pingUpdateRate) {
this.examDAO = examDAO;

View file

@ -405,102 +405,43 @@ class ExamUpdateHandler {
return this.lmsAPIService
.getLmsAPITemplate(lmsSetupId)
.flatMap(template -> template.tryRecoverQuizForExam(exam))
.onError(error -> {
this.additionalAttributesDAO.saveAdditionalAttribute(
EntityType.EXAM,
exam.id,
Exam.ADDITIONAL_ATTR_QUIZ_RECOVER_ATTEMPTS,
String.valueOf(attempts + 1))
.onError(error1 -> log.error("Failed to save new attempts: ", error1));
if (exam.lmsAvailable == null || exam.isLmsAvailable()) {
this.examDAO.markLMSAvailability(quizId, false, updateId);
}
})
.onSuccess(recoveredQuizData -> recoverSuccess(updateId, exam, recoveredQuizData))
.onError(error -> recoverError(quizId, updateId, exam, attempts))
.getOrThrowRuntime("Not Available");
// // If this is a Moodle quiz, try to recover from eventually restore of the quiz on the LMS side
// // NOTE: This is a workaround for Moodle quizzes that had have a recovery within the sandbox tool
// // Where potentially quiz identifiers get changed during such a recovery and the SEB Server
// // internal mapping is not working properly anymore. In this case we try to recover from such
// // a case by using the short name of the quiz and search for the quiz within the course with this
// // short name. If one quiz has been found that matches all criteria, we adapt the internal id
// // mapping to this quiz.
// // If recovering fails, this returns null and the calling side must handle the lack of quiz data
// if (lmsTemplate.getType() == LmsType.MOODLE || lmsTemplate.getType() == LmsType.MOODLE_PLUGIN) {
//
// final int attempts = Integer.parseInt(this.additionalAttributesDAO.getAdditionalAttribute(
// EntityType.EXAM,
// exam.id,
// Exam.ADDITIONAL_ATTR_QUIZ_RECOVER_ATTEMPTS)
// .map(AdditionalAttributeRecord::getValue)
// .getOr("0"));
//
// if (attempts >= this.recoverAttempts) {
// if (log.isDebugEnabled()) {
// log.debug("Skip recovering quiz due to too many attempts: {}", exam.getModelId());
// throw new RuntimeException("Recover attempts reached");
// }
// }
//
// log.info(
// "Try to recover quiz data for Moodle quiz with internal identifier: {}",
// quizId);
//
// if (exam != null && exam.name != null
// && !exam.name.startsWith(Constants.SQUARE_BRACE_OPEN.toString())) {
//
// log.debug("Found formerName quiz name: {}", exam.name);
//
// // get the course name identifier
// final String shortname = MoodleUtils.getShortname(quizId);
// if (StringUtils.isNotBlank(shortname)) {
//
// log.debug("Using short-name: {} for recovering", shortname);
//
// final QuizData recoveredQuizData = lmsTemplate
// .getQuizzes(new FilterMap())
// .getOrThrow()
// .stream()
// .filter(quiz -> {
// final String qShortName = MoodleUtils.getShortname(quiz.id);
// return qShortName != null && qShortName.equals(shortname);
// })
// .filter(quiz -> exam.name.equals(quiz.name))
// .findAny()
// .get();
//
// if (recoveredQuizData != null) {
//
// log.debug("Found quiz data for recovering: {}", recoveredQuizData);
//
// // save exam with new external id and quit data
// this.examDAO
// .updateQuizData(exam.id, recoveredQuizData, updateId)
// .getOrThrow();
//
// log.debug("Successfully recovered exam quiz data to new externalId {}",
// recoveredQuizData.id);
// }
// return recoveredQuizData;
// }
// }
//
// this.additionalAttributesDAO.saveAdditionalAttribute(
// EntityType.EXAM,
// exam.id,
// Exam.ADDITIONAL_ATTR_QUIZ_RECOVER_ATTEMPTS,
// String.valueOf(attempts + 1))
// .onError(error -> log.error("Failed to save new attempts: ", error));
// }
//
// if (exam.lmsAvailable == null || exam.isLmsAvailable()) {
// this.examDAO.markLMSAvailability(quizId, false, updateId);
// }
//
// throw new RuntimeException("Not Available");
});
}
private void recoverError(final String quizId, final String updateId, final Exam exam, final int attempts) {
// increment attempts
this.additionalAttributesDAO.saveAdditionalAttribute(
EntityType.EXAM,
exam.id,
Exam.ADDITIONAL_ATTR_QUIZ_RECOVER_ATTEMPTS,
String.valueOf(attempts + 1))
.onError(error1 -> log.error("Failed to save new attempts: ", error1));
if (exam.lmsAvailable == null || exam.isLmsAvailable()) {
this.examDAO.markLMSAvailability(quizId, false, updateId);
}
}
private void recoverSuccess(final String updateId, final Exam exam, final QuizData recoveredQuizData) {
if (recoveredQuizData != null) {
// save exam with new external id and quit data
this.examDAO
.updateQuizData(exam.id, recoveredQuizData, updateId)
.onError(error -> log.error("Failed to save exam for recovered quiz data: ", error))
.onSuccess(qd -> log.info("Successfully recovered exam from quiz data, {}", qd))
.getOrThrow();
// delete attempts attribute
this.additionalAttributesDAO.delete(
EntityType.EXAM,
exam.id,
Exam.ADDITIONAL_ATTR_QUIZ_RECOVER_ATTEMPTS);
}
}
}

View file

@ -586,7 +586,10 @@ sebserver.exam.form.sebrestriction.PERMISSION_COMPONENTS=Permissions
sebserver.exam.form.sebrestriction.PERMISSION_COMPONENTS.tooltip=Define the additional SEB restriction permissions
sebserver.exam.form.sebrestriction.USER_BANNING_ENABLED=User Banning
sebserver.exam.form.sebrestriction.USER_BANNING_ENABLED.tooltip=Indicates whether the user of a restricted access shall be banned on authentication failure or not
sebserver.exam.form.sebrestriction.ALT_BEK_KEY=SEB Server Browser Exam Key
sebserver.exam.form.sebrestriction.MOODLE_ALT_BEK_KEY=SEB Server Exam Key
sebserver.exam.form.sebrestriction.MOODLE_ALT_BEK_KEY.tootlip=This key is generated by SEB Server and used as Browser Exam Key for Moodle SEB restriction.
sebserver.exam.form.sebrestriction.MOODLE_BEK_KEY=Additional Browser Exam Keys
sebserver.exam.form.sebrestriction.MOODLE_BEK_KEY.tooltip==A comma-separated list of additional SEB Browser Exam Keys<br/>that are checked by the LMS for the restricted SEB access for every request
sebserver.exam.form.sebrestriction.whiteListPaths.ABOUT=About
sebserver.exam.form.sebrestriction.whiteListPaths.ABOUT.tooltip=The "About" section of the Open edX course