Merge remote-tracking branch 'origin/dev-1.2' into development
Conflicts: src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/exam/ExamAdminService.java src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/exam/impl/ExamAdminServiceImpl.java
This commit is contained in:
commit
b1181bb97a
7 changed files with 73 additions and 8 deletions
|
@ -30,6 +30,7 @@ import org.joda.time.DateTime;
|
||||||
import org.mybatis.dynamic.sql.SqlBuilder;
|
import org.mybatis.dynamic.sql.SqlBuilder;
|
||||||
import org.mybatis.dynamic.sql.select.MyBatis3SelectModelAdapter;
|
import org.mybatis.dynamic.sql.select.MyBatis3SelectModelAdapter;
|
||||||
import org.mybatis.dynamic.sql.select.QueryExpressionDSL;
|
import org.mybatis.dynamic.sql.select.QueryExpressionDSL;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.transaction.annotation.Propagation;
|
import org.springframework.transaction.annotation.Propagation;
|
||||||
|
@ -78,17 +79,20 @@ public class ExamDAOImpl implements ExamDAO {
|
||||||
private final ExamRecordMapper examRecordMapper;
|
private final ExamRecordMapper examRecordMapper;
|
||||||
private final ClientConnectionRecordMapper clientConnectionRecordMapper;
|
private final ClientConnectionRecordMapper clientConnectionRecordMapper;
|
||||||
private final AdditionalAttributeRecordMapper additionalAttributeRecordMapper;
|
private final AdditionalAttributeRecordMapper additionalAttributeRecordMapper;
|
||||||
|
private final ApplicationEventPublisher applicationEventPublisher;
|
||||||
private final LmsAPIService lmsAPIService;
|
private final LmsAPIService lmsAPIService;
|
||||||
|
|
||||||
public ExamDAOImpl(
|
public ExamDAOImpl(
|
||||||
final ExamRecordMapper examRecordMapper,
|
final ExamRecordMapper examRecordMapper,
|
||||||
final ClientConnectionRecordMapper clientConnectionRecordMapper,
|
final ClientConnectionRecordMapper clientConnectionRecordMapper,
|
||||||
final AdditionalAttributeRecordMapper additionalAttributeRecordMapper,
|
final AdditionalAttributeRecordMapper additionalAttributeRecordMapper,
|
||||||
|
final ApplicationEventPublisher applicationEventPublisher,
|
||||||
final LmsAPIService lmsAPIService) {
|
final LmsAPIService lmsAPIService) {
|
||||||
|
|
||||||
this.examRecordMapper = examRecordMapper;
|
this.examRecordMapper = examRecordMapper;
|
||||||
this.clientConnectionRecordMapper = clientConnectionRecordMapper;
|
this.clientConnectionRecordMapper = clientConnectionRecordMapper;
|
||||||
this.additionalAttributeRecordMapper = additionalAttributeRecordMapper;
|
this.additionalAttributeRecordMapper = additionalAttributeRecordMapper;
|
||||||
|
this.applicationEventPublisher = applicationEventPublisher;
|
||||||
this.lmsAPIService = lmsAPIService;
|
this.lmsAPIService = lmsAPIService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -651,6 +655,9 @@ public class ExamDAOImpl implements ExamDAO {
|
||||||
|
|
||||||
final List<Long> ids = extractListOfPKs(all);
|
final List<Long> ids = extractListOfPKs(all);
|
||||||
|
|
||||||
|
// notify exam deletition listener about following deletion, to cleanup stuff before deletion
|
||||||
|
this.applicationEventPublisher.publishEvent(new ExamDeletionEvent(ids));
|
||||||
|
|
||||||
this.examRecordMapper.deleteByExample()
|
this.examRecordMapper.deleteByExample()
|
||||||
.where(ExamRecordDynamicSqlSupport.id, isIn(ids))
|
.where(ExamRecordDynamicSqlSupport.id, isIn(ids))
|
||||||
.build()
|
.build()
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 ETH Zürich, Educational Development and Technology (LET)
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ch.ethz.seb.sebserver.webservice.servicelayer.dao.impl;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.context.ApplicationEvent;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||||
|
|
||||||
|
public class ExamDeletionEvent extends ApplicationEvent {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -8910368901893082365L;
|
||||||
|
|
||||||
|
public final List<Long> ids;
|
||||||
|
|
||||||
|
public ExamDeletionEvent(final List<Long> ids) {
|
||||||
|
super(ids);
|
||||||
|
this.ids = Utils.immutableListOf(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -246,11 +246,17 @@ public class RemoteProctoringRoomDAOImpl implements RemoteProctoringRoomDAO {
|
||||||
@Transactional
|
@Transactional
|
||||||
public Result<Collection<EntityKey>> deleteRooms(final Long examId) {
|
public Result<Collection<EntityKey>> deleteRooms(final Long examId) {
|
||||||
final Result<Collection<EntityKey>> tryCatch = Result.tryCatch(() -> {
|
final Result<Collection<EntityKey>> tryCatch = Result.tryCatch(() -> {
|
||||||
final List<Long> ids = this.remoteProctoringRoomRecordMapper.selectIdsByExample()
|
final List<Long> ids = this.remoteProctoringRoomRecordMapper
|
||||||
|
.selectIdsByExample()
|
||||||
.where(RemoteProctoringRoomRecordDynamicSqlSupport.examId, isEqualTo(examId))
|
.where(RemoteProctoringRoomRecordDynamicSqlSupport.examId, isEqualTo(examId))
|
||||||
.build()
|
.build()
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
|
if (ids == null || ids.isEmpty()) {
|
||||||
|
log.info("No proctoring rooms found for exam to delete: {}", examId);
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
this.remoteProctoringRoomRecordMapper.deleteByExample()
|
this.remoteProctoringRoomRecordMapper.deleteByExample()
|
||||||
.where(RemoteProctoringRoomRecordDynamicSqlSupport.id, isIn(ids))
|
.where(RemoteProctoringRoomRecordDynamicSqlSupport.id, isIn(ids))
|
||||||
.build()
|
.build()
|
||||||
|
|
|
@ -16,6 +16,12 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamProctoringServi
|
||||||
|
|
||||||
public interface ExamAdminService {
|
public interface ExamAdminService {
|
||||||
|
|
||||||
|
/** Get the exam domain object for the exam identifier (PK).
|
||||||
|
*
|
||||||
|
* @param examId the exam identifier
|
||||||
|
* @return Result refer to the domain object or to an error when happened */
|
||||||
|
Result<Exam> examForPK(Long examId);
|
||||||
|
|
||||||
/** Saves additional attributes for the exam that are specific to a type of LMS
|
/** Saves additional attributes for the exam that are specific to a type of LMS
|
||||||
*
|
*
|
||||||
* @param exam The Exam to add the LMS specific attributes
|
* @param exam The Exam to add the LMS specific attributes
|
||||||
|
|
|
@ -76,7 +76,11 @@ public class ExamAdminServiceImpl implements ExamAdminService {
|
||||||
this.cryptor = cryptor;
|
this.cryptor = cryptor;
|
||||||
this.examProctoringServiceFactory = examProctoringServiceFactory;
|
this.examProctoringServiceFactory = examProctoringServiceFactory;
|
||||||
this.remoteProctoringRoomDAO = remoteProctoringRoomDAO;
|
this.remoteProctoringRoomDAO = remoteProctoringRoomDAO;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<Exam> examForPK(final Long examId) {
|
||||||
|
return this.examDAO.byPK(examId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -21,12 +21,12 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
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.ProctoringRoomConnection;
|
import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringRoomConnection;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringServiceSettings;
|
import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringServiceSettings;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
|
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
|
||||||
|
@ -38,6 +38,7 @@ import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ClientConnectionRecord;
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ClientConnectionRecord;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ClientConnectionDAO;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ClientConnectionDAO;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.RemoteProctoringRoomDAO;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.RemoteProctoringRoomDAO;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.impl.ExamDeletionEvent;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.exam.ExamAdminService;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.exam.ExamAdminService;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamProctoringRoomService;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamProctoringRoomService;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamProctoringService;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamProctoringService;
|
||||||
|
@ -137,16 +138,28 @@ public class ExamProctoringRoomServiceImpl implements ExamProctoringRoomService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EventListener(ExamDeletionEvent.class)
|
||||||
|
public void notifyExamDeletionEvent(final ExamDeletionEvent event) {
|
||||||
|
event.ids.forEach(examId -> {
|
||||||
|
try {
|
||||||
|
|
||||||
|
this.examAdminService.examForPK(examId)
|
||||||
|
.flatMap(this::disposeRoomsForExam)
|
||||||
|
.getOrThrow();
|
||||||
|
|
||||||
|
} catch (final Exception e) {
|
||||||
|
log.error("Failed to delete depending proctoring data for exam: {}", examId, e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result<Exam> disposeRoomsForExam(final Exam exam) {
|
public Result<Exam> disposeRoomsForExam(final Exam exam) {
|
||||||
if (exam.status != ExamStatus.FINISHED) {
|
|
||||||
log.warn("The exam has not been finished yet. No proctoring rooms will be deleted: {} / {}",
|
|
||||||
exam.name,
|
|
||||||
exam.externalId);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result.tryCatch(() -> {
|
return Result.tryCatch(() -> {
|
||||||
|
|
||||||
|
log.info("Dispose and deleting proctoring rooms for exam: {}", exam.externalId);
|
||||||
|
|
||||||
final ProctoringServiceSettings proctoringSettings = this.examAdminService
|
final ProctoringServiceSettings proctoringSettings = this.examAdminService
|
||||||
.getProctoringServiceSettings(exam.id)
|
.getProctoringServiceSettings(exam.id)
|
||||||
.getOrThrow();
|
.getOrThrow();
|
||||||
|
|
|
@ -685,6 +685,7 @@ public class ZoomProctoringService implements ExamProctoringService {
|
||||||
|
|
||||||
private final static class ZoomRestTemplate {
|
private final static class ZoomRestTemplate {
|
||||||
|
|
||||||
|
private static final int LIZENSED_USER = 2;
|
||||||
private static final String API_TEST_ENDPOINT = "v2/users";
|
private static final String API_TEST_ENDPOINT = "v2/users";
|
||||||
private static final String API_CREATE_USER_ENDPOINT = "v2/users";
|
private static final String API_CREATE_USER_ENDPOINT = "v2/users";
|
||||||
private static final String API_DELETE_USER_ENDPOINT = "v2/users/{userid}?action=delete";
|
private static final String API_DELETE_USER_ENDPOINT = "v2/users/{userid}?action=delete";
|
||||||
|
@ -749,7 +750,7 @@ public class ZoomProctoringService implements ExamProctoringService {
|
||||||
API_USER_CUST_CREATE,
|
API_USER_CUST_CREATE,
|
||||||
new CreateUserRequest.UserInfo(
|
new CreateUserRequest.UserInfo(
|
||||||
roomName + "@" + host,
|
roomName + "@" + host,
|
||||||
1,
|
LIZENSED_USER,
|
||||||
roomName,
|
roomName,
|
||||||
API_ZOOM_ROOM_USER));
|
API_ZOOM_ROOM_USER));
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue