use of de.tum.in.www1.artemis.service.scheduled.quiz.QuizScheduleService in project Artemis by ls1intum.
the class QuizSubmissionService method checkSubmissionForLiveModeOrThrow.
/**
* Check that the user is allowed to currently submit to the specified exercise and throws an exception if not
*/
private void checkSubmissionForLiveModeOrThrow(Long exerciseId, String userLogin, String logText, long start) throws QuizSubmissionException {
// check if submission is still allowed
QuizExercise quizExercise = quizScheduleService.getQuizExercise(exerciseId);
if (quizExercise == null) {
// Fallback solution
log.info("Quiz not in QuizScheduleService cache, fetching from DB");
quizExercise = quizExerciseRepository.findByIdElseThrow(exerciseId);
quizExercise.setQuizBatches(null);
}
log.debug("{}: Received quiz exercise for user {} in quiz {} in {} µs.", logText, userLogin, exerciseId, (System.nanoTime() - start) / 1000);
if (!quizExercise.isQuizStarted() || quizExercise.isQuizEnded()) {
throw new QuizSubmissionException("The quiz is not active");
}
var cachedSubmission = quizScheduleService.getQuizSubmission(exerciseId, userLogin);
if (cachedSubmission.isSubmitted()) {
// the old submission has not yet been processed, so don't allow a new one yet
throw new QuizSubmissionException("You have already submitted the quiz");
}
if (quizExercise.getQuizMode() == QuizMode.SYNCHRONIZED) {
// the batch exists if the quiz is active, otherwise a new inactive batch is returned
if (!quizBatchService.getOrCreateSynchronizedQuizBatch(quizExercise).isSubmissionAllowed()) {
throw new QuizSubmissionException("The quiz is not active");
}
// in synchronized mode we cache the participation after we processed the submission, so we can check there if the submission was already processed
var cachedParticipation = quizScheduleService.getParticipation(exerciseId, userLogin);
if (cachedParticipation != null && cachedParticipation.getResults().stream().anyMatch(r -> r.getSubmission().isSubmitted())) {
throw new QuizSubmissionException("You have already submitted the quiz");
}
} else {
// in the other modes the resubmission checks are done at join time and the student-batch association is removed when processing a submission
var batch = quizBatchService.getQuizBatchForStudentByLogin(quizExercise, userLogin);
// there is no way of distinguishing these two error cases without an extra db query
if (batch.isEmpty()) {
throw new QuizSubmissionException("You did not join or have already submitted the quiz");
}
if (!batch.get().isSubmissionAllowed()) {
throw new QuizSubmissionException("The quiz is not active");
}
}
// TODO: additional checks that may be beneficial
// for example it is possible for students that are not members of the course to submit the quiz
// but for performance reasons the checks may have to be done in the quiz submission service where no feedback for the students can be generated
}
use of de.tum.in.www1.artemis.service.scheduled.quiz.QuizScheduleService in project ArTEMiS by ls1intum.
the class QuizScheduleService method startSchedule.
/**
* Start scheduler of quiz schedule service
*
* @param delayInMillis gap for which the QuizScheduleService should run repeatedly
*/
public void startSchedule(long delayInMillis) {
if (scheduledProcessQuizSubmissions.isNull()) {
try {
var scheduledFuture = threadPoolTaskScheduler.scheduleAtFixedRate(new QuizProcessCacheTask(), 0, delayInMillis, TimeUnit.MILLISECONDS);
scheduledProcessQuizSubmissions.set(scheduledFuture.getHandler());
log.info("QuizScheduleService was started to run repeatedly with {} second delay.", delayInMillis / 1000.0);
} catch (@SuppressWarnings("unused") DuplicateTaskException e) {
log.warn("Quiz process cache task already registered");
// this is expected if we run on multiple nodes
}
// schedule quiz start for all existing quizzes that are planned to start in the future
List<QuizExercise> quizExercises = quizExerciseRepository.findAllPlannedToStartInTheFuture();
log.info("Found {} quiz exercises with planned start in the future", quizExercises.size());
for (QuizExercise quizExercise : quizExercises) {
if (quizExercise.isCourseExercise()) {
// only schedule quiz exercises in courses, not in exams
// Note: the quiz exercise does not include questions and statistics, so we pass the id
scheduleQuizStart(quizExercise.getId());
}
}
} else {
log.info("Cannot start quiz exercise schedule service, it is already RUNNING");
}
}
use of de.tum.in.www1.artemis.service.scheduled.quiz.QuizScheduleService in project Artemis by ls1intum.
the class QuizScheduleService method startSchedule.
/**
* Start scheduler of quiz schedule service
*
* @param delayInMillis gap for which the QuizScheduleService should run repeatedly
*/
public void startSchedule(long delayInMillis) {
if (scheduledProcessQuizSubmissions.isNull()) {
try {
var scheduledFuture = threadPoolTaskScheduler.scheduleAtFixedRate(new QuizProcessCacheTask(), 0, delayInMillis, TimeUnit.MILLISECONDS);
scheduledProcessQuizSubmissions.set(scheduledFuture.getHandler());
log.info("QuizScheduleService was started to run repeatedly with {} second delay.", delayInMillis / 1000.0);
} catch (@SuppressWarnings("unused") DuplicateTaskException e) {
log.warn("Quiz process cache task already registered");
// this is expected if we run on multiple nodes
}
// schedule quiz start for all existing quizzes that are planned to start in the future
List<QuizExercise> quizExercises = quizExerciseRepository.findAllPlannedToStartInTheFuture();
log.info("Found {} quiz exercises with planned start in the future", quizExercises.size());
for (QuizExercise quizExercise : quizExercises) {
if (quizExercise.isCourseExercise()) {
// only schedule quiz exercises in courses, not in exams
// Note: the quiz exercise does not include questions and statistics, so we pass the id
scheduleQuizStart(quizExercise.getId());
}
}
} else {
log.info("Cannot start quiz exercise schedule service, it is already RUNNING");
}
}
use of de.tum.in.www1.artemis.service.scheduled.quiz.QuizScheduleService in project Artemis by ls1intum.
the class QuizScheduleService method startSchedule.
/**
* Start scheduler of quiz schedule service
*
* @param delayInMillis gap for which the QuizScheduleService should run repeatedly
*/
public void startSchedule(long delayInMillis) {
if (scheduledProcessQuizSubmissions.isNull()) {
try {
var scheduledFuture = threadPoolTaskScheduler.scheduleAtFixedRate(new QuizProcessCacheTask(), 0, delayInMillis, TimeUnit.MILLISECONDS);
scheduledProcessQuizSubmissions.set(scheduledFuture.getHandler());
log.info("QuizScheduleService was started to run repeatedly with {} second delay.", delayInMillis / 1000.0);
} catch (@SuppressWarnings("unused") DuplicateTaskException e) {
log.warn("Quiz process cache task already registered");
// this is expected if we run on multiple nodes
}
// schedule quiz start for all existing quizzes that are planned to start in the future
List<QuizExercise> quizExercises = quizExerciseRepository.findAllPlannedToStartInTheFuture();
log.info("Found {} quiz exercises with planned start in the future", quizExercises.size());
for (QuizExercise quizExercise : quizExercises) {
if (quizExercise.isCourseExercise()) {
// only schedule quiz exercises in courses, not in exams
// Note: the quiz exercise does not include questions and statistics, so we pass the id
scheduleQuizStart(quizExercise.getId());
}
}
} else {
log.info("Cannot start quiz exercise schedule service, it is already RUNNING");
}
}
Aggregations