Merge remote-tracking branch 'origin/dev-1.4' into development
This commit is contained in:
commit
e6280ed581
14 changed files with 857 additions and 54 deletions
|
@ -1,7 +1,7 @@
|
|||
coverage:
|
||||
precision: 2
|
||||
round: down
|
||||
range: "40...100"
|
||||
range: "30..70"
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
|
|
|
@ -248,6 +248,9 @@ public final class Utils {
|
|||
}
|
||||
|
||||
public static String formatDate(final DateTime dateTime) {
|
||||
if (dateTime == null) {
|
||||
return Constants.EMPTY_NOTE;
|
||||
}
|
||||
return dateTime.toString(Constants.STANDARD_DATE_TIME_MILLIS_FORMATTER);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2022 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.gui.service.remote.webservice.api.batch;
|
||||
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.BatchAction;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Page;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class GetBatchActionPage extends RestCall<Page<BatchAction>> {
|
||||
|
||||
public GetBatchActionPage() {
|
||||
super(new TypeKey<>(
|
||||
CallType.GET_PAGE,
|
||||
EntityType.BATCH_ACTION,
|
||||
new TypeReference<Page<BatchAction>>() {
|
||||
}),
|
||||
HttpMethod.GET,
|
||||
MediaType.APPLICATION_FORM_URLENCODED,
|
||||
API.BATCH_ACTION_ENDPOINT);
|
||||
}
|
||||
|
||||
}
|
|
@ -156,7 +156,7 @@ public class FilterMap extends POSTMapper {
|
|||
}
|
||||
|
||||
public String getConfigAttributeType() {
|
||||
return getSQLWildcard(ConfigurationAttribute.FILTER_ATTR_TYPE);
|
||||
return getString(ConfigurationAttribute.FILTER_ATTR_TYPE);
|
||||
}
|
||||
|
||||
public Long getConfigValueConfigId() {
|
||||
|
|
|
@ -177,7 +177,7 @@ public class ConfigurationAttributeDAOImpl implements ConfigurationAttributeDAO
|
|||
final ConfigurationAttributeRecord newRecord = new ConfigurationAttributeRecord(
|
||||
data.id,
|
||||
data.name,
|
||||
data.type.name(),
|
||||
data.type != null ? data.type.name() : null,
|
||||
data.parentId,
|
||||
data.resources,
|
||||
data.validator,
|
||||
|
|
|
@ -154,11 +154,18 @@ public class DistributedIndicatorValueService implements DisposableBean {
|
|||
final Long recId = this.clientIndicatorValueMapper.indicatorRecordIdByConnectionId(
|
||||
connectionId,
|
||||
type);
|
||||
|
||||
if (recId != null) {
|
||||
log.debug("Distributed indicator value cache already exists for: {}, {}", connectionId, type);
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Distributed indicator value cache already exists for: {}, {}", connectionId, type);
|
||||
}
|
||||
return recId;
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.info("Missing distributed indicator value cache. Create for: {}, {}", connectionId, type);
|
||||
}
|
||||
|
||||
// if not, create new one and return PK
|
||||
final ClientIndicatorRecord clientEventRecord = new ClientIndicatorRecord(
|
||||
null, connectionId, type.id, initValue);
|
||||
|
|
|
@ -60,6 +60,7 @@ import ch.ethz.seb.sebserver.gbl.util.Cryptor;
|
|||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
import ch.ethz.seb.sebserver.webservice.WebserviceInfo;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamProctoringService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamSessionService;
|
||||
|
@ -107,19 +108,22 @@ public class JitsiProctoringService implements ExamProctoringService {
|
|||
private final Cryptor cryptor;
|
||||
private final ClientHttpRequestFactoryService clientHttpRequestFactoryService;
|
||||
private final JSONMapper jsonMapper;
|
||||
private final WebserviceInfo webserviceInfo;
|
||||
|
||||
protected JitsiProctoringService(
|
||||
final AuthorizationService authorizationService,
|
||||
final ExamSessionService examSessionService,
|
||||
final Cryptor cryptor,
|
||||
final ClientHttpRequestFactoryService clientHttpRequestFactoryService,
|
||||
final JSONMapper jsonMapper) {
|
||||
final JSONMapper jsonMapper,
|
||||
final WebserviceInfo webserviceInfo) {
|
||||
|
||||
this.authorizationService = authorizationService;
|
||||
this.examSessionService = examSessionService;
|
||||
this.cryptor = cryptor;
|
||||
this.clientHttpRequestFactoryService = clientHttpRequestFactoryService;
|
||||
this.jsonMapper = jsonMapper;
|
||||
this.webserviceInfo = webserviceInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -141,6 +145,11 @@ public class JitsiProctoringService implements ExamProctoringService {
|
|||
"proctoringSettings:serverURL:invalidURL");
|
||||
}
|
||||
|
||||
// In testing we do not check the JITSI service on URL to be able to test without service
|
||||
if (this.webserviceInfo != null && this.webserviceInfo.hasProfile("test")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final ClientHttpRequestFactory clientHttpRequestFactory = this.clientHttpRequestFactoryService
|
||||
.getClientHttpRequestFactory()
|
||||
.getOrThrow();
|
||||
|
|
|
@ -206,19 +206,6 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
return page;
|
||||
}
|
||||
|
||||
protected void populateFilterMap(final FilterMap filterMap, final Long institutionId, final String sort) {
|
||||
// If current user has no read access for specified entity type within other institution
|
||||
// then the current users institutionId is put as a SQL filter criteria attribute to extends query performance
|
||||
if (!this.authorization.hasGrant(PrivilegeType.READ, getGrantEntityType())) {
|
||||
filterMap.putIfAbsent(API.PARAM_INSTITUTION_ID, String.valueOf(institutionId));
|
||||
}
|
||||
|
||||
// If sorting is on institution name we need to join the institution table
|
||||
if (sort != null && sort.contains(Entity.FILTER_ATTR_INSTITUTION)) {
|
||||
filterMap.putIfAbsent(FilterMap.ATTR_ADD_INSITUTION_JOIN, Constants.TRUE_STRING);
|
||||
}
|
||||
}
|
||||
|
||||
// ******************
|
||||
// * GET (names)
|
||||
// ******************
|
||||
|
@ -581,6 +568,19 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
.getOrThrow();
|
||||
}
|
||||
|
||||
protected void populateFilterMap(final FilterMap filterMap, final Long institutionId, final String sort) {
|
||||
// If current user has no read access for specified entity type within other institution
|
||||
// then the current users institutionId is put as a SQL filter criteria attribute to extends query performance
|
||||
if (!this.authorization.hasGrant(PrivilegeType.READ, getGrantEntityType())) {
|
||||
filterMap.putIfAbsent(API.PARAM_INSTITUTION_ID, String.valueOf(institutionId));
|
||||
}
|
||||
|
||||
// If sorting is on institution name we need to join the institution table
|
||||
if (sort != null && sort.contains(Entity.FILTER_ATTR_INSTITUTION)) {
|
||||
filterMap.putIfAbsent(FilterMap.ATTR_ADD_INSITUTION_JOIN, Constants.TRUE_STRING);
|
||||
}
|
||||
}
|
||||
|
||||
protected EnumSet<EntityType> convertToEntityType(final boolean addIncludes, final List<String> includes) {
|
||||
final EnumSet<EntityType> includeDependencies = (includes != null)
|
||||
? (includes.isEmpty())
|
||||
|
@ -783,24 +783,6 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
return this.userActivityLogDAO.logModify(entity);
|
||||
}
|
||||
|
||||
/** Makes a DELETE user activity log for the specified entity.
|
||||
* This may be overwritten if the create user activity log should be skipped.
|
||||
*
|
||||
* @param entity the Entity instance
|
||||
* @return Result refer to the logged Entity instance or to an error if happened */
|
||||
protected String logDelete(final String modelId) {
|
||||
try {
|
||||
return this.entityDAO
|
||||
.byModelId(modelId)
|
||||
.flatMap(this::logDelete)
|
||||
.map(Entity::getModelId)
|
||||
.getOrThrow();
|
||||
} catch (final Exception e) {
|
||||
log.warn("Failed to log delete for entity id: {}", modelId, e);
|
||||
return modelId;
|
||||
}
|
||||
}
|
||||
|
||||
/** Makes a DELETE user activity log for the specified entity.
|
||||
* This may be overwritten if the create user activity log should be skipped.
|
||||
*
|
||||
|
|
|
@ -41,7 +41,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.dao.WebserviceInfoDAO;
|
|||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(
|
||||
properties = "file.encoding=UTF-8",
|
||||
properties = { "file.encoding=UTF-8" },
|
||||
classes = SEBServer.class,
|
||||
webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
|
||||
@ActiveProfiles("test")
|
||||
|
@ -62,15 +62,15 @@ public abstract class GuiIntegrationTest {
|
|||
@Autowired
|
||||
protected FilterChainProxy springSecurityFilterChain;
|
||||
@Autowired
|
||||
private WebserviceInfoDAO webserviceInfoDAO;
|
||||
protected WebserviceInfoDAO webserviceInfoDAO;
|
||||
@Autowired
|
||||
private WebserviceInfo webserviceInfo;
|
||||
protected WebserviceInfo webserviceInfo;
|
||||
|
||||
protected MockMvc mockMvc;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.webserviceInfoDAO.unregister(this.webserviceInfo.getWebserviceUUID());
|
||||
//this.webserviceInfoDAO.unregister(this.webserviceInfo.getWebserviceUUID());
|
||||
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)
|
||||
.addFilter(this.springSecurityFilterChain).build();
|
||||
|
||||
|
|
|
@ -96,10 +96,15 @@ public class SEBClientBot {
|
|||
long errorInterval = ONE_SECOND;
|
||||
long warnInterval = ONE_SECOND / 2;
|
||||
long notificationInterval = 800;
|
||||
long runtime = ONE_SECOND * 3;
|
||||
long runtime = ONE_SECOND * 5;
|
||||
int connectionAttempts = 1;
|
||||
|
||||
public SEBClientBot(final String clientId, final String clientSecret, final String examId, final String instId)
|
||||
public SEBClientBot(
|
||||
final String clientId,
|
||||
final String clientSecret,
|
||||
final String examId,
|
||||
final String instId,
|
||||
final boolean wait)
|
||||
throws Exception {
|
||||
|
||||
this.clientId = clientId;
|
||||
|
@ -114,7 +119,13 @@ public class SEBClientBot {
|
|||
? this.sessionId
|
||||
: "connection_" + getRandomName();
|
||||
|
||||
new ConnectionBot(sessionId).run();
|
||||
if (wait) {
|
||||
new ConnectionBot(sessionId).run();
|
||||
} else {
|
||||
new Thread(new ConnectionBot(sessionId)).start();
|
||||
}
|
||||
|
||||
//new ConnectionBot(sessionId).run();
|
||||
//this.executorService.execute(new ConnectionBot(sessionId));
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ import org.junit.runners.MethodSorters;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.test.context.jdbc.Sql;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
@ -47,12 +48,15 @@ import org.springframework.util.StreamUtils;
|
|||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.API.BatchActionType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
||||
import ch.ethz.seb.sebserver.gbl.client.ClientCredentials;
|
||||
import ch.ethz.seb.sebserver.gbl.model.BatchAction;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain.BATCH_ACTION;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain.SEB_CLIENT_CONFIGURATION;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityDependency;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
|
@ -62,6 +66,7 @@ import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport.ErrorEntry;
|
|||
import ch.ethz.seb.sebserver.gbl.model.Page;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Chapters;
|
||||
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.Exam.ExamType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.ExamConfigurationMap;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.ExamTemplate;
|
||||
|
@ -69,6 +74,7 @@ import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
|
|||
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.IndicatorType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.Threshold;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.IndicatorTemplate;
|
||||
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.ProctoringFeature;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringServiceSettings.ProctoringServerType;
|
||||
|
@ -97,6 +103,7 @@ import ch.ethz.seb.sebserver.gbl.model.sebconfig.View;
|
|||
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
|
||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection.ConnectionStatus;
|
||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnectionData;
|
||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent.ExportType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction;
|
||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction.InstructionType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientNotification;
|
||||
|
@ -104,6 +111,7 @@ import ch.ethz.seb.sebserver.gbl.model.session.ExtendedClientEvent;
|
|||
import ch.ethz.seb.sebserver.gbl.model.session.IndicatorValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.session.MonitoringFullPageData;
|
||||
import ch.ethz.seb.sebserver.gbl.model.session.MonitoringSEBConnectionData;
|
||||
import ch.ethz.seb.sebserver.gbl.model.session.RemoteProctoringRoom;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.PasswordChange;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||
|
@ -114,7 +122,11 @@ import ch.ethz.seb.sebserver.gui.service.examconfig.impl.AttributeMapping;
|
|||
import ch.ethz.seb.sebserver.gui.service.examconfig.impl.ExamConfigurationServiceImpl;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCallError;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestServiceImpl;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.batch.DoBatchAction;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.batch.GetBatchAction;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.batch.GetBatchActionPage;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.ActivateSEBRestriction;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.ArchiveExam;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.CheckExamConsistency;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.CheckExamImported;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.CheckSEBRestriction;
|
||||
|
@ -165,7 +177,9 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.GetLmsSe
|
|||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.NewLmsSetup;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.SaveLmsSetup;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.TestLmsSetup;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs.DeleteAllClientEvents;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs.DeleteAllUserLogs;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs.ExportSEBClientLogs;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs.GetExtendedClientEventPage;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs.GetUserLogNames;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs.GetUserLogPage;
|
||||
|
@ -214,18 +228,27 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.Sa
|
|||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfigHistory;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfigTableValues;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfigValue;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.CloseProctoringRoom;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.ConfirmPendingClientNotification;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.DisableClientConnection;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetClientConnection;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetClientConnectionDataList;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetClientConnectionPage;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetCollectingRoomConnections;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetCollectingRooms;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetFinishedExamClientConnection;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetFinishedExamClientConnectionPage;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetFinishedExamPage;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetMonitoringFullPageData;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetPendingClientNotifications;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetProctorRoomConnection;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetRunningExamPage;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetTownhallRoom;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.IsTownhallRoomAvailable;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.NotifyProctoringRoomOpened;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.OpenTownhallRoom;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.PropagateInstruction;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.SendProctoringReconfigurationAttributes;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.ActivateUserAccount;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.ChangePassword;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.DeleteUserAccount;
|
||||
|
@ -235,7 +258,9 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUs
|
|||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.NewUserAccount;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.RegisterNewUser;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.SaveUserAccount;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ClientConnectionDAO;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.SEBClientConfigDAO;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamProctoringRoomService;
|
||||
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
public class UseCasesIntegrationTest extends GuiIntegrationTest {
|
||||
|
@ -2107,6 +2132,8 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
|
|||
new GetClientConnection(),
|
||||
new GetMonitoringFullPageData(),
|
||||
new GetExtendedClientEventPage(),
|
||||
new ExportSEBClientLogs(),
|
||||
new DeleteAllClientEvents(),
|
||||
new DisableClientConnection(),
|
||||
new PropagateInstruction(),
|
||||
new GetClientConnectionPage(),
|
||||
|
@ -2123,7 +2150,8 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
|
|||
new ActivateClientConfig(),
|
||||
new GetClientConfigPage(),
|
||||
new GetIndicatorPage(),
|
||||
new GetIndicators());
|
||||
new GetIndicators(),
|
||||
new DeleteAllClientEvents());
|
||||
|
||||
// get running exams
|
||||
final Result<Page<Exam>> runningExamsCall = restService.getBuilder(GetRunningExamPage.class)
|
||||
|
@ -2162,7 +2190,8 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
|
|||
.collect(Collectors.toList()).toString());
|
||||
|
||||
// get active client config's credentials
|
||||
final Result<Page<SEBClientConfig>> cconfigs = adminRestService.getBuilder(GetClientConfigPage.class)
|
||||
final Result<Page<SEBClientConfig>> cconfigs = adminRestService
|
||||
.getBuilder(GetClientConfigPage.class)
|
||||
.call();
|
||||
assertNotNull(cconfigs);
|
||||
assertFalse(cconfigs.hasError());
|
||||
|
@ -2171,7 +2200,8 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
|
|||
|
||||
final SEBClientConfig clientConfig = ccPage.content.get(0);
|
||||
assertTrue(clientConfig.isActive());
|
||||
final ClientCredentials credentials = this.sebClientConfigDAO.getSEBClientCredentials(clientConfig.getModelId())
|
||||
final ClientCredentials credentials = this.sebClientConfigDAO
|
||||
.getSEBClientCredentials(clientConfig.getModelId())
|
||||
.getOrThrow();
|
||||
|
||||
adminRestService.getBuilder(ActivateClientConfig.class)
|
||||
|
@ -2184,8 +2214,9 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
|
|||
credentials.clientIdAsString(),
|
||||
this.cryptor.decrypt(credentials.secret).getOrThrow().toString(),
|
||||
exam.getModelId(),
|
||||
String.valueOf(exam.institutionId));
|
||||
Thread.sleep(1000);
|
||||
String.valueOf(exam.institutionId),
|
||||
true);
|
||||
//Thread.sleep(1000);
|
||||
|
||||
// send get connections
|
||||
connectionsCall =
|
||||
|
@ -2263,7 +2294,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
|
|||
assertNotNull(instructionCall);
|
||||
assertFalse(instructionCall.hasError());
|
||||
|
||||
Thread.sleep(1000);
|
||||
//Thread.sleep(1000);
|
||||
} catch (final Exception e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
@ -2315,7 +2346,8 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
|
|||
assertEquals("DISABLED", conData.clientConnection.status.name());
|
||||
|
||||
// get client logs
|
||||
final Result<Page<ExtendedClientEvent>> clientLogPage = restService.getBuilder(GetExtendedClientEventPage.class)
|
||||
final Result<Page<ExtendedClientEvent>> clientLogPage = restService
|
||||
.getBuilder(GetExtendedClientEventPage.class)
|
||||
.call();
|
||||
|
||||
assertNotNull(clientLogPage);
|
||||
|
@ -2325,6 +2357,32 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
|
|||
final ExtendedClientEvent extendedClientEvent = clientLogs.content.get(0);
|
||||
assertNotNull(extendedClientEvent);
|
||||
|
||||
// export client logs
|
||||
restService
|
||||
.getBuilder(ExportSEBClientLogs.class)
|
||||
.withQueryParam(API.SEB_CLIENT_EVENT_EXPORT_TYPE, ExportType.CSV.name())
|
||||
.withQueryParam(API.SEB_CLIENT_EVENT_EXPORT_INCLUDE_EXAMS, "true")
|
||||
.withResponseExtractor(response -> {
|
||||
final HttpStatus statusCode = response.getStatusCode();
|
||||
assertEquals("200 OK", statusCode.toString());
|
||||
final String csvExport = IOUtils.toString(response.getBody());
|
||||
assertTrue(StringUtils.isNotBlank(csvExport));
|
||||
return true;
|
||||
})
|
||||
.call();
|
||||
|
||||
// delete client logs
|
||||
final Result<EntityProcessingReport> report = adminRestService
|
||||
.getBuilder(DeleteAllClientEvents.class)
|
||||
.withFormParam(
|
||||
API.PARAM_MODEL_ID_LIST,
|
||||
StringUtils.join(
|
||||
clientLogs.content.stream().map(e -> e.getModelId()).collect(Collectors.toList()), ","))
|
||||
.call();
|
||||
|
||||
assertNotNull(report);
|
||||
assertFalse(report.hasError());
|
||||
|
||||
// get client connection page
|
||||
Result<Page<ClientConnection>> connectionPageRes = restService
|
||||
.getBuilder(GetClientConnectionPage.class)
|
||||
|
@ -2344,6 +2402,44 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
|
|||
connectionPage = connectionPageRes.get();
|
||||
assertNotNull(connectionPage);
|
||||
assertTrue(connectionPage.isEmpty());
|
||||
|
||||
Result<Page<ClientConnectionData>> connectionDatacall = restService
|
||||
.getBuilder(GetFinishedExamClientConnectionPage.class)
|
||||
.withURIVariable(API.PARAM_PARENT_MODEL_ID, exam.getModelId())
|
||||
.call();
|
||||
assertNotNull(connectionDatacall);
|
||||
assertFalse(connectionDatacall.hasError());
|
||||
Page<ClientConnectionData> ccDataPage = connectionDatacall.get();
|
||||
assertNotNull(ccDataPage);
|
||||
assertFalse(ccDataPage.content.isEmpty());
|
||||
final ClientConnectionData clientConnectionData = ccDataPage.content.get(0);
|
||||
assertNotNull(clientConnectionData);
|
||||
assertEquals("DISABLED", clientConnectionData.clientConnection.status.toString());
|
||||
|
||||
connectionDatacall = restService
|
||||
.getBuilder(GetFinishedExamClientConnectionPage.class)
|
||||
.withURIVariable(API.PARAM_PARENT_MODEL_ID, exam.getModelId())
|
||||
.withQueryParam(ClientConnection.FILTER_ATTR_INFO, "test")
|
||||
.call();
|
||||
assertNotNull(connectionDatacall);
|
||||
assertFalse(connectionDatacall.hasError());
|
||||
ccDataPage = connectionDatacall.get();
|
||||
assertNotNull(ccDataPage);
|
||||
assertTrue(ccDataPage.content.isEmpty());
|
||||
|
||||
final Result<ClientConnectionData> ccDataCall = restService
|
||||
.getBuilder(GetFinishedExamClientConnection.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, clientConnectionData.getModelId())
|
||||
.call();
|
||||
|
||||
assertNotNull(ccDataCall);
|
||||
assertFalse(ccDataCall.hasError());
|
||||
final ClientConnectionData clientConnectionData2 = ccDataCall.get();
|
||||
assertNotNull(clientConnectionData2);
|
||||
assertEquals(
|
||||
clientConnectionData2.clientConnection.connectionToken,
|
||||
clientConnectionData.clientConnection.connectionToken);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -3457,4 +3553,466 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
|
|||
.getOrThrow();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(27)
|
||||
// *************************************
|
||||
// Use Case 27: Login as admin and set exam proctoring settings for Jtisi
|
||||
// - Get Exam (running)
|
||||
// - Set Proctoring settings for exam
|
||||
// - Check settings for exam
|
||||
public void testUsecase27_SetProctoringSettingsJitsiForExam() throws IOException {
|
||||
final RestServiceImpl restService = createRestServiceForUser(
|
||||
"admin",
|
||||
"admin",
|
||||
new GetExamPage(),
|
||||
new GetExamProctoringSettings(),
|
||||
new SaveExamProctoringSettings(),
|
||||
new IsTownhallRoomAvailable(),
|
||||
new GetCollectingRooms());
|
||||
|
||||
// get exam
|
||||
final Result<Page<Exam>> exams = restService
|
||||
.getBuilder(GetExamPage.class)
|
||||
.call();
|
||||
|
||||
assertNotNull(exams);
|
||||
assertFalse(exams.hasError());
|
||||
final Page<Exam> examPage = exams.get();
|
||||
assertFalse(examPage.isEmpty());
|
||||
|
||||
final Exam runningExam = examPage.content
|
||||
.stream()
|
||||
.filter(exam -> exam.status == ExamStatus.RUNNING)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
assertNotNull(runningExam);
|
||||
assertTrue(runningExam.status == ExamStatus.RUNNING);
|
||||
|
||||
final Result<ProctoringServiceSettings> pSettings = restService
|
||||
.getBuilder(GetExamProctoringSettings.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
|
||||
.call();
|
||||
|
||||
assertNotNull(pSettings);
|
||||
assertFalse(pSettings.hasError());
|
||||
ProctoringServiceSettings proctoringServiceSettings = pSettings.get();
|
||||
assertFalse(proctoringServiceSettings.enableProctoring);
|
||||
assertNull(proctoringServiceSettings.serverURL);
|
||||
|
||||
// set proctoring settings
|
||||
final ProctoringServiceSettings newProctoringServiceSettings = new ProctoringServiceSettings(
|
||||
runningExam.id,
|
||||
true,
|
||||
ProctoringServerType.JITSI_MEET,
|
||||
"https://test.proc/service",
|
||||
2,
|
||||
EnumSet.allOf(ProctoringFeature.class),
|
||||
true,
|
||||
"appKey", "appSecret",
|
||||
"sdkKey", "sdkSecret",
|
||||
false);
|
||||
|
||||
final Result<ProctoringServiceSettings> newProcSettings = restService
|
||||
.getBuilder(SaveExamProctoringSettings.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
|
||||
.withBody(newProctoringServiceSettings)
|
||||
.call();
|
||||
|
||||
assertNotNull(newProcSettings);
|
||||
assertFalse(newProcSettings.hasError());
|
||||
|
||||
proctoringServiceSettings = restService
|
||||
.getBuilder(GetExamProctoringSettings.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
|
||||
.call()
|
||||
.get();
|
||||
|
||||
assertTrue(proctoringServiceSettings.enableProctoring);
|
||||
assertEquals("https://test.proc/service", proctoringServiceSettings.serverURL);
|
||||
|
||||
final String twonhallRoom = restService
|
||||
.getBuilder(IsTownhallRoomAvailable.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
|
||||
.call()
|
||||
.get();
|
||||
|
||||
assertEquals("true", twonhallRoom);
|
||||
|
||||
final Collection<RemoteProctoringRoom> collectingRooms = restService
|
||||
.getBuilder(GetCollectingRooms.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
|
||||
.call()
|
||||
.get();
|
||||
|
||||
assertNotNull(collectingRooms);
|
||||
assertTrue(collectingRooms.isEmpty());
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private ExamProctoringRoomService examProcotringRoomService;
|
||||
@Autowired
|
||||
private ClientConnectionDAO clientConnectionDAO;
|
||||
|
||||
@Test
|
||||
@Order(28)
|
||||
// *************************************
|
||||
// Use Case 28: Login as admin and connect with SEBs to running exam with procotring enabled
|
||||
// - Get Exam (running)
|
||||
// - start some SEB clients connecting to running exam
|
||||
// - Check collecting rooms created
|
||||
public void testUsecase28_TestExamProctoring() throws IOException {
|
||||
|
||||
final RestServiceImpl restService = createRestServiceForUser(
|
||||
"admin",
|
||||
"admin",
|
||||
new GetExamPage(),
|
||||
new GetExamProctoringSettings(),
|
||||
new SaveExamProctoringSettings(),
|
||||
new IsTownhallRoomAvailable(),
|
||||
new GetCollectingRooms(),
|
||||
new GetClientConfigPage(),
|
||||
new ActivateClientConfig(),
|
||||
new NewClientConfig(),
|
||||
new GetClientConfig(),
|
||||
new GetProctorRoomConnection(),
|
||||
new GetCollectingRoomConnections(),
|
||||
new NotifyProctoringRoomOpened(),
|
||||
new SendProctoringReconfigurationAttributes(),
|
||||
new GetTownhallRoom(),
|
||||
new OpenTownhallRoom(),
|
||||
new CloseProctoringRoom());
|
||||
|
||||
// get exam
|
||||
final Result<Page<Exam>> exams = restService
|
||||
.getBuilder(GetExamPage.class)
|
||||
.call();
|
||||
|
||||
assertNotNull(exams);
|
||||
assertFalse(exams.hasError());
|
||||
final Page<Exam> examPage = exams.get();
|
||||
assertFalse(examPage.isEmpty());
|
||||
|
||||
final Exam runningExam = examPage.content
|
||||
.stream()
|
||||
.filter(exam -> exam.status == ExamStatus.RUNNING)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
assertNotNull(runningExam);
|
||||
assertTrue(runningExam.status == ExamStatus.RUNNING);
|
||||
|
||||
final Result<ProctoringServiceSettings> pSettings = restService
|
||||
.getBuilder(GetExamProctoringSettings.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
|
||||
.call();
|
||||
|
||||
assertNotNull(pSettings);
|
||||
assertFalse(pSettings.hasError());
|
||||
final ProctoringServiceSettings proctoringServiceSettings = pSettings.get();
|
||||
assertTrue(proctoringServiceSettings.enableProctoring);
|
||||
assertEquals("https://test.proc/service", proctoringServiceSettings.serverURL);
|
||||
|
||||
// start some SEB connections for this exam
|
||||
|
||||
// create SEB Client Config without password protection
|
||||
Result<SEBClientConfig> newConfigResponse = restService
|
||||
.getBuilder(NewClientConfig.class)
|
||||
.withFormParam(Domain.SEB_CLIENT_CONFIGURATION.ATTR_NAME, "No Password Protection")
|
||||
.withFormParam(SEBClientConfig.ATTR_FALLBACK, Constants.TRUE_STRING)
|
||||
.withFormParam(SEBClientConfig.ATTR_FALLBACK_START_URL, "http://fallback.com/fallback")
|
||||
.withFormParam(SEBClientConfig.ATTR_FALLBACK_TIMEOUT, "100")
|
||||
.withFormParam(SEBClientConfig.ATTR_FALLBACK_ATTEMPTS, "5")
|
||||
.withFormParam(SEBClientConfig.ATTR_FALLBACK_ATTEMPT_INTERVAL, "5")
|
||||
.withFormParam(SEBClientConfig.ATTR_CONFIG_PURPOSE, SEBClientConfig.ConfigPurpose.START_EXAM.name())
|
||||
.call();
|
||||
|
||||
assertNotNull(newConfigResponse);
|
||||
assertFalse(newConfigResponse.hasError());
|
||||
final SEBClientConfig sebClientConfig = newConfigResponse.get();
|
||||
assertEquals("No Password Protection", sebClientConfig.name);
|
||||
assertFalse(sebClientConfig.isActive());
|
||||
assertEquals("http://fallback.com/fallback", sebClientConfig.fallbackStartURL);
|
||||
|
||||
// activate the new Client Configuration
|
||||
restService
|
||||
.getBuilder(ActivateClientConfig.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, sebClientConfig.getModelId())
|
||||
.call();
|
||||
|
||||
newConfigResponse = restService.getBuilder(GetClientConfig.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, sebClientConfig.getModelId())
|
||||
.call();
|
||||
|
||||
final SEBClientConfig clientConfig = newConfigResponse.get();
|
||||
assertTrue(clientConfig.isActive());
|
||||
final ClientCredentials credentials = this.sebClientConfigDAO
|
||||
.getSEBClientCredentials(clientConfig.getModelId())
|
||||
.getOrThrow();
|
||||
|
||||
assertTrue(clientConfig.isActive());
|
||||
|
||||
// simulate a SEB connection
|
||||
try {
|
||||
new SEBClientBot(
|
||||
credentials.clientIdAsString(),
|
||||
this.cryptor.decrypt(credentials.secret).getOrThrow().toString(),
|
||||
runningExam.getModelId(),
|
||||
String.valueOf(runningExam.institutionId),
|
||||
false);
|
||||
|
||||
Thread.sleep(1000);
|
||||
|
||||
this.examProcotringRoomService.updateProctoringCollectingRooms();
|
||||
|
||||
// check collecting room was created
|
||||
final Collection<RemoteProctoringRoom> collectingRooms = restService
|
||||
.getBuilder(GetCollectingRooms.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
|
||||
.call()
|
||||
.get();
|
||||
|
||||
assertNotNull(collectingRooms);
|
||||
assertFalse(collectingRooms.isEmpty());
|
||||
// Two rooms a two people for four connections
|
||||
assertEquals(2, collectingRooms.size());
|
||||
final RemoteProctoringRoom room1 = collectingRooms.iterator().next();
|
||||
assertEquals(2, room1.roomSize.intValue());
|
||||
assertFalse(room1.townhallRoom);
|
||||
|
||||
final ProctoringRoomConnection proctoringRoomConnection = restService
|
||||
.getBuilder(GetProctorRoomConnection.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
|
||||
.withQueryParam(ProctoringRoomConnection.ATTR_ROOM_NAME, room1.name)
|
||||
.call()
|
||||
.get();
|
||||
|
||||
assertNotNull(proctoringRoomConnection);
|
||||
assertEquals(room1.name, proctoringRoomConnection.roomName);
|
||||
assertNotNull(proctoringRoomConnection.accessToken);
|
||||
|
||||
// notify room open
|
||||
restService
|
||||
.getBuilder(NotifyProctoringRoomOpened.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
|
||||
.withQueryParam(ProctoringRoomConnection.ATTR_ROOM_NAME, room1.name)
|
||||
.call()
|
||||
.get();
|
||||
|
||||
// reconfigure clients in room
|
||||
restService
|
||||
.getBuilder(SendProctoringReconfigurationAttributes.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
|
||||
.withQueryParam(Domain.REMOTE_PROCTORING_ROOM.ATTR_ID, room1.name)
|
||||
.withQueryParam(API.EXAM_PROCTORING_ATTR_RECEIVE_AUDIO, "true")
|
||||
.withQueryParam(API.EXAM_PROCTORING_ATTR_RECEIVE_VIDEO, "true")
|
||||
.withQueryParam(API.EXAM_PROCTORING_ATTR_ALLOW_CHAT, "true")
|
||||
.call()
|
||||
.get();
|
||||
|
||||
final Collection<ClientConnection> collection = restService
|
||||
.getBuilder(GetCollectingRoomConnections.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
|
||||
.withQueryParam(Domain.REMOTE_PROCTORING_ROOM.ATTR_ID, room1.name)
|
||||
.call()
|
||||
.get();
|
||||
|
||||
assertNotNull(collection);
|
||||
assertFalse(collection.isEmpty());
|
||||
assertEquals(2, collection.size());
|
||||
final ClientConnection connection = collection.iterator().next();
|
||||
assertEquals(runningExam.id, connection.examId);
|
||||
// this is because the Json model do not contian certain attributes due to performance
|
||||
assertNull(connection.remoteProctoringRoomId);
|
||||
// we can geht the room number by getting it directyl from the record
|
||||
final ClientConnection clientConnection = this.clientConnectionDAO.byPK(connection.id).get();
|
||||
assertNotNull(clientConnection.remoteProctoringRoomId);
|
||||
|
||||
// get and open townhall
|
||||
final String townhallActive = restService
|
||||
.getBuilder(IsTownhallRoomAvailable.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
|
||||
.call()
|
||||
.get();
|
||||
|
||||
assertEquals("true", townhallActive);
|
||||
|
||||
// check no Townhallroom yet
|
||||
RemoteProctoringRoom townhallRoom = restService
|
||||
.getBuilder(GetTownhallRoom.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
|
||||
.call()
|
||||
.get();
|
||||
assertEquals(RemoteProctoringRoom.NULL_ROOM, townhallRoom);
|
||||
|
||||
// open townhall room
|
||||
final ProctoringRoomConnection townhallRoomConntection = restService
|
||||
.getBuilder(OpenTownhallRoom.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
|
||||
.call()
|
||||
.get();
|
||||
|
||||
assertNotNull(townhallRoomConntection);
|
||||
|
||||
// check Townhallroom is available yet
|
||||
townhallRoom = restService
|
||||
.getBuilder(GetTownhallRoom.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
|
||||
.call()
|
||||
.get();
|
||||
assertTrue(townhallRoom.townhallRoom);
|
||||
assertEquals(townhallRoom.name, townhallRoomConntection.roomName);
|
||||
|
||||
// close townhall room
|
||||
restService
|
||||
.getBuilder(CloseProctoringRoom.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
|
||||
.withQueryParam(ProctoringRoomConnection.ATTR_ROOM_NAME, townhallRoom.name)
|
||||
.call()
|
||||
.get();
|
||||
|
||||
townhallRoom = restService
|
||||
.getBuilder(GetTownhallRoom.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
|
||||
.call()
|
||||
.get();
|
||||
assertEquals(RemoteProctoringRoom.NULL_ROOM, townhallRoom);
|
||||
|
||||
Thread.sleep(5000);
|
||||
|
||||
} catch (final Exception e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(29)
|
||||
// *************************************
|
||||
// Use Case 29: Login as admin and create some batch actions
|
||||
// - Get Exam (running)
|
||||
// - start some SEB clients connecting to running exam
|
||||
// - Check collecting rooms created
|
||||
public void testUsecase29_TestBatchAction() throws IOException, InterruptedException {
|
||||
final RestServiceImpl restService = createRestServiceForUser(
|
||||
"admin",
|
||||
"admin",
|
||||
new DoBatchAction(),
|
||||
new GetBatchAction(),
|
||||
new GetBatchActionPage(),
|
||||
new GetExamConfigNodePage());
|
||||
|
||||
final ConfigurationNode config = restService
|
||||
.getBuilder(GetExamConfigNodePage.class)
|
||||
.call()
|
||||
.getOrThrow().content
|
||||
.get(0);
|
||||
assertNotNull(config);
|
||||
assertEquals("READY_TO_USE", config.status.toString());
|
||||
|
||||
// apply batch action
|
||||
final Result<BatchAction> doBatchAction = restService
|
||||
.getBuilder(DoBatchAction.class)
|
||||
.withFormParam(Domain.BATCH_ACTION.ATTR_ACTION_TYPE, BatchActionType.EXAM_CONFIG_STATE_CHANGE.name())
|
||||
.withFormParam(BATCH_ACTION.ATTR_SOURCE_IDS, config.getModelId())
|
||||
.withFormParam(BatchAction.ACTION_ATTRIBUT_TARGET_STATE, ConfigurationStatus.CONSTRUCTION.name())
|
||||
.call();
|
||||
|
||||
assertNotNull(doBatchAction);
|
||||
assertFalse(doBatchAction.hasError());
|
||||
final BatchAction batchAction = doBatchAction.get();
|
||||
assertNotNull(batchAction);
|
||||
assertNotNull(batchAction.ownerId);
|
||||
assertFalse(batchAction.isFinished());
|
||||
assertEquals("EXAM_CONFIG_STATE_CHANGE", batchAction.actionType.name());
|
||||
|
||||
Thread.sleep(1000);
|
||||
|
||||
final BatchAction savedBatchAction = restService
|
||||
.getBuilder(GetBatchAction.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, batchAction.getModelId())
|
||||
.call().get();
|
||||
|
||||
assertNotNull(savedBatchAction);
|
||||
assertNotNull(savedBatchAction.ownerId);
|
||||
assertTrue(savedBatchAction.isFinished());
|
||||
assertEquals("EXAM_CONFIG_STATE_CHANGE", savedBatchAction.actionType.name());
|
||||
assertNotNull(savedBatchAction.processorId);
|
||||
|
||||
final Page<BatchAction> page = restService
|
||||
.getBuilder(GetBatchActionPage.class)
|
||||
.call().get();
|
||||
|
||||
assertNotNull(page);
|
||||
assertFalse(page.content.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(30)
|
||||
// *************************************
|
||||
// Use Case 30: Login as admin and archive finished exam
|
||||
// - Get Exam (finished), archive and check
|
||||
public void testUsecase30_TestArchiveExam() throws IOException {
|
||||
final RestServiceImpl restService = createRestServiceForUser(
|
||||
"admin",
|
||||
"admin",
|
||||
new GetExamPage(),
|
||||
new GetExam(),
|
||||
new ArchiveExam());
|
||||
|
||||
final Page<Exam> finishedExams = restService
|
||||
.getBuilder(GetExamPage.class)
|
||||
.withQueryParam(Exam.FILTER_ATTR_STATUS, ExamStatus.FINISHED.name())
|
||||
.call()
|
||||
.get();
|
||||
|
||||
assertNotNull(finishedExams);
|
||||
assertFalse(finishedExams.content.isEmpty());
|
||||
final Exam exam = finishedExams.content.get(0);
|
||||
assertEquals(ExamStatus.FINISHED, exam.status);
|
||||
|
||||
final Result<Exam> archiveCall = restService.getBuilder(ArchiveExam.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, exam.getModelId())
|
||||
.call();
|
||||
|
||||
assertNotNull(archiveCall);
|
||||
assertFalse(archiveCall.hasError());
|
||||
final Exam exam2 = archiveCall.get();
|
||||
assertNotNull(exam2);
|
||||
assertEquals(exam.id, exam2.id);
|
||||
assertEquals(ExamStatus.ARCHIVED, exam2.status);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(31)
|
||||
// *************************************
|
||||
// Use Case 31: Login as admin and archive finished exam
|
||||
// - Get Exam (running), archive and check not possible
|
||||
public void testUsecase31_TestArchiveRunningExam_NotPossible() throws IOException {
|
||||
final RestServiceImpl restService = createRestServiceForUser(
|
||||
"admin",
|
||||
"admin",
|
||||
new GetExamPage(),
|
||||
new GetExam(),
|
||||
new ArchiveExam());
|
||||
|
||||
final Page<Exam> finishedExams = restService
|
||||
.getBuilder(GetExamPage.class)
|
||||
.withQueryParam(Exam.FILTER_ATTR_STATUS, ExamStatus.RUNNING.name())
|
||||
.call()
|
||||
.get();
|
||||
|
||||
assertNotNull(finishedExams);
|
||||
assertFalse(finishedExams.content.isEmpty());
|
||||
final Exam exam = finishedExams.content.get(0);
|
||||
assertEquals(ExamStatus.RUNNING, exam.status);
|
||||
|
||||
final Result<Exam> archiveCall = restService.getBuilder(ArchiveExam.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, exam.getModelId())
|
||||
.call();
|
||||
|
||||
assertNotNull(archiveCall);
|
||||
assertTrue(archiveCall.hasError());
|
||||
assertTrue(archiveCall.getError().getMessage().contains("Exam is in wrong status to archive"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
* Copyright (c) 2022 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.integration.api.admin;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.Test;
|
||||
import org.junit.runners.MethodSorters;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.test.context.jdbc.Sql;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityName;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Page;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.impl.SEBServerUser;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.impl.UserServiceImpl;
|
||||
import ch.ethz.seb.sebserver.webservice.weblayer.api.ConfigurationAttributeController;
|
||||
|
||||
@Sql(scripts = { "classpath:schema-test.sql", "classpath:data-test.sql", "classpath:data-test-additional.sql" })
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
public class ConfigurationAttributeAPITest extends AdministrationAPIIntegrationTester {
|
||||
|
||||
@Autowired
|
||||
private ConfigurationAttributeController configurationAttributeController;
|
||||
@Autowired
|
||||
private UserServiceImpl userServiceImpl;
|
||||
@Mock
|
||||
private HttpServletRequest mockRequest;
|
||||
|
||||
private final MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
this.userServiceImpl.setAuthenticationIfAbsent(new SEBServerUser(
|
||||
-1L,
|
||||
new UserInfo("user1", 1L, null, "admin", null, null, null, true, null, null,
|
||||
EnumSet.allOf(UserRole.class).stream().map(r -> r.name()).collect(Collectors.toSet())),
|
||||
null));
|
||||
Mockito.when(this.mockRequest.getQueryString()).thenReturn("");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(1)
|
||||
public void test1_GetPage() {
|
||||
final Page<ConfigurationAttribute> page = this.configurationAttributeController.getPage(
|
||||
1L, 0, 100, null,
|
||||
new LinkedMultiValueMap<String, String>(),
|
||||
this.mockRequest);
|
||||
|
||||
assertNotNull(page);
|
||||
assertFalse(page.content.isEmpty());
|
||||
assertEquals("100", String.valueOf(page.content.size()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(2)
|
||||
public void test2_GetNames() {
|
||||
Collection<EntityName> names = this.configurationAttributeController.getNames(
|
||||
1L,
|
||||
new LinkedMultiValueMap<String, String>(),
|
||||
this.mockRequest);
|
||||
|
||||
assertNotNull(names);
|
||||
assertFalse(names.isEmpty());
|
||||
assertEquals("241", String.valueOf(names.size()));
|
||||
|
||||
this.params.clear();
|
||||
this.params.add(ConfigurationAttribute.FILTER_ATTR_TYPE, AttributeType.CHECKBOX.name());
|
||||
|
||||
names = this.configurationAttributeController.getNames(
|
||||
1L,
|
||||
this.params,
|
||||
this.mockRequest);
|
||||
|
||||
assertNotNull(names);
|
||||
assertFalse(names.isEmpty());
|
||||
assertEquals("139", String.valueOf(names.size()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(3)
|
||||
public void test3_GetSingle() {
|
||||
final ConfigurationAttribute attr = this.configurationAttributeController.getBy("1");
|
||||
|
||||
assertNotNull(attr);
|
||||
assertEquals("hashedAdminPassword", attr.name);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(4)
|
||||
public void test4_GetList() {
|
||||
List<ConfigurationAttribute> forIds = this.configurationAttributeController.getForIds("1,2");
|
||||
|
||||
assertNotNull(forIds);
|
||||
assertEquals("2", String.valueOf(forIds.size()));
|
||||
|
||||
forIds = this.configurationAttributeController.getForIds(null);
|
||||
|
||||
assertNotNull(forIds);
|
||||
assertEquals("241", String.valueOf(forIds.size()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(5)
|
||||
public void test5_CreateAndSaveAndDelete() {
|
||||
this.params.clear();
|
||||
this.params.add(Domain.CONFIGURATION_ATTRIBUTE.ATTR_PARENT_ID, null);
|
||||
this.params.add(Domain.CONFIGURATION_ATTRIBUTE.ATTR_NAME, "testAttribute");
|
||||
this.params.add(Domain.CONFIGURATION_ATTRIBUTE.ATTR_TYPE, AttributeType.CHECKBOX.name());
|
||||
this.params.add(Domain.CONFIGURATION_ATTRIBUTE.ATTR_RESOURCES, "");
|
||||
this.params.add(Domain.CONFIGURATION_ATTRIBUTE.ATTR_VALIDATOR, "");
|
||||
this.params.add(Domain.CONFIGURATION_ATTRIBUTE.ATTR_DEPENDENCIES, "");
|
||||
this.params.add(Domain.CONFIGURATION_ATTRIBUTE.ATTR_DEFAULT_VALUE, "true");
|
||||
|
||||
final ConfigurationAttribute create = this.configurationAttributeController.create(
|
||||
this.params,
|
||||
1L,
|
||||
this.mockRequest);
|
||||
|
||||
assertNotNull(create);
|
||||
assertNotNull(create.id);
|
||||
assertEquals("testAttribute", create.name);
|
||||
assertEquals("true", create.defaultValue);
|
||||
|
||||
final ConfigurationAttribute savePut = this.configurationAttributeController.savePut(new ConfigurationAttribute(
|
||||
create.id,
|
||||
null, null, null, null, null, null,
|
||||
"false"));
|
||||
|
||||
assertNotNull(savePut);
|
||||
assertNotNull(savePut.id);
|
||||
assertEquals("testAttribute", savePut.name);
|
||||
assertEquals("false", savePut.defaultValue);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(6)
|
||||
public void test6_NoDeletionSupport() {
|
||||
|
||||
try {
|
||||
this.configurationAttributeController.hardDeleteAll(
|
||||
Arrays.asList("1,2,3"),
|
||||
false,
|
||||
null,
|
||||
1L);
|
||||
fail("Error expected here");
|
||||
} catch (final Exception e) {
|
||||
assertEquals(
|
||||
"No bulk action support for: BulkAction [type=HARD_DELETE, sourceType=CONFIGURATION_ATTRIBUTE, sources=[]]",
|
||||
e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
this.configurationAttributeController.hardDelete(
|
||||
"1",
|
||||
false,
|
||||
null);
|
||||
fail("Error expected here");
|
||||
} catch (final Exception e) {
|
||||
assertEquals(
|
||||
"No bulk action support for: BulkAction [type=HARD_DELETE, sourceType=CONFIGURATION_ATTRIBUTE, sources=[EntityName [entityType=CONFIGURATION_ATTRIBUTE, modelId=1, name=hashedAdminPassword]]]",
|
||||
e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -81,7 +81,7 @@ public class ExamJITSIProctoringServiceTest {
|
|||
final Cryptor cryptorMock = Mockito.mock(Cryptor.class);
|
||||
Mockito.when(cryptorMock.decrypt(Mockito.any())).thenReturn(Result.of("fbvgeghergrgrthrehreg123"));
|
||||
final JitsiProctoringService examJITSIProctoringService =
|
||||
new JitsiProctoringService(null, null, cryptorMock, null, new JSONMapper());
|
||||
new JitsiProctoringService(null, null, cryptorMock, null, new JSONMapper(), null);
|
||||
|
||||
String accessToken = examJITSIProctoringService.createPayload(
|
||||
"test-app",
|
||||
|
@ -115,7 +115,7 @@ public class ExamJITSIProctoringServiceTest {
|
|||
final Cryptor cryptorMock = Mockito.mock(Cryptor.class);
|
||||
Mockito.when(cryptorMock.decrypt(Mockito.any())).thenReturn(Result.of("fbvgeghergrgrthrehreg123"));
|
||||
final JitsiProctoringService examJITSIProctoringService =
|
||||
new JitsiProctoringService(null, null, cryptorMock, null, new JSONMapper());
|
||||
new JitsiProctoringService(null, null, cryptorMock, null, new JSONMapper(), null);
|
||||
final ProctoringRoomConnection data = examJITSIProctoringService.createProctoringConnection(
|
||||
"connectionToken",
|
||||
"https://seb-jitsi.example.ch",
|
||||
|
@ -160,7 +160,7 @@ public class ExamJITSIProctoringServiceTest {
|
|||
examSessionService,
|
||||
cryptor,
|
||||
clientHttpRequestFactoryService,
|
||||
jsonMapper);
|
||||
jsonMapper, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -556,7 +556,6 @@ CREATE TABLE IF NOT EXISTS `seb_client_configuration` (
|
|||
-- -----------------------------------------------------
|
||||
-- Table `webservice_server_info`
|
||||
-- -----------------------------------------------------
|
||||
DROP TABLE IF EXISTS `webservice_server_info` ;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `webservice_server_info` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
|
|
Loading…
Reference in a new issue