SEBSERV-62 controller implementation and prepare for testing
This commit is contained in:
parent
44688429bb
commit
b314ca651f
42 changed files with 1681 additions and 183 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -60,3 +60,4 @@ pom.xml.tag
|
||||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||||
hs_err_pid*
|
hs_err_pid*
|
||||||
/log-byDay_IS_UNDEFINED.txt
|
/log-byDay_IS_UNDEFINED.txt
|
||||||
|
/log/
|
||||||
|
|
|
@ -104,7 +104,9 @@ public final class API {
|
||||||
|
|
||||||
public static final String EXAM_API_PARAM_EXAM_ID = "examId";
|
public static final String EXAM_API_PARAM_EXAM_ID = "examId";
|
||||||
|
|
||||||
public static final String EXAM_API_SEB_CONNECTION_TOKEN = "seb-connection-token";
|
public static final String EXAM_API_SEB_CONNECTION_TOKEN = "SEBConnectionToken";
|
||||||
|
|
||||||
|
public static final String EXAM_API_USER_SESSION_ID = "seb_user_session_id";
|
||||||
|
|
||||||
public static final String EXAM_API_HANDSHAKE_ENDPOINT = "/handshake";
|
public static final String EXAM_API_HANDSHAKE_ENDPOINT = "/handshake";
|
||||||
|
|
||||||
|
@ -112,6 +114,10 @@ public final class API {
|
||||||
|
|
||||||
public static final String EXAM_API_PING_ENDPOINT = "/sebping";
|
public static final String EXAM_API_PING_ENDPOINT = "/sebping";
|
||||||
|
|
||||||
|
public static final String EXAM_API_PING_TIMESTAMP = "timestamp";
|
||||||
|
|
||||||
|
public static final String EXAM_API_PING_NUMBER = "ping-number";
|
||||||
|
|
||||||
public static final String EXAM_API_EVENT_ENDPOINT = "/seblog";
|
public static final String EXAM_API_EVENT_ENDPOINT = "/seblog";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,8 @@ package ch.ethz.seb.sebserver.gbl.model.session;
|
||||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
||||||
|
|
||||||
public final class RunningExam {
|
public final class RunningExam {
|
||||||
|
|
||||||
@JsonProperty("examId")
|
@JsonProperty("examId")
|
||||||
|
@ -31,6 +33,12 @@ public final class RunningExam {
|
||||||
this.url = url;
|
this.url = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RunningExam(final Exam exam) {
|
||||||
|
this.examId = exam.getModelId();
|
||||||
|
this.name = exam.name;
|
||||||
|
this.url = exam.startURL;
|
||||||
|
}
|
||||||
|
|
||||||
public String getExamId() {
|
public String getExamId() {
|
||||||
return this.examId;
|
return this.examId;
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ public final class Utils {
|
||||||
return Collectors.collectingAndThen(
|
return Collectors.collectingAndThen(
|
||||||
Collectors.toList(),
|
Collectors.toList(),
|
||||||
list -> {
|
list -> {
|
||||||
if (list == null) {
|
if (list == null || list.size() == 0) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"Expected one elements in the given list but is empty");
|
"Expected one elements in the given list but is empty");
|
||||||
}
|
}
|
||||||
|
@ -335,4 +335,8 @@ public final class Utils {
|
||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String toSQLWildcard(final String text) {
|
||||||
|
return (text == null) ? null : Constants.PERCENTAGE + text + Constants.PERCENTAGE;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,11 +55,11 @@ public interface ClientCredentialService {
|
||||||
return encryptClientCredentials(clientIdPlaintext, secretPlaintext, null);
|
return encryptClientCredentials(clientIdPlaintext, secretPlaintext, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Use this to get a decrypted plain text clientId form given ClientCredentials
|
// /** Use this to get a decrypted plain text clientId form given ClientCredentials
|
||||||
*
|
// *
|
||||||
* @param credentials ClientCredentials containing the clientId to decrypt
|
// * @param credentials ClientCredentials containing the clientId to decrypt
|
||||||
* @return decrypted plain text clientId */
|
// * @return decrypted plain text clientId */
|
||||||
CharSequence getPlainClientId(ClientCredentials credentials);
|
// CharSequence getPlainClientId(ClientCredentials credentials);
|
||||||
|
|
||||||
/** Use this to get a decrypted plain text secret form given ClientCredentials
|
/** Use this to get a decrypted plain text secret form given ClientCredentials
|
||||||
*
|
*
|
||||||
|
|
|
@ -64,9 +64,7 @@ public class ClientCredentialServiceImpl implements ClientCredentialService {
|
||||||
.getRequiredProperty(SEBSERVER_WEBSERVICE_INTERNAL_SECRET_KEY);
|
.getRequiredProperty(SEBSERVER_WEBSERVICE_INTERNAL_SECRET_KEY);
|
||||||
|
|
||||||
return new ClientCredentials(
|
return new ClientCredentials(
|
||||||
(clientIdPlaintext != null)
|
clientIdPlaintext,
|
||||||
? encrypt(clientIdPlaintext, secret).toString()
|
|
||||||
: null,
|
|
||||||
(secretPlaintext != null)
|
(secretPlaintext != null)
|
||||||
? encrypt(secretPlaintext, secret).toString()
|
? encrypt(secretPlaintext, secret).toString()
|
||||||
: null,
|
: null,
|
||||||
|
@ -75,17 +73,10 @@ public class ClientCredentialServiceImpl implements ClientCredentialService {
|
||||||
: null);
|
: null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
// @Override
|
||||||
public CharSequence getPlainClientId(final ClientCredentials credentials) {
|
// public CharSequence getPlainClientId(final ClientCredentials credentials) {
|
||||||
if (credentials == null || !credentials.hasClientId()) {
|
// return credentials.clientId;
|
||||||
return null;
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
final CharSequence secret = this.environment
|
|
||||||
.getRequiredProperty(SEBSERVER_WEBSERVICE_INTERNAL_SECRET_KEY);
|
|
||||||
|
|
||||||
return this.decrypt(credentials.clientId, secret);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CharSequence getPlainClientSecret(final ClientCredentials credentials) {
|
public CharSequence getPlainClientSecret(final ClientCredentials credentials) {
|
||||||
|
|
|
@ -15,4 +15,6 @@ public interface ClientConnectionDAO extends EntityDAO<ClientConnection, ClientC
|
||||||
|
|
||||||
Result<ClientConnection> byConnectionToken(Long institutionId, String connectionToken);
|
Result<ClientConnection> byConnectionToken(Long institutionId, String connectionToken);
|
||||||
|
|
||||||
|
Result<ClientConnection> byConnectionToken(String connectionToken);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,10 +9,15 @@
|
||||||
package ch.ethz.seb.sebserver.webservice.servicelayer.dao;
|
package ch.ethz.seb.sebserver.webservice.servicelayer.dao;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.ExamConfigurationMap;
|
import ch.ethz.seb.sebserver.gbl.model.exam.ExamConfigurationMap;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionSupportDAO;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionSupportDAO;
|
||||||
|
|
||||||
public interface ExamConfigurationMapDAO extends
|
public interface ExamConfigurationMapDAO extends
|
||||||
EntityDAO<ExamConfigurationMap, ExamConfigurationMap>,
|
EntityDAO<ExamConfigurationMap, ExamConfigurationMap>,
|
||||||
BulkActionSupportDAO<ExamConfigurationMap> {
|
BulkActionSupportDAO<ExamConfigurationMap> {
|
||||||
|
|
||||||
|
public Result<Long> getDefaultConfigurationForExam(Long examId);
|
||||||
|
|
||||||
|
public Result<Long> getUserConfigurationIdForExam(final Long examId, final String userId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ import org.joda.time.DateTimeZone;
|
||||||
import org.springframework.util.LinkedMultiValueMap;
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
import org.springframework.util.MultiValueMap;
|
import org.springframework.util.MultiValueMap;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
|
||||||
import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
|
import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
||||||
|
@ -179,11 +178,7 @@ public class FilterMap extends POSTMapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSQLWildcard(final String name) {
|
public String getSQLWildcard(final String name) {
|
||||||
return toSQLWildcard(this.params.getFirst(name));
|
return Utils.toSQLWildcard(this.params.getFirst(name));
|
||||||
}
|
|
||||||
|
|
||||||
public static String toSQLWildcard(final String text) {
|
|
||||||
return (text == null) ? null : Constants.PERCENTAGE + text + Constants.PERCENTAGE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getClientConnectionExamId() {
|
public Long getClientConnectionExamId() {
|
||||||
|
|
|
@ -18,6 +18,12 @@ public interface SebClientConfigDAO extends
|
||||||
ActivatableEntityDAO<SebClientConfig, SebClientConfig>,
|
ActivatableEntityDAO<SebClientConfig, SebClientConfig>,
|
||||||
BulkActionSupportDAO<SebClientConfig> {
|
BulkActionSupportDAO<SebClientConfig> {
|
||||||
|
|
||||||
|
/** Get a SebClientConfig by specified client identifier
|
||||||
|
*
|
||||||
|
* @param clientId the client identifier
|
||||||
|
* @return Result refer to the SebClientConfig for client or refer to an error if happened */
|
||||||
|
Result<SebClientConfig> byClientId(String clientId);
|
||||||
|
|
||||||
/** Get the configured ClientCredentials for a given SebClientConfig.
|
/** Get the configured ClientCredentials for a given SebClientConfig.
|
||||||
* The ClientCredentials are still encoded as they are on DB storage
|
* The ClientCredentials are still encoded as they are on DB storage
|
||||||
*
|
*
|
||||||
|
|
|
@ -120,7 +120,7 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
|
||||||
data.institutionId,
|
data.institutionId,
|
||||||
data.examId,
|
data.examId,
|
||||||
ConnectionStatus.CONNECTION_REQUESTED.name(),
|
ConnectionStatus.CONNECTION_REQUESTED.name(),
|
||||||
null,
|
data.connectionToken,
|
||||||
null,
|
null,
|
||||||
data.clientAddress,
|
data.clientAddress,
|
||||||
data.virtualClientAddress);
|
data.virtualClientAddress);
|
||||||
|
@ -214,6 +214,31 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
|
||||||
.flatMap(ClientConnectionDAOImpl::toDomainModel);
|
.flatMap(ClientConnectionDAOImpl::toDomainModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<ClientConnection> byConnectionToken(final String connectionToken) {
|
||||||
|
return Result.tryCatch(() -> {
|
||||||
|
final List<ClientConnectionRecord> list = this.clientConnectionRecordMapper
|
||||||
|
.selectByExample()
|
||||||
|
.where(
|
||||||
|
ClientConnectionRecordDynamicSqlSupport.connectionToken,
|
||||||
|
SqlBuilder.isEqualTo(connectionToken))
|
||||||
|
|
||||||
|
.build()
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
if (list.isEmpty()) {
|
||||||
|
throw new ResourceNotFoundException(EntityType.CLIENT_CONNECTION, "connectionToken");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list.size() > 1) {
|
||||||
|
throw new IllegalStateException("Only one ClientConnection expected but there are: " + list.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
return list.get(0);
|
||||||
|
})
|
||||||
|
.flatMap(ClientConnectionDAOImpl::toDomainModel);
|
||||||
|
}
|
||||||
|
|
||||||
private Result<ClientConnectionRecord> recordById(final Long id) {
|
private Result<ClientConnectionRecord> recordById(final Long id) {
|
||||||
return Result.tryCatch(() -> {
|
return Result.tryCatch(() -> {
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ import ch.ethz.seb.sebserver.gbl.model.exam.ExamConfigurationMap;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationStatus;
|
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationStatus;
|
||||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ConfigurationNodeRecordMapper;
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ConfigurationNodeRecordMapper;
|
||||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ExamConfigurationMapRecordDynamicSqlSupport;
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ExamConfigurationMapRecordDynamicSqlSupport;
|
||||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ExamConfigurationMapRecordMapper;
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ExamConfigurationMapRecordMapper;
|
||||||
|
@ -125,6 +126,39 @@ public class ExamConfigurationMapDAOImpl implements ExamConfigurationMapDAO {
|
||||||
.collect(Collectors.toList()));
|
.collect(Collectors.toList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public Result<Long> getDefaultConfigurationForExam(final Long examId) {
|
||||||
|
return Result.tryCatch(() -> this.examConfigurationMapRecordMapper
|
||||||
|
.selectIdsByExample()
|
||||||
|
.where(
|
||||||
|
ExamConfigurationMapRecordDynamicSqlSupport.examId,
|
||||||
|
SqlBuilder.isEqualTo(examId))
|
||||||
|
.and(
|
||||||
|
ExamConfigurationMapRecordDynamicSqlSupport.userNames,
|
||||||
|
SqlBuilder.isNull())
|
||||||
|
.build()
|
||||||
|
.execute()
|
||||||
|
.stream()
|
||||||
|
.collect(Utils.toSingleton()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<Long> getUserConfigurationIdForExam(final Long examId, final String userId) {
|
||||||
|
return Result.tryCatch(() -> this.examConfigurationMapRecordMapper
|
||||||
|
.selectIdsByExample()
|
||||||
|
.where(
|
||||||
|
ExamConfigurationMapRecordDynamicSqlSupport.examId,
|
||||||
|
SqlBuilder.isEqualTo(examId))
|
||||||
|
.and(
|
||||||
|
ExamConfigurationMapRecordDynamicSqlSupport.userNames,
|
||||||
|
SqlBuilder.isLike(Utils.toSQLWildcard(userId)))
|
||||||
|
.build()
|
||||||
|
.execute()
|
||||||
|
.stream()
|
||||||
|
.collect(Utils.toSingleton()));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public Result<ExamConfigurationMap> createNew(final ExamConfigurationMap data) {
|
public Result<ExamConfigurationMap> createNew(final ExamConfigurationMap data) {
|
||||||
|
|
|
@ -318,15 +318,13 @@ public class LmsSetupDAOImpl implements LmsSetupDAO {
|
||||||
record.getLmsClientsecret(),
|
record.getLmsClientsecret(),
|
||||||
record.getLmsRestApiToken());
|
record.getLmsRestApiToken());
|
||||||
|
|
||||||
final CharSequence plainClientId = this.clientCredentialService.getPlainClientId(clientCredentials);
|
|
||||||
final CharSequence plainAccessToken = this.clientCredentialService.getPlainAccessToken(clientCredentials);
|
final CharSequence plainAccessToken = this.clientCredentialService.getPlainAccessToken(clientCredentials);
|
||||||
|
|
||||||
return Result.tryCatch(() -> new LmsSetup(
|
return Result.tryCatch(() -> new LmsSetup(
|
||||||
record.getId(),
|
record.getId(),
|
||||||
record.getInstitutionId(),
|
record.getInstitutionId(),
|
||||||
record.getName(),
|
record.getName(),
|
||||||
LmsType.valueOf(record.getLmsType()),
|
LmsType.valueOf(record.getLmsType()),
|
||||||
Utils.toString(plainClientId),
|
Utils.toString(clientCredentials.clientId),
|
||||||
null,
|
null,
|
||||||
record.getLmsUrl(),
|
record.getLmsUrl(),
|
||||||
Utils.toString(plainAccessToken),
|
Utils.toString(plainAccessToken),
|
||||||
|
|
|
@ -35,6 +35,7 @@ import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SebClientConfig;
|
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SebClientConfig;
|
||||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.SebClientConfigRecordDynamicSqlSupport;
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.SebClientConfigRecordDynamicSqlSupport;
|
||||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.SebClientConfigRecordMapper;
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.SebClientConfigRecordMapper;
|
||||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.SebClientConfigRecord;
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.SebClientConfigRecord;
|
||||||
|
@ -131,6 +132,24 @@ public class SebClientConfigDAOImpl implements SebClientConfigDAO {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<SebClientConfig> byClientId(final String clientId) {
|
||||||
|
return Result.tryCatch(() -> {
|
||||||
|
|
||||||
|
return this.sebClientConfigRecordMapper
|
||||||
|
.selectByExample()
|
||||||
|
.where(
|
||||||
|
SebClientConfigRecordDynamicSqlSupport.clientName,
|
||||||
|
isEqualTo(clientId))
|
||||||
|
.build()
|
||||||
|
.execute()
|
||||||
|
.stream()
|
||||||
|
.map(SebClientConfigDAOImpl::toDomainModel)
|
||||||
|
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||||
|
.collect(Utils.toSingleton());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public boolean isActive(final String modelId) {
|
public boolean isActive(final String modelId) {
|
||||||
|
|
|
@ -58,7 +58,7 @@ public class LmsAPIServiceImpl implements LmsAPIService {
|
||||||
final LmsSetupDAO lmsSetupDAO,
|
final LmsSetupDAO lmsSetupDAO,
|
||||||
final ClientCredentialService clientCredentialService,
|
final ClientCredentialService clientCredentialService,
|
||||||
final ClientHttpRequestFactory clientHttpRequestFactory,
|
final ClientHttpRequestFactory clientHttpRequestFactory,
|
||||||
@Value("${sebserver.lms.openedix.api.token.request.paths}") final String alternativeTokenRequestPaths) {
|
@Value("${sebserver.webservice.lms.openedx.api.token.request.paths}") final String alternativeTokenRequestPaths) {
|
||||||
|
|
||||||
this.asyncService = asyncService;
|
this.asyncService = asyncService;
|
||||||
this.lmsSetupDAO = lmsSetupDAO;
|
this.lmsSetupDAO = lmsSetupDAO;
|
||||||
|
|
|
@ -130,7 +130,7 @@ final class MockupLmsAPITemplate implements LmsAPITemplate {
|
||||||
private boolean authenticate() {
|
private boolean authenticate() {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
final CharSequence plainClientId = this.clientCredentialService.getPlainClientId(this.credentials);
|
final CharSequence plainClientId = this.credentials.clientId;
|
||||||
if (plainClientId == null || plainClientId.length() <= 0) {
|
if (plainClientId == null || plainClientId.length() <= 0) {
|
||||||
throw new IllegalAccessException("Wrong client credential");
|
throw new IllegalAccessException("Wrong client credential");
|
||||||
}
|
}
|
||||||
|
|
|
@ -202,7 +202,7 @@ final class OpenEdxLmsAPITemplate implements LmsAPITemplate {
|
||||||
final ClientCredentials credentials,
|
final ClientCredentials credentials,
|
||||||
final String accessTokenRequestPath) {
|
final String accessTokenRequestPath) {
|
||||||
|
|
||||||
final CharSequence plainClientId = this.clientCredentialService.getPlainClientId(credentials);
|
final CharSequence plainClientId = credentials.clientId;
|
||||||
final CharSequence plainClientSecret = this.clientCredentialService.getPlainClientSecret(credentials);
|
final CharSequence plainClientSecret = this.clientCredentialService.getPlainClientSecret(credentials);
|
||||||
|
|
||||||
final ClientCredentialsResourceDetails details = new ClientCredentialsResourceDetails();
|
final ClientCredentialsResourceDetails details = new ClientCredentialsResourceDetails();
|
||||||
|
|
|
@ -73,6 +73,6 @@ public interface SebClientConfigService {
|
||||||
*
|
*
|
||||||
* @param clientId the clientId/clientName
|
* @param clientId the clientId/clientName
|
||||||
* @return encoded clientSecret for that SebClientConfiguration with clientId or null of not existing */
|
* @return encoded clientSecret for that SebClientConfiguration with clientId or null of not existing */
|
||||||
Result<String> getEncodedClientSecret(String clientId);
|
Result<CharSequence> getEncodedClientSecret(String clientId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import java.io.OutputStream;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage.FieldValidationException;
|
import ch.ethz.seb.sebserver.gbl.api.APIMessage.FieldValidationException;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues;
|
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
|
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||||
|
|
||||||
/** The base interface and service for all SEB Exam Configuration related functionality. */
|
/** The base interface and service for all SEB Exam Configuration related functionality. */
|
||||||
public interface SebExamConfigService {
|
public interface SebExamConfigService {
|
||||||
|
@ -31,6 +32,10 @@ public interface SebExamConfigService {
|
||||||
* @throws FieldValidationException on validation exception */
|
* @throws FieldValidationException on validation exception */
|
||||||
void validate(ConfigurationTableValues tableValue) throws FieldValidationException;
|
void validate(ConfigurationTableValues tableValue) throws FieldValidationException;
|
||||||
|
|
||||||
|
Result<Long> getDefaultConfigurationIdForExam(Long examId);
|
||||||
|
|
||||||
|
Result<Long> getUserConfigurationIdForExam(Long examId, String userId);
|
||||||
|
|
||||||
/** Used to export a specified SEB Exam Configuration as plain XML
|
/** Used to export a specified SEB Exam Configuration as plain XML
|
||||||
* This exports the values of the follow-up configuration defined by a given
|
* This exports the values of the follow-up configuration defined by a given
|
||||||
* ConfigurationNode (configurationNodeId)
|
* ConfigurationNode (configurationNodeId)
|
||||||
|
|
|
@ -17,8 +17,6 @@ import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -28,14 +26,10 @@ import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.context.request.RequestAttributes;
|
|
||||||
import org.springframework.web.context.request.RequestContextHolder;
|
|
||||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
|
||||||
import org.springframework.web.util.UriComponentsBuilder;
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.WebSecurityConfig;
|
import ch.ethz.seb.sebserver.WebSecurityConfig;
|
||||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
|
||||||
import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
|
import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SebClientConfig;
|
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SebClientConfig;
|
||||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||||
|
@ -135,46 +129,14 @@ public class SebClientConfigServiceImpl implements SebClientConfigService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result<String> getEncodedClientSecret(final String clientId) {
|
public Result<CharSequence> getEncodedClientSecret(final String clientId) {
|
||||||
return Result.tryCatch(() -> {
|
return this.sebClientConfigDAO.byClientId(clientId)
|
||||||
final Collection<SebClientConfig> clientConfigs = this.sebClientConfigDAO.all(extractInstitution(), true)
|
.flatMap(this::getEncodedSecret);
|
||||||
.getOrThrow();
|
|
||||||
|
|
||||||
final ClientCredentials clientCredentials = findClientCredentialsFor(clientId, clientConfigs);
|
|
||||||
return this.clientPasswordEncoder.encode(
|
|
||||||
this.clientCredentialService.getPlainClientSecret(clientCredentials));
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientCredentials findClientCredentialsFor(final String clientId,
|
private Result<CharSequence> getEncodedSecret(final SebClientConfig clientConfig) {
|
||||||
final Collection<SebClientConfig> clientConfigs) {
|
return this.sebClientConfigDAO.getSebClientCredentials(clientConfig.getModelId())
|
||||||
for (final SebClientConfig config : clientConfigs) {
|
.map(cc -> this.clientPasswordEncoder.encode(this.clientCredentialService.getPlainClientSecret(cc)));
|
||||||
try {
|
|
||||||
final ClientCredentials clientCredentials =
|
|
||||||
this.sebClientConfigDAO.getSebClientCredentials(config.getModelId())
|
|
||||||
.getOrThrow();
|
|
||||||
if (clientId.equals(this.clientCredentialService.getPlainClientId(clientCredentials))) {
|
|
||||||
return clientCredentials;
|
|
||||||
}
|
|
||||||
} catch (final Exception e) {
|
|
||||||
log.error("Unexpected error while trying to fetch client credentials: ", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Long extractInstitution() {
|
|
||||||
try {
|
|
||||||
final RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
|
|
||||||
final HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
|
|
||||||
return Long.parseLong(request.getParameter(API.PARAM_INSTITUTION_ID));
|
|
||||||
} catch (final Exception e) {
|
|
||||||
log.error(
|
|
||||||
"Failed to extract institution from current request. Search client Id over all active client configurations");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -193,8 +155,7 @@ public class SebClientConfigServiceImpl implements SebClientConfigService {
|
||||||
.getConfigPasswortCipher(config.getModelId())
|
.getConfigPasswortCipher(config.getModelId())
|
||||||
.getOrThrow();
|
.getOrThrow();
|
||||||
|
|
||||||
final CharSequence plainClientId = this.clientCredentialService
|
final CharSequence plainClientId = sebClientCredentials.clientId;
|
||||||
.getPlainClientId(sebClientCredentials);
|
|
||||||
final CharSequence plainClientSecret = this.clientCredentialService
|
final CharSequence plainClientSecret = this.clientCredentialService
|
||||||
.getPlainClientSecret(sebClientCredentials);
|
.getPlainClientSecret(sebClientCredentials);
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,9 @@ import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues;
|
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
|
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
|
||||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ConfigurationAttributeDAO;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ConfigurationAttributeDAO;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamConfigurationMapDAO;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ConfigurationValueValidator;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ConfigurationValueValidator;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebExamConfigService;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebExamConfigService;
|
||||||
|
|
||||||
|
@ -38,15 +40,18 @@ public class SebExamConfigServiceImpl implements SebExamConfigService {
|
||||||
|
|
||||||
private final ExamConfigIO examConfigIO;
|
private final ExamConfigIO examConfigIO;
|
||||||
private final ConfigurationAttributeDAO configurationAttributeDAO;
|
private final ConfigurationAttributeDAO configurationAttributeDAO;
|
||||||
|
private final ExamConfigurationMapDAO examConfigurationMapDAO;
|
||||||
private final Collection<ConfigurationValueValidator> validators;
|
private final Collection<ConfigurationValueValidator> validators;
|
||||||
|
|
||||||
protected SebExamConfigServiceImpl(
|
protected SebExamConfigServiceImpl(
|
||||||
final ExamConfigIO examConfigIO,
|
final ExamConfigIO examConfigIO,
|
||||||
final ConfigurationAttributeDAO configurationAttributeDAO,
|
final ConfigurationAttributeDAO configurationAttributeDAO,
|
||||||
|
final ExamConfigurationMapDAO examConfigurationMapDAO,
|
||||||
final Collection<ConfigurationValueValidator> validators) {
|
final Collection<ConfigurationValueValidator> validators) {
|
||||||
|
|
||||||
this.examConfigIO = examConfigIO;
|
this.examConfigIO = examConfigIO;
|
||||||
this.configurationAttributeDAO = configurationAttributeDAO;
|
this.configurationAttributeDAO = configurationAttributeDAO;
|
||||||
|
this.examConfigurationMapDAO = examConfigurationMapDAO;
|
||||||
this.validators = validators;
|
this.validators = validators;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -122,6 +127,16 @@ public class SebExamConfigServiceImpl implements SebExamConfigService {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<Long> getDefaultConfigurationIdForExam(final Long examId) {
|
||||||
|
return this.examConfigurationMapDAO.getDefaultConfigurationForExam(examId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<Long> getUserConfigurationIdForExam(final Long examId, final String userId) {
|
||||||
|
return this.examConfigurationMapDAO.getUserConfigurationIdForExam(examId, userId);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void exportForExam(final OutputStream out, final Long configExamMappingId) {
|
public void exportForExam(final OutputStream out, final Long configExamMappingId) {
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
|
|
|
@ -12,6 +12,8 @@ import java.util.function.Consumer;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent;
|
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent;
|
||||||
|
|
||||||
|
/** A exam session SEB client event handling strategy implements a certain strategy to
|
||||||
|
* store ClientEvent that are coming in within the specified endpoint in height frequency. */
|
||||||
public interface EventHandlingStrategy extends Consumer<ClientEvent> {
|
public interface EventHandlingStrategy extends Consumer<ClientEvent> {
|
||||||
|
|
||||||
String EVENT_CONSUMER_STRATEGY_CONFIG_PROPERTY_KEY = "sebserver.webservice.api.exam.event-handling-strategy";
|
String EVENT_CONSUMER_STRATEGY_CONFIG_PROPERTY_KEY = "sebserver.webservice.api.exam.event-handling-strategy";
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.webservice.servicelayer.session;
|
package ch.ethz.seb.sebserver.webservice.servicelayer.session;
|
||||||
|
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
||||||
|
@ -38,4 +39,6 @@ public interface ExamSessionService {
|
||||||
* happened. */
|
* happened. */
|
||||||
Result<Collection<Exam>> getRunningExamsForInstitution(Long institutionId);
|
Result<Collection<Exam>> getRunningExamsForInstitution(Long institutionId);
|
||||||
|
|
||||||
|
void streamDefaultExamConfig(Long institutionId, String connectionToken, OutputStream out);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,24 +12,95 @@ import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent;
|
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||||
|
|
||||||
|
/** Service interface defining functionality to handle SEB client connections on running exams. */
|
||||||
public interface SebClientConnectionService {
|
public interface SebClientConnectionService {
|
||||||
|
|
||||||
|
/** If a SEB client connects to the SEB Server the first time for a exam session,
|
||||||
|
* this is used to create a ClientConnection for this connection attempt.
|
||||||
|
* So this starts the SEB Client - SEB Server handshake.
|
||||||
|
* <p>
|
||||||
|
* The examId is not mandatory here an can still be null if at this time
|
||||||
|
* no exam was selected.
|
||||||
|
* <p>
|
||||||
|
* A connection-token to identify the connection is generated and stored within the
|
||||||
|
* returned ClientConnection.
|
||||||
|
*
|
||||||
|
* @param institutionId The institution identifier
|
||||||
|
* @param clientAddress The clients remote IP address
|
||||||
|
* @param examId the exam identifier (can be null)
|
||||||
|
* @return A Result refer to the newly created ClientConnection in state: CONNECTION_REQUESTED, or refer to an error
|
||||||
|
* if happened */
|
||||||
Result<ClientConnection> createClientConnection(
|
Result<ClientConnection> createClientConnection(
|
||||||
Long institutionId,
|
Long institutionId,
|
||||||
String clientAddress,
|
String clientAddress,
|
||||||
Long examId);
|
Long examId);
|
||||||
|
|
||||||
Result<ClientConnection> establishClientConnection(
|
/** This updates an already existing ClientConnection with the given connectionToken.
|
||||||
final Long institutionId,
|
* <p>
|
||||||
|
* If a clientAddress is given and it differs from the existing clientAddress and the there is
|
||||||
|
* an exam mapping to an exam of type VDI, the given clientAddress is used to update the virtualClientAddress
|
||||||
|
* of the ClientConnection.
|
||||||
|
* <p>
|
||||||
|
* If an examId is given this is used to update the ClientConnection
|
||||||
|
* <p>
|
||||||
|
* If a userSessionId is given this is used to update the ClientConnection
|
||||||
|
*
|
||||||
|
* @param connectionToken The connection-token that was given on ClientConnection creation and that identifies the
|
||||||
|
* connection
|
||||||
|
* @param institutionId The institution identifier
|
||||||
|
* @param clientAddress The clients remote IP address
|
||||||
|
* @param examId The exam identifier
|
||||||
|
* @param userSessionId The user session identifier of the users http-session with the LMS
|
||||||
|
* @return A Result refer to the updated ClientConnection instance, or refer to an error if happened */
|
||||||
|
Result<ClientConnection> updateClientConnection(
|
||||||
String connectionToken,
|
String connectionToken,
|
||||||
|
Long institutionId,
|
||||||
|
String clientAddress,
|
||||||
Long examId,
|
Long examId,
|
||||||
final String clientAddress,
|
|
||||||
String userSessionId);
|
String userSessionId);
|
||||||
|
|
||||||
Result<ClientConnection> closeConnection(String connectionToken);
|
/** This is used to establish a already created ClientConnection and set it to sate: ESTABLISHED
|
||||||
|
* The connectionToken identifies the ClientConnection and the given clientAddress must match with
|
||||||
|
* the clientAddress of the already created ClientConnection in state CONNECTION_REQUESTED.
|
||||||
|
* <p>
|
||||||
|
* This may not be the case for VDI exams. In case of VDI exams the different clientAddress is stored
|
||||||
|
* in the virtualClientAddress field of the ClientConnection.
|
||||||
|
* <p>
|
||||||
|
* The examId may also be null here if the examId is already known within the existing ClientConnection.
|
||||||
|
* If not, an error is thrown and send to the calling SEB Client.
|
||||||
|
* <p>
|
||||||
|
* If a userSessionId is provided within the establish request, this is also stored within the ClientConnection.
|
||||||
|
*
|
||||||
|
* @param connectionToken The connection-token that was given on ClientConnection creation and that identifies the
|
||||||
|
* connection
|
||||||
|
* @param institutionId The institution identifier
|
||||||
|
* @param examId The exam identifier (may be null of already known)
|
||||||
|
* @param clientAddress The clients remote IP address
|
||||||
|
* @param userSessionId The user session identifier of the users http-session with the LMS
|
||||||
|
* @return A Result refer to the established ClientConnection instance, or refer to an error if happened */
|
||||||
|
Result<ClientConnection> establishClientConnection(
|
||||||
|
String connectionToken,
|
||||||
|
Long institutionId,
|
||||||
|
Long examId,
|
||||||
|
String clientAddress,
|
||||||
|
String userSessionId);
|
||||||
|
|
||||||
void notifyPing(Long connectionId, long timestamp, int pingNumber);
|
/** This is used to regular close an established ClientConnection from SEB Client side.
|
||||||
|
* <p>
|
||||||
|
* This will save the existing established ClientConnection in new CLOSED state and flush all caches.
|
||||||
|
*
|
||||||
|
* @param connectionToken The connection-token that was given on ClientConnection creation and that identifies the
|
||||||
|
* connection
|
||||||
|
* @param institutionId institution identifier
|
||||||
|
* @param clientAddress The clients remote IP address
|
||||||
|
* @return A Result refer to the closed ClientConnection instance, or refer to an error if happened */
|
||||||
|
Result<ClientConnection> closeConnection(
|
||||||
|
String connectionToken,
|
||||||
|
Long institutionId,
|
||||||
|
String clientAddress);
|
||||||
|
|
||||||
void notifyClientEvent(final ClientEvent event, Long connectionId);
|
void notifyPing(String connectionToken, long timestamp, int pingNumber);
|
||||||
|
|
||||||
|
void notifyClientEvent(String connectionToken, final ClientEvent event);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ public class ClientIndicatorFactory {
|
||||||
public ClientIndicatorFactory(
|
public ClientIndicatorFactory(
|
||||||
final ApplicationContext applicationContext,
|
final ApplicationContext applicationContext,
|
||||||
final IndicatorDAO indicatorDAO,
|
final IndicatorDAO indicatorDAO,
|
||||||
@Value("${sebserver.indicator.caching}") final boolean enableCaching) {
|
@Value("${sebserver.webservice.api.exam.enable-indicator-cache:true}") final boolean enableCaching) {
|
||||||
|
|
||||||
this.applicationContext = applicationContext;
|
this.applicationContext = applicationContext;
|
||||||
this.indicatorDAO = indicatorDAO;
|
this.indicatorDAO = indicatorDAO;
|
||||||
|
@ -60,9 +60,15 @@ public class ClientIndicatorFactory {
|
||||||
|
|
||||||
for (final Indicator indicatorDef : examIndicators) {
|
for (final Indicator indicatorDef : examIndicators) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
final ClientIndicator indicator = this.applicationContext
|
final ClientIndicator indicator = this.applicationContext
|
||||||
.getBean(indicatorDef.type.name(), ClientIndicator.class);
|
.getBean(indicatorDef.type.name(), ClientIndicator.class);
|
||||||
indicator.init(indicatorDef, clientConnection.id, this.enableCaching);
|
|
||||||
|
indicator.init(
|
||||||
|
indicatorDef,
|
||||||
|
clientConnection.id,
|
||||||
|
this.enableCaching);
|
||||||
|
|
||||||
result.add(indicator);
|
result.add(indicator);
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
log.warn("No Indicator with type: {} found as registered bean. Ignore this one.", indicatorDef.type,
|
log.warn("No Indicator with type: {} found as registered bean. Ignore this one.", indicatorDef.type,
|
||||||
|
|
|
@ -8,6 +8,13 @@
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl;
|
package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PipedInputStream;
|
||||||
|
import java.io.PipedOutputStream;
|
||||||
|
|
||||||
|
import org.apache.tomcat.util.http.fileupload.IOUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.cache.annotation.CacheEvict;
|
import org.springframework.cache.annotation.CacheEvict;
|
||||||
|
@ -17,6 +24,7 @@ import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
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.session.ClientConnection;
|
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.profile.WebServiceProfile;
|
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ClientConnectionDAO;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ClientConnectionDAO;
|
||||||
|
@ -98,25 +106,34 @@ public class ExamSessionCacheService {
|
||||||
|
|
||||||
@Cacheable(
|
@Cacheable(
|
||||||
cacheNames = CACHE_NAME_ACTIVE_CLIENT_CONNECTION,
|
cacheNames = CACHE_NAME_ACTIVE_CLIENT_CONNECTION,
|
||||||
key = "#connectionId",
|
key = "#connectionToken",
|
||||||
unless = "#result == null")
|
unless = "#result == null")
|
||||||
ClientConnectionDataInternal getActiveClientConnection(final Long connectionId) {
|
ClientConnectionDataInternal getActiveClientConnection(final String connectionToken) {
|
||||||
|
|
||||||
if (log.isDebugEnabled()) {
|
if (log.isDebugEnabled()) {
|
||||||
log.debug("Verify ClientConnection for running exam for caching by id: ", connectionId);
|
log.debug("Verify ClientConnection for running exam for caching by connectionToken: ", connectionToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
final Result<ClientConnection> byPK = this.clientConnectionDAO.byPK(connectionId);
|
final Result<ClientConnection> byPK = this.clientConnectionDAO
|
||||||
|
.byConnectionToken(connectionToken);
|
||||||
|
|
||||||
if (byPK.hasError()) {
|
if (byPK.hasError()) {
|
||||||
log.error("Failed to find/load ClientConnection with id {}", connectionId, byPK.getError());
|
log.error("Failed to find/load ClientConnection with connectionToken {}", connectionToken, byPK.getError());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ClientConnection clientConnection = byPK.get();
|
final ClientConnection clientConnection = byPK.get();
|
||||||
|
|
||||||
|
// verify connection is established
|
||||||
|
if (clientConnection.status != ConnectionStatus.ESTABLISHED) {
|
||||||
|
log.error("Illegal state: ClientConnection is not in expected state; ESTABLISHED. ClientConnection: ",
|
||||||
|
clientConnection);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// verify exam is running
|
// verify exam is running
|
||||||
if (getRunningExam(clientConnection.examId) == null) {
|
if (getRunningExam(clientConnection.examId) == null) {
|
||||||
log.error("Exam for ClientConnection with id { is not currently running}", connectionId);
|
log.error("Exam for ClientConnection with id { is not currently running}", clientConnection.id);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,10 +144,10 @@ public class ExamSessionCacheService {
|
||||||
|
|
||||||
@CacheEvict(
|
@CacheEvict(
|
||||||
cacheNames = CACHE_NAME_ACTIVE_CLIENT_CONNECTION,
|
cacheNames = CACHE_NAME_ACTIVE_CLIENT_CONNECTION,
|
||||||
key = "#connectionId")
|
key = "#connectionToken")
|
||||||
void evictClientConnection(final Long connectionId) {
|
void evictClientConnection(final String connectionToken) {
|
||||||
if (log.isDebugEnabled()) {
|
if (log.isDebugEnabled()) {
|
||||||
log.debug("Eviction of ClientConnectionData from cache: {}", connectionId);
|
log.debug("Eviction of ClientConnectionData from cache: {}", connectionToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,8 +156,27 @@ public class ExamSessionCacheService {
|
||||||
key = "#examId",
|
key = "#examId",
|
||||||
unless = "#result == null")
|
unless = "#result == null")
|
||||||
InMemorySebConfig getDefaultSebConfigForExam(final Long examId) {
|
InMemorySebConfig getDefaultSebConfigForExam(final Long examId) {
|
||||||
// TODO
|
final Exam runningExam = this.getRunningExam(examId);
|
||||||
return null;
|
final PipedOutputStream pipOut = new PipedOutputStream();
|
||||||
|
try {
|
||||||
|
final Long configId = this.sebExamConfigService
|
||||||
|
.getDefaultConfigurationIdForExam(runningExam.id)
|
||||||
|
.getOrThrow();
|
||||||
|
|
||||||
|
// TODO add header, zip and encrypt if needed
|
||||||
|
|
||||||
|
final BufferedInputStream in = new BufferedInputStream(new PipedInputStream(pipOut));
|
||||||
|
this.sebExamConfigService.exportPlainXML(pipOut, runningExam.institutionId, configId);
|
||||||
|
|
||||||
|
final ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
|
||||||
|
IOUtils.copyLarge(in, byteOut);
|
||||||
|
|
||||||
|
return new InMemorySebConfig(configId, runningExam.id, byteOut.toByteArray());
|
||||||
|
|
||||||
|
} catch (final IOException e) {
|
||||||
|
log.error("Unexpected error while getting default exam configuration for running exam; {}", runningExam, e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@CacheEvict(
|
@CacheEvict(
|
||||||
|
|
|
@ -8,35 +8,46 @@
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl;
|
package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
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.session.ClientConnection;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection.ConnectionStatus;
|
||||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ClientConnectionDAO;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamDAO;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamDAO;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamSessionService;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamSessionService;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.SebClientConnectionService;
|
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
@Service
|
@Service
|
||||||
@WebServiceProfile
|
@WebServiceProfile
|
||||||
public class ExamSessionServiceImpl implements ExamSessionService {
|
public class ExamSessionServiceImpl implements ExamSessionService {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(ExamSessionServiceImpl.class);
|
||||||
|
|
||||||
|
private final ClientConnectionDAO clientConnectionDAO;
|
||||||
private final ExamSessionCacheService examSessionCacheService;
|
private final ExamSessionCacheService examSessionCacheService;
|
||||||
private final ExamDAO examDAO;
|
private final ExamDAO examDAO;
|
||||||
|
|
||||||
protected ExamSessionServiceImpl(
|
protected ExamSessionServiceImpl(
|
||||||
final ExamSessionCacheService examSessionCacheService,
|
final ExamSessionCacheService examSessionCacheService,
|
||||||
final ExamDAO examDAO,
|
final ExamDAO examDAO,
|
||||||
final SebClientConnectionService sebClientConnectionService) {
|
final ClientConnectionDAO clientConnectionDAO) {
|
||||||
|
|
||||||
this.examSessionCacheService = examSessionCacheService;
|
this.examSessionCacheService = examSessionCacheService;
|
||||||
this.examDAO = examDAO;
|
this.examDAO = examDAO;
|
||||||
|
this.clientConnectionDAO = clientConnectionDAO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -47,13 +58,24 @@ public class ExamSessionServiceImpl implements ExamSessionService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result<Exam> getRunningExam(final Long examId) {
|
public Result<Exam> getRunningExam(final Long examId) {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Running exam request for exam {}", examId);
|
||||||
|
}
|
||||||
|
|
||||||
final Exam exam = this.examSessionCacheService.getRunningExam(examId);
|
final Exam exam = this.examSessionCacheService.getRunningExam(examId);
|
||||||
if (this.examSessionCacheService.isRunning(exam)) {
|
if (this.examSessionCacheService.isRunning(exam)) {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Exam {} is running and cached", examId);
|
||||||
|
}
|
||||||
|
|
||||||
return Result.of(exam);
|
return Result.of(exam);
|
||||||
} else {
|
} else {
|
||||||
if (exam != null) {
|
if (exam != null) {
|
||||||
this.examSessionCacheService.evict(exam);
|
this.examSessionCacheService.evict(exam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.warn("Exam {} is not currently running", examId);
|
||||||
|
|
||||||
return Result.ofError(new NoSuchElementException(
|
return Result.ofError(new NoSuchElementException(
|
||||||
"No currenlty running exam found for id: " + examId));
|
"No currenlty running exam found for id: " + examId));
|
||||||
}
|
}
|
||||||
|
@ -68,4 +90,55 @@ public class ExamSessionServiceImpl implements ExamSessionService {
|
||||||
.collect(Collectors.toList()));
|
.collect(Collectors.toList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void streamDefaultExamConfig(
|
||||||
|
final Long institutionId,
|
||||||
|
final String connectionToken,
|
||||||
|
final OutputStream out) {
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("SEB exam configuration download request, connectionToken: {}", connectionToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
final ClientConnection connection = this.clientConnectionDAO
|
||||||
|
.byConnectionToken(institutionId, connectionToken)
|
||||||
|
.getOrThrow();
|
||||||
|
|
||||||
|
if (connection == null || connection.status != ConnectionStatus.ESTABLISHED) {
|
||||||
|
log.warn("SEB exam configuration download request, no active ClientConnection found for token: {}",
|
||||||
|
connectionToken);
|
||||||
|
throw new AccessDeniedException("Illegal connection token. No active ClientConnection found for token");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("SEB exam configuration download request: {}", connection);
|
||||||
|
log.debug("Trying to get exam form InMemorySebConfig");
|
||||||
|
}
|
||||||
|
|
||||||
|
final InMemorySebConfig sebConfigForExam = this.examSessionCacheService
|
||||||
|
.getDefaultSebConfigForExam(connection.examId);
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
if (sebConfigForExam == null) {
|
||||||
|
log.debug("Failed to get and cache InMemorySebConfig for connection: {}", connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("SEB exam configuration download request, start writing SEB exam configuration");
|
||||||
|
}
|
||||||
|
|
||||||
|
out.write(sebConfigForExam.getData());
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("SEB exam configuration download request, finished writing SEB exam configuration");
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (final IOException e) {
|
||||||
|
log.error("SEB exam configuration download request, failed to write SEB exam configuration: ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,10 +13,15 @@ import java.util.UUID;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.exam.Exam.ExamType;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
|
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.ClientEvent;
|
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||||
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.session.EventHandlingStrategy;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.session.EventHandlingStrategy;
|
||||||
|
@ -24,6 +29,9 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamSessionService;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.SebClientConnectionService;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.session.SebClientConnectionService;
|
||||||
import io.micrometer.core.instrument.util.StringUtils;
|
import io.micrometer.core.instrument.util.StringUtils;
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
@Service
|
||||||
|
@WebServiceProfile
|
||||||
public class SebClientConnectionServiceImpl implements SebClientConnectionService {
|
public class SebClientConnectionServiceImpl implements SebClientConnectionService {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(SebClientConnectionServiceImpl.class);
|
private static final Logger log = LoggerFactory.getLogger(SebClientConnectionServiceImpl.class);
|
||||||
|
@ -65,15 +73,16 @@ public class SebClientConnectionServiceImpl implements SebClientConnectionServic
|
||||||
return Result.tryCatch(() -> {
|
return Result.tryCatch(() -> {
|
||||||
|
|
||||||
if (log.isDebugEnabled()) {
|
if (log.isDebugEnabled()) {
|
||||||
log.debug("SEB client connection attempt, create ClientConnection for instituion {} and exam: {}",
|
log.debug("SEB client connection attempt, create ClientConnection for "
|
||||||
|
+ "instituion {} "
|
||||||
|
+ "exam: {} "
|
||||||
|
+ "client address: {}",
|
||||||
institutionId,
|
institutionId,
|
||||||
examId);
|
examId,
|
||||||
|
clientAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Integrity check: in case examId is provided is the specified exam running?
|
checkExamRunning(examId);
|
||||||
if (examId != null && !this.examSessionService.isExamRunning(examId)) {
|
|
||||||
examNotRunningException(examId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create ClientConnection in status CONNECTION_REQUESTED for further processing
|
// Create ClientConnection in status CONNECTION_REQUESTED for further processing
|
||||||
final String connectionToken = createToken();
|
final String connectionToken = createToken();
|
||||||
|
@ -97,9 +106,69 @@ public class SebClientConnectionServiceImpl implements SebClientConnectionServic
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result<ClientConnection> establishClientConnection(
|
public Result<ClientConnection> updateClientConnection(
|
||||||
final Long institutionId,
|
|
||||||
final String connectionToken,
|
final String connectionToken,
|
||||||
|
final Long institutionId,
|
||||||
|
final String clientAddress,
|
||||||
|
final Long examId,
|
||||||
|
final String userSessionId) {
|
||||||
|
|
||||||
|
return Result.tryCatch(() -> {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug(
|
||||||
|
"SEB client connection, update ClientConnection for "
|
||||||
|
+ "connectionToken {} "
|
||||||
|
+ "institutionId"
|
||||||
|
+ "exam: {} "
|
||||||
|
+ "client address: {} "
|
||||||
|
+ "userSessionId: {}",
|
||||||
|
connectionToken,
|
||||||
|
institutionId,
|
||||||
|
examId,
|
||||||
|
clientAddress,
|
||||||
|
userSessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
checkExamRunning(examId);
|
||||||
|
|
||||||
|
final ClientConnection clientConnection = getClientConnection(
|
||||||
|
connectionToken,
|
||||||
|
institutionId);
|
||||||
|
|
||||||
|
checkInstitutionalIntegrity(
|
||||||
|
institutionId,
|
||||||
|
clientConnection);
|
||||||
|
|
||||||
|
final String virtualClientAddress = getVirtualClientAddress(
|
||||||
|
(examId != null) ? examId : clientConnection.examId,
|
||||||
|
clientAddress,
|
||||||
|
clientConnection.clientAddress);
|
||||||
|
|
||||||
|
final ClientConnection updatedClientConnection = this.clientConnectionDAO
|
||||||
|
.save(new ClientConnection(
|
||||||
|
clientConnection.id,
|
||||||
|
null,
|
||||||
|
examId,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
userSessionId,
|
||||||
|
null,
|
||||||
|
virtualClientAddress))
|
||||||
|
.getOrThrow();
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("SEB client connection, successfully updated ClientConnection: {}",
|
||||||
|
updatedClientConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
return updatedClientConnection;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<ClientConnection> establishClientConnection(
|
||||||
|
final String connectionToken,
|
||||||
|
final Long institutionId,
|
||||||
final Long examId,
|
final Long examId,
|
||||||
final String clientAddress,
|
final String clientAddress,
|
||||||
final String userSessionId) {
|
final String userSessionId) {
|
||||||
|
@ -108,38 +177,30 @@ public class SebClientConnectionServiceImpl implements SebClientConnectionServic
|
||||||
|
|
||||||
if (log.isDebugEnabled()) {
|
if (log.isDebugEnabled()) {
|
||||||
log.debug(
|
log.debug(
|
||||||
"SEB client connection, establish ClientConnection for instituion {} and exam: {} and userSessionId: {}",
|
"SEB client connection, establish ClientConnection for "
|
||||||
|
+ "connectionToken {} "
|
||||||
|
+ "institutionId"
|
||||||
|
+ "exam: {} "
|
||||||
|
+ "client address: {} "
|
||||||
|
+ "userSessionId: {}",
|
||||||
|
connectionToken,
|
||||||
institutionId,
|
institutionId,
|
||||||
examId,
|
examId,
|
||||||
|
clientAddress,
|
||||||
userSessionId);
|
userSessionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Integrity check: is the specified exam running?
|
checkExamRunning(examId);
|
||||||
if (!this.examSessionService.isExamRunning(examId)) {
|
|
||||||
examNotRunningException(examId);
|
|
||||||
}
|
|
||||||
|
|
||||||
final ClientConnection clientConnection = this.clientConnectionDAO
|
final ClientConnection clientConnection = getClientConnection(
|
||||||
.byConnectionToken(institutionId, connectionToken)
|
connectionToken,
|
||||||
.get(t -> {
|
institutionId);
|
||||||
// TODO: This indicates some irregularity on SEB-Client connection attempt.
|
|
||||||
// Later we should handle this more accurately, and maybe indicate this to the monitoring board
|
|
||||||
// For example; check if there is already a connection for the userIdentifier and
|
|
||||||
// if true in which state it is.
|
|
||||||
log.debug("Unable to connect SEB-Client {} to exam {}",
|
|
||||||
clientAddress,
|
|
||||||
this.examSessionService.getRunningExam(examId).map(exam -> exam.name));
|
|
||||||
throw new IllegalStateException("Unable to connect SEB-Client to exam");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Integrity checks:
|
checkInstitutionalIntegrity(
|
||||||
if (!institutionId.equals(clientConnection.institutionId)) {
|
institutionId,
|
||||||
log.error("Instituion integrity violation with institution: {} on clientConnection: {}",
|
clientConnection);
|
||||||
institutionId,
|
|
||||||
clientConnection);
|
|
||||||
throw new IllegalAccessError("Instituion integrity violation");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Exam integrity
|
||||||
if (clientConnection.examId != null && !examId.equals(clientConnection.examId)) {
|
if (clientConnection.examId != null && !examId.equals(clientConnection.examId)) {
|
||||||
log.error("Exam integrity violation with examId: {} on clientConnection: {}",
|
log.error("Exam integrity violation with examId: {} on clientConnection: {}",
|
||||||
examId,
|
examId,
|
||||||
|
@ -147,30 +208,111 @@ public class SebClientConnectionServiceImpl implements SebClientConnectionServic
|
||||||
throw new IllegalAccessError("Exam integrity violation");
|
throw new IllegalAccessError("Exam integrity violation");
|
||||||
}
|
}
|
||||||
|
|
||||||
final ClientConnection updatedClientConnection = this.clientConnectionDAO.save(new ClientConnection(
|
final String virtualClientAddress = getVirtualClientAddress(
|
||||||
|
(examId != null) ? examId : clientConnection.examId,
|
||||||
|
clientAddress,
|
||||||
|
clientConnection.clientAddress);
|
||||||
|
|
||||||
|
final ClientConnection establishedClientConnection = new ClientConnection(
|
||||||
clientConnection.id,
|
clientConnection.id,
|
||||||
clientConnection.institutionId,
|
null,
|
||||||
clientConnection.examId,
|
examId,
|
||||||
ClientConnection.ConnectionStatus.ESTABLISHED,
|
ClientConnection.ConnectionStatus.ESTABLISHED,
|
||||||
null,
|
null,
|
||||||
userSessionId,
|
userSessionId,
|
||||||
null,
|
null,
|
||||||
null)).getOrThrow();
|
virtualClientAddress);
|
||||||
|
|
||||||
|
// ClientConnection integrity
|
||||||
|
if (establishedClientConnection.institutionId == null ||
|
||||||
|
establishedClientConnection.examId == null ||
|
||||||
|
establishedClientConnection.clientAddress == null ||
|
||||||
|
establishedClientConnection.connectionToken == null) {
|
||||||
|
|
||||||
|
log.error("ClientConnection integrity violation: {}", establishedClientConnection);
|
||||||
|
throw new IllegalStateException("ClientConnection integrity violation: " + establishedClientConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
final ClientConnection updatedClientConnection = this.clientConnectionDAO
|
||||||
|
.save(establishedClientConnection)
|
||||||
|
.getOrThrow();
|
||||||
|
|
||||||
|
if (updatedClientConnection.status == ConnectionStatus.ESTABLISHED) {
|
||||||
|
// load into cache...
|
||||||
|
final ClientConnectionDataInternal activeClientConnection = this.examSessionCacheService
|
||||||
|
.getActiveClientConnection(updatedClientConnection.connectionToken);
|
||||||
|
|
||||||
|
if (activeClientConnection == null) {
|
||||||
|
log.warn("Unable to access and cache ClientConnection");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("ClientConnection: {} successfully established", clientConnection);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("ClientConnection: {} updated", clientConnection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return updatedClientConnection;
|
return updatedClientConnection;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result<ClientConnection> closeConnection(final String connectionToken) {
|
public Result<ClientConnection> closeConnection(
|
||||||
// TODO Auto-generated method stub
|
final String connectionToken,
|
||||||
return null;
|
final Long institutionId,
|
||||||
|
final String clientAddress) {
|
||||||
|
|
||||||
|
return Result.tryCatch(() -> {
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("SEB client connection: regular close attempt for "
|
||||||
|
+ "instituion {} "
|
||||||
|
+ "client address: {} "
|
||||||
|
+ "connectionToken {} ",
|
||||||
|
institutionId,
|
||||||
|
clientAddress,
|
||||||
|
connectionToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
final ClientConnection clientConnection = this.clientConnectionDAO
|
||||||
|
.byConnectionToken(institutionId, connectionToken)
|
||||||
|
.getOrThrow();
|
||||||
|
|
||||||
|
// evict ClientConnection from cache
|
||||||
|
this.examSessionCacheService
|
||||||
|
.evictClientConnection(clientConnection.connectionToken);
|
||||||
|
|
||||||
|
final ClientConnection updatedClientConnection = this.clientConnectionDAO.save(new ClientConnection(
|
||||||
|
clientConnection.id,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
ClientConnection.ConnectionStatus.CLOSED,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null)).getOrThrow();
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("SEB client connection: successfully closed ClientConnection: {}",
|
||||||
|
clientConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
return updatedClientConnection;
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void notifyPing(final Long connectionId, final long timestamp, final int pingNumber) {
|
public void notifyPing(
|
||||||
|
final String connectionToken,
|
||||||
|
final long timestamp,
|
||||||
|
final int pingNumber) {
|
||||||
|
|
||||||
final ClientConnectionDataInternal activeClientConnection =
|
final ClientConnectionDataInternal activeClientConnection =
|
||||||
this.examSessionCacheService.getActiveClientConnection(connectionId);
|
this.examSessionCacheService.getActiveClientConnection(connectionToken);
|
||||||
|
|
||||||
if (activeClientConnection != null) {
|
if (activeClientConnection != null) {
|
||||||
activeClientConnection.pingMappings
|
activeClientConnection.pingMappings
|
||||||
|
@ -180,11 +322,14 @@ public class SebClientConnectionServiceImpl implements SebClientConnectionServic
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void notifyClientEvent(final ClientEvent event, final Long connectionId) {
|
public void notifyClientEvent(
|
||||||
|
final String connectionToken,
|
||||||
|
final ClientEvent event) {
|
||||||
|
|
||||||
this.eventHandlingStrategy.accept(event);
|
this.eventHandlingStrategy.accept(event);
|
||||||
|
|
||||||
final ClientConnectionDataInternal activeClientConnection =
|
final ClientConnectionDataInternal activeClientConnection =
|
||||||
this.examSessionCacheService.getActiveClientConnection(connectionId);
|
this.examSessionCacheService.getActiveClientConnection(connectionToken);
|
||||||
|
|
||||||
if (activeClientConnection != null) {
|
if (activeClientConnection != null) {
|
||||||
activeClientConnection.getindicatorMapping(event.eventType)
|
activeClientConnection.getindicatorMapping(event.eventType)
|
||||||
|
@ -193,6 +338,30 @@ public class SebClientConnectionServiceImpl implements SebClientConnectionServic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkExamRunning(final Long examId) {
|
||||||
|
if (examId != null && !this.examSessionService.isExamRunning(examId)) {
|
||||||
|
examNotRunningException(examId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClientConnection getClientConnection(final String connectionToken, final Long institutionId) {
|
||||||
|
final ClientConnection clientConnection = this.clientConnectionDAO
|
||||||
|
.byConnectionToken(institutionId, connectionToken)
|
||||||
|
.getOrThrow();
|
||||||
|
return clientConnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkInstitutionalIntegrity(final Long institutionId, final ClientConnection clientConnection)
|
||||||
|
throws IllegalAccessError {
|
||||||
|
// Institutional integrity
|
||||||
|
if (!institutionId.equals(clientConnection.institutionId)) {
|
||||||
|
log.error("Instituion integrity violation with institution: {} on clientConnection: {}",
|
||||||
|
institutionId,
|
||||||
|
clientConnection);
|
||||||
|
throw new IllegalAccessError("Instituion integrity violation");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO maybe we need a stronger connectionToken but for now a simple UUID is used
|
// TODO maybe we need a stronger connectionToken but for now a simple UUID is used
|
||||||
private String createToken() {
|
private String createToken() {
|
||||||
return UUID.randomUUID().toString();
|
return UUID.randomUUID().toString();
|
||||||
|
@ -203,4 +372,30 @@ public class SebClientConnectionServiceImpl implements SebClientConnectionServic
|
||||||
throw new IllegalStateException("The exam " + examId + " is not running");
|
throw new IllegalStateException("The exam " + examId + " is not running");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getVirtualClientAddress(
|
||||||
|
final Long examId,
|
||||||
|
final String requestClientAddress,
|
||||||
|
final String existingClientAddress) {
|
||||||
|
|
||||||
|
if (examId == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestClientAddress.equals(existingClientAddress)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isVDI(examId)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return requestClientAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isVDI(final Long examId) {
|
||||||
|
return this.examSessionService.getRunningExam(examId)
|
||||||
|
.getOrThrow()
|
||||||
|
.getType() == ExamType.VDI;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.apache.catalina.filters.RemoteIpFilter;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
@ -94,6 +95,15 @@ public class WebServiceSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
@Value("${sebserver.webservice.api.redirect.unauthorized}")
|
@Value("${sebserver.webservice.api.redirect.unauthorized}")
|
||||||
private String unauthorizedRedirect;
|
private String unauthorizedRedirect;
|
||||||
|
|
||||||
|
/** Used to get real remote IP address by using "X-Forwarded-For" and "X-Forwarded-Proto" header.
|
||||||
|
* https://tomcat.apache.org/tomcat-7.0-doc/api/org/apache/catalina/filters/RemoteIpFilter.html
|
||||||
|
*
|
||||||
|
* @return RemoteIpFilter instance */
|
||||||
|
@Bean
|
||||||
|
public RemoteIpFilter remoteIpFilter() {
|
||||||
|
return new RemoteIpFilter();
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public AccessTokenConverter accessTokenConverter() {
|
public AccessTokenConverter accessTokenConverter() {
|
||||||
final DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter();
|
final DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter();
|
||||||
|
|
|
@ -28,7 +28,6 @@ public class WebServiceUserDetails implements UserDetailsService {
|
||||||
this.userDAO = userDAO;
|
this.userDAO = userDAO;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO do we need an institution id here? otherwise username must be unique thought all institutions!
|
|
||||||
@Override
|
@Override
|
||||||
public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {
|
public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {
|
||||||
return this.userDAO.sebServerUserByUsername(username)
|
return this.userDAO.sebServerUserByUsername(username)
|
||||||
|
|
|
@ -8,15 +8,22 @@
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.webservice.weblayer.api;
|
package ch.ethz.seb.sebserver.webservice.weblayer.api;
|
||||||
|
|
||||||
|
import java.security.Principal;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
@ -24,43 +31,223 @@ import org.springframework.web.bind.annotation.RestController;
|
||||||
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
|
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.session.PingResponse;
|
import ch.ethz.seb.sebserver.gbl.model.session.PingResponse;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.session.RunningExam;
|
import ch.ethz.seb.sebserver.gbl.model.session.RunningExam;
|
||||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamDAO;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.SebClientConfigDAO;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamSessionService;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.session.SebClientConnectionService;
|
||||||
|
|
||||||
@WebServiceProfile
|
@WebServiceProfile
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("${sebserver.webservice.api.exam.endpoint.v1}")
|
@RequestMapping("${sebserver.webservice.api.exam.endpoint.v1}")
|
||||||
public class ExamAPI_V1_Controller {
|
public class ExamAPI_V1_Controller {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(ExamAPI_V1_Controller.class);
|
||||||
|
|
||||||
|
private final ExamDAO examDAO;
|
||||||
|
private final ExamSessionService examSessionService;
|
||||||
|
private final SebClientConnectionService sebClientConnectionService;
|
||||||
|
private final SebClientConfigDAO sebClientConfigDAO;
|
||||||
|
|
||||||
|
protected ExamAPI_V1_Controller(
|
||||||
|
final ExamDAO examDAO,
|
||||||
|
final ExamSessionService examSessionService,
|
||||||
|
final SebClientConnectionService sebClientConnectionService,
|
||||||
|
final SebClientConfigDAO sebClientConfigDAO) {
|
||||||
|
|
||||||
|
this.examDAO = examDAO;
|
||||||
|
this.examSessionService = examSessionService;
|
||||||
|
this.sebClientConnectionService = sebClientConnectionService;
|
||||||
|
this.sebClientConfigDAO = sebClientConfigDAO;
|
||||||
|
}
|
||||||
|
|
||||||
@RequestMapping(
|
@RequestMapping(
|
||||||
path = API.EXAM_API_HANDSHAKE_ENDPOINT,
|
path = API.EXAM_API_HANDSHAKE_ENDPOINT,
|
||||||
method = RequestMethod.GET,
|
method = RequestMethod.GET,
|
||||||
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
|
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
|
||||||
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||||
public Collection<RunningExam> handshake(
|
public Collection<RunningExam> handshakeCreate(
|
||||||
@RequestParam(name = API.PARAM_INSTITUTION_ID, required = true) final Long institutionId,
|
@RequestParam(name = API.PARAM_INSTITUTION_ID, required = false) final Long instIdRequestParam,
|
||||||
|
@RequestParam(name = API.EXAM_API_PARAM_EXAM_ID, required = false) final Long examIdRequestParam,
|
||||||
|
@RequestBody final MultiValueMap<String, String> formParams,
|
||||||
|
final Principal principal,
|
||||||
final HttpServletRequest request,
|
final HttpServletRequest request,
|
||||||
final HttpServletResponse response) {
|
final HttpServletResponse response) {
|
||||||
|
|
||||||
// TODO
|
final POSTMapper mapper = new POSTMapper(formParams);
|
||||||
return Arrays.asList(new RunningExam("1", "testExam", "TODO"));
|
|
||||||
|
final String remoteAddr = request.getRemoteAddr();
|
||||||
|
final Long institutionId = (instIdRequestParam != null)
|
||||||
|
? instIdRequestParam
|
||||||
|
: mapper.getLong(API.PARAM_INSTITUTION_ID);
|
||||||
|
final Long examId = (examIdRequestParam != null)
|
||||||
|
? examIdRequestParam
|
||||||
|
: mapper.getLong(API.EXAM_API_PARAM_EXAM_ID);
|
||||||
|
final Long clientsInstitution = getInstitutionId(principal);
|
||||||
|
|
||||||
|
if (!clientsInstitution.equals(institutionId)) {
|
||||||
|
log.error("Institutional integrity violation: requested institution: {} authenticated institution: {}",
|
||||||
|
institutionId,
|
||||||
|
clientsInstitution);
|
||||||
|
throw new APIConstraintViolationException("Institutional integrity violation");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Request received on Exam Client Connection create endpoint: "
|
||||||
|
+ "institution: {} "
|
||||||
|
+ "exam: {} "
|
||||||
|
+ "client-address: {}",
|
||||||
|
institutionId,
|
||||||
|
examId,
|
||||||
|
remoteAddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<RunningExam> result;
|
||||||
|
if (examId == null) {
|
||||||
|
result = this.examSessionService.getRunningExamsForInstitution(institutionId)
|
||||||
|
.getOrThrow()
|
||||||
|
.stream()
|
||||||
|
.map(exam -> new RunningExam(exam))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
} else {
|
||||||
|
final Exam exam = this.examDAO.byPK(examId)
|
||||||
|
.getOrThrow();
|
||||||
|
|
||||||
|
result = Arrays.asList(new RunningExam(exam));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.isEmpty()) {
|
||||||
|
log.warn("There are no currently running exams for institution: {}. SEB connection creation denied");
|
||||||
|
throw new IllegalStateException("There are no currently running exams");
|
||||||
|
}
|
||||||
|
|
||||||
|
final ClientConnection clientConnection = this.sebClientConnectionService
|
||||||
|
.createClientConnection(institutionId, remoteAddr, examId)
|
||||||
|
.getOrThrow();
|
||||||
|
|
||||||
|
response.setHeader(
|
||||||
|
API.EXAM_API_SEB_CONNECTION_TOKEN,
|
||||||
|
clientConnection.connectionToken);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(
|
||||||
|
path = API.EXAM_API_HANDSHAKE_ENDPOINT,
|
||||||
|
method = RequestMethod.PATCH,
|
||||||
|
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||||
|
public void handshakeUpdate(
|
||||||
|
@RequestParam(name = API.EXAM_API_PARAM_EXAM_ID, required = false) final Long examId,
|
||||||
|
@RequestParam(name = API.EXAM_API_SEB_CONNECTION_TOKEN, required = true) final String connectionToken,
|
||||||
|
@RequestParam(name = API.EXAM_API_USER_SESSION_ID, required = false) final String userSessionId,
|
||||||
|
final Principal principal,
|
||||||
|
final HttpServletRequest request) {
|
||||||
|
|
||||||
|
final String remoteAddr = request.getRemoteAddr();
|
||||||
|
final Long institutionId = getInstitutionId(principal);
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Request received on SEB Client Connection update endpoint: "
|
||||||
|
+ "institution: {} "
|
||||||
|
+ "exam: {} "
|
||||||
|
+ "userSessionId: {} "
|
||||||
|
+ "client-address: {}",
|
||||||
|
institutionId,
|
||||||
|
examId,
|
||||||
|
userSessionId,
|
||||||
|
remoteAddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sebClientConnectionService.establishClientConnection(
|
||||||
|
connectionToken,
|
||||||
|
institutionId,
|
||||||
|
examId,
|
||||||
|
remoteAddr,
|
||||||
|
userSessionId)
|
||||||
|
.getOrThrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(
|
||||||
|
path = API.EXAM_API_HANDSHAKE_ENDPOINT,
|
||||||
|
method = RequestMethod.PUT,
|
||||||
|
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||||
|
public void handshakeEstablish(
|
||||||
|
@RequestParam(name = API.EXAM_API_PARAM_EXAM_ID, required = false) final Long examId,
|
||||||
|
@RequestParam(name = API.EXAM_API_SEB_CONNECTION_TOKEN, required = true) final String connectionToken,
|
||||||
|
@RequestParam(name = API.EXAM_API_USER_SESSION_ID, required = false) final String userSessionId,
|
||||||
|
final Principal principal,
|
||||||
|
final HttpServletRequest request) {
|
||||||
|
|
||||||
|
final String remoteAddr = request.getRemoteAddr();
|
||||||
|
final Long institutionId = getInstitutionId(principal);
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Request received on SEB Client Connection establish endpoint: "
|
||||||
|
+ "institution: {} "
|
||||||
|
+ "exam: {} "
|
||||||
|
+ "client-address: {}",
|
||||||
|
institutionId,
|
||||||
|
examId,
|
||||||
|
remoteAddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sebClientConnectionService.establishClientConnection(
|
||||||
|
connectionToken,
|
||||||
|
institutionId,
|
||||||
|
examId,
|
||||||
|
remoteAddr,
|
||||||
|
userSessionId)
|
||||||
|
.getOrThrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(
|
||||||
|
path = API.EXAM_API_HANDSHAKE_ENDPOINT,
|
||||||
|
method = RequestMethod.DELETE,
|
||||||
|
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||||
|
public void handshakeEstablish(
|
||||||
|
@RequestParam(name = API.EXAM_API_SEB_CONNECTION_TOKEN, required = true) final String connectionToken,
|
||||||
|
final Principal principal,
|
||||||
|
final HttpServletRequest request) {
|
||||||
|
|
||||||
|
final String remoteAddr = request.getRemoteAddr();
|
||||||
|
final Long institutionId = getInstitutionId(principal);
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Request received on SEB Client Connection close endpoint: "
|
||||||
|
+ "institution: {} "
|
||||||
|
+ "client-address: {}",
|
||||||
|
institutionId,
|
||||||
|
remoteAddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sebClientConnectionService.closeConnection(
|
||||||
|
connectionToken,
|
||||||
|
institutionId,
|
||||||
|
remoteAddr)
|
||||||
|
.getOrThrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(
|
@RequestMapping(
|
||||||
path = API.EXAM_API_CONFIGURATION_REQUEST_ENDPOINT,
|
path = API.EXAM_API_CONFIGURATION_REQUEST_ENDPOINT,
|
||||||
method = RequestMethod.GET,
|
method = RequestMethod.GET,
|
||||||
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
|
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
|
||||||
produces = MediaType.TEXT_XML_VALUE)
|
produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
|
||||||
public ResponseEntity<StreamingResponseBody> getConfig(
|
public ResponseEntity<StreamingResponseBody> getConfig(
|
||||||
@RequestParam(name = API.EXAM_API_SEB_CONNECTION_TOKEN, required = true) final String connectionToken,
|
@RequestParam(name = API.EXAM_API_SEB_CONNECTION_TOKEN, required = true) final String connectionToken,
|
||||||
@RequestParam(name = API.EXAM_API_PARAM_EXAM_ID, required = true) final String examId) {
|
final Principal principal) {
|
||||||
|
|
||||||
|
final Long institutionId = getInstitutionId(principal);
|
||||||
|
final StreamingResponseBody stream = out -> this.examSessionService.streamDefaultExamConfig(
|
||||||
|
institutionId,
|
||||||
|
connectionToken,
|
||||||
|
out);
|
||||||
|
|
||||||
// TODO
|
|
||||||
// 1. check connection validity (connection token)
|
|
||||||
// 2. get and stream SEB Exam configuration for specified exam (Id)
|
|
||||||
final StreamingResponseBody stream = out -> out.write(Utils.toByteArray("TODO SEB Config"));
|
|
||||||
return new ResponseEntity<>(stream, HttpStatus.OK);
|
return new ResponseEntity<>(stream, HttpStatus.OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,13 +255,17 @@ public class ExamAPI_V1_Controller {
|
||||||
path = API.EXAM_API_PING_ENDPOINT,
|
path = API.EXAM_API_PING_ENDPOINT,
|
||||||
method = RequestMethod.PUT,
|
method = RequestMethod.PUT,
|
||||||
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
|
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
|
||||||
produces = MediaType.TEXT_XML_VALUE)
|
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||||
public PingResponse ping(
|
public PingResponse ping(
|
||||||
@RequestParam(name = API.EXAM_API_SEB_CONNECTION_TOKEN, required = true) final String connectionToken,
|
@RequestParam(name = API.EXAM_API_SEB_CONNECTION_TOKEN, required = true) final String connectionToken,
|
||||||
final HttpServletRequest request,
|
@RequestParam(name = API.EXAM_API_PING_TIMESTAMP, required = true) final long timestamp,
|
||||||
final HttpServletResponse response) {
|
@RequestParam(name = API.EXAM_API_PING_NUMBER, required = false) final int pingNumber) {
|
||||||
|
|
||||||
|
this.sebClientConnectionService
|
||||||
|
.notifyPing(connectionToken, timestamp, pingNumber);
|
||||||
|
|
||||||
|
// TODO ping response (issue SEBSERV-74)
|
||||||
|
|
||||||
// TODO
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,11 +275,15 @@ public class ExamAPI_V1_Controller {
|
||||||
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||||
public void event(
|
public void event(
|
||||||
@RequestParam(name = API.EXAM_API_SEB_CONNECTION_TOKEN, required = true) final String connectionToken,
|
@RequestParam(name = API.EXAM_API_SEB_CONNECTION_TOKEN, required = true) final String connectionToken,
|
||||||
final HttpServletRequest request,
|
@RequestBody(required = true) final ClientEvent event) {
|
||||||
final HttpServletResponse response) {
|
|
||||||
|
|
||||||
// TODO
|
this.sebClientConnectionService.notifyClientEvent(connectionToken, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Long getInstitutionId(final Principal principal) {
|
||||||
|
final String clientId = principal.getName();
|
||||||
|
return this.sebClientConfigDAO.byClientId(clientId)
|
||||||
|
.getOrThrow().institutionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,7 @@ public class WebClientDetailsService implements ClientDetailsService {
|
||||||
"");
|
"");
|
||||||
|
|
||||||
baseClientDetails.setScope(Collections.emptySet());
|
baseClientDetails.setScope(Collections.emptySet());
|
||||||
baseClientDetails.setClientSecret(pwd);
|
baseClientDetails.setClientSecret(Utils.toString(pwd));
|
||||||
return baseClientDetails;
|
return baseClientDetails;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ sebserver.webservice.api.exam.refreshTokenValiditySeconds=-1
|
||||||
sebserver.webservice.api.redirect.unauthorized=http://0.0.0.0:8080/gui
|
sebserver.webservice.api.redirect.unauthorized=http://0.0.0.0:8080/gui
|
||||||
sebserver.webservice.api.pagination.maxPageSize=500
|
sebserver.webservice.api.pagination.maxPageSize=500
|
||||||
# comma separated list of known possible OpenEdX API access token request endpoints
|
# comma separated list of known possible OpenEdX API access token request endpoints
|
||||||
sebserver.lms.openedix.api.token.request.paths=/oauth2/access_token
|
sebserver.webservice.lms.openedx.api.token.request.paths=/oauth2/access_token
|
||||||
|
|
||||||
sebserver.gui.entrypoint=/gui
|
sebserver.gui.entrypoint=/gui
|
||||||
sebserver.gui.webservice.protocol=http
|
sebserver.gui.webservice.protocol=http
|
||||||
|
|
|
@ -2,6 +2,9 @@ server.address=localhost
|
||||||
server.port=8090
|
server.port=8090
|
||||||
server.servlet.context-path=/
|
server.servlet.context-path=/
|
||||||
|
|
||||||
|
logging.file=log/sebserver.log
|
||||||
|
|
||||||
|
#
|
||||||
spring.datasource.initialize=true
|
spring.datasource.initialize=true
|
||||||
spring.datasource.initialization-mode=always
|
spring.datasource.initialization-mode=always
|
||||||
spring.datasource.url=jdbc:mariadb://localhost:6603/SEBServer?useSSL=false
|
spring.datasource.url=jdbc:mariadb://localhost:6603/SEBServer?useSSL=false
|
||||||
|
@ -9,6 +12,7 @@ spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
|
||||||
spring.datasource.platform=dev
|
spring.datasource.platform=dev
|
||||||
spring.datasource.hikari.max-lifetime=600000
|
spring.datasource.hikari.max-lifetime=600000
|
||||||
|
|
||||||
|
# webservice configuration
|
||||||
sebserver.webservice.http.scheme=http
|
sebserver.webservice.http.scheme=http
|
||||||
sebserver.webservice.http.server.name=localhost
|
sebserver.webservice.http.server.name=localhost
|
||||||
sebserver.webservice.api.admin.endpoint=/admin-api/v1
|
sebserver.webservice.api.admin.endpoint=/admin-api/v1
|
||||||
|
@ -20,7 +24,11 @@ sebserver.webservice.api.exam.endpoint.v1=${sebserver.webservice.api.exam.endpoi
|
||||||
sebserver.webservice.api.exam.accessTokenValiditySeconds=1800
|
sebserver.webservice.api.exam.accessTokenValiditySeconds=1800
|
||||||
sebserver.webservice.api.exam.refreshTokenValiditySeconds=-1
|
sebserver.webservice.api.exam.refreshTokenValiditySeconds=-1
|
||||||
sebserver.webservice.api.exam.event-handling-strategy=ASYNC_BATCH_STORE_STRATEGY
|
sebserver.webservice.api.exam.event-handling-strategy=ASYNC_BATCH_STORE_STRATEGY
|
||||||
|
sebserver.webservice.api.exam.enable-indicator-cache=true
|
||||||
sebserver.webservice.api.pagination.maxPageSize=500
|
sebserver.webservice.api.pagination.maxPageSize=500
|
||||||
|
# comma separated list of known possible OpenEdX API access token request endpoints
|
||||||
|
sebserver.webservice.lms.openedx.api.token.request.paths=/oauth2/access_token
|
||||||
|
|
||||||
|
# actuator configuration
|
||||||
management.endpoints.web.base-path=/actuator
|
management.endpoints.web.base-path=/actuator
|
||||||
|
management.endpoints.web.exposure.include=logfile,loggers
|
|
@ -8,5 +8,3 @@ spring.http.encoding.enabled=true
|
||||||
sebserver.version=0.3.0 pre-beta
|
sebserver.version=0.3.0 pre-beta
|
||||||
sebserver.supported.languages=en,de
|
sebserver.supported.languages=en,de
|
||||||
|
|
||||||
# comma separated list of known possible OpenEdX API access token request endpoints
|
|
||||||
sebserver.lms.openedix.api.token.request.paths=/oauth2/access_token
|
|
|
@ -7,8 +7,8 @@
|
||||||
</encoder>
|
</encoder>
|
||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
<appender name="DEMO" class="ch.qos.logback.core.FileAppender">
|
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
|
||||||
<file> log-${byDay}.txt </file>
|
<file>log/sebserver.log</file>
|
||||||
<append>true</append>
|
<append>true</append>
|
||||||
<encoder>
|
<encoder>
|
||||||
<pattern>%d{HH:mm:ss.SSS} %-5level [%thread]:[%logger] %msg%n</pattern>
|
<pattern>%d{HH:mm:ss.SSS} %-5level [%thread]:[%logger] %msg%n</pattern>
|
||||||
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
<root level="INFO" additivity="true">
|
<root level="INFO" additivity="true">
|
||||||
<appender-ref ref="STDOUT" />
|
<appender-ref ref="STDOUT" />
|
||||||
|
<appender-ref ref="FILE" />
|
||||||
</root>
|
</root>
|
||||||
|
|
||||||
<Logger name="ch.ethz.seb.sebserver" level="DEBUG" additivity="true" />
|
<Logger name="ch.ethz.seb.sebserver" level="DEBUG" additivity="true" />
|
||||||
|
|
|
@ -79,18 +79,25 @@ DROP TABLE IF EXISTS `client_connection` ;
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `client_connection` (
|
CREATE TABLE IF NOT EXISTS `client_connection` (
|
||||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
`institution_id` BIGINT UNSIGNED NOT NULL,
|
||||||
`exam_id` BIGINT UNSIGNED NULL,
|
`exam_id` BIGINT UNSIGNED NULL,
|
||||||
`status` VARCHAR(45) NOT NULL,
|
`status` VARCHAR(45) NOT NULL,
|
||||||
`connection_token` VARCHAR(255) NOT NULL,
|
`connection_token` VARCHAR(255) NOT NULL,
|
||||||
`exam_user_session_identifer` VARCHAR(255) NOT NULL,
|
`exam_user_session_identifer` VARCHAR(255) NULL,
|
||||||
`client_address` VARCHAR(45) NOT NULL,
|
`client_address` VARCHAR(45) NOT NULL,
|
||||||
`virtual_client_address` VARCHAR(45) NULL,
|
`virtual_client_address` VARCHAR(45) NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
INDEX `connection_exam_ref_idx` (`exam_id` ASC),
|
INDEX `connection_exam_ref_idx` (`exam_id` ASC),
|
||||||
|
INDEX `clientConnectionInstitutionRef_idx` (`institution_id` ASC),
|
||||||
CONSTRAINT `clientConnectionExamRef`
|
CONSTRAINT `clientConnectionExamRef`
|
||||||
FOREIGN KEY (`exam_id`)
|
FOREIGN KEY (`exam_id`)
|
||||||
REFERENCES `exam` (`id`)
|
REFERENCES `exam` (`id`)
|
||||||
ON DELETE NO ACTION
|
ON DELETE NO ACTION
|
||||||
|
ON UPDATE NO ACTION,
|
||||||
|
CONSTRAINT `clientConnectionInstitutionRef`
|
||||||
|
FOREIGN KEY (`institution_id`)
|
||||||
|
REFERENCES `institution` (`id`)
|
||||||
|
ON DELETE NO ACTION
|
||||||
ON UPDATE NO ACTION)
|
ON UPDATE NO ACTION)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
|
@ -102,7 +102,7 @@ CREATE TABLE IF NOT EXISTS `client_connection` (
|
||||||
`exam_id` BIGINT UNSIGNED NULL,
|
`exam_id` BIGINT UNSIGNED NULL,
|
||||||
`status` VARCHAR(45) NOT NULL,
|
`status` VARCHAR(45) NOT NULL,
|
||||||
`connection_token` VARCHAR(255) NOT NULL,
|
`connection_token` VARCHAR(255) NOT NULL,
|
||||||
`exam_user_session_identifer` VARCHAR(255) NOT NULL,
|
`exam_user_session_identifer` VARCHAR(255) NULL,
|
||||||
`client_address` VARCHAR(45) NOT NULL,
|
`client_address` VARCHAR(45) NOT NULL,
|
||||||
`virtual_client_address` VARCHAR(45) NULL,
|
`virtual_client_address` VARCHAR(45) NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
|
|
|
@ -20,13 +20,12 @@ public class ClientCredentialServiceTest {
|
||||||
// @Test
|
// @Test
|
||||||
// public void testEncryptSimpleSecret() {
|
// public void testEncryptSimpleSecret() {
|
||||||
// final Environment envMock = mock(Environment.class);
|
// final Environment envMock = mock(Environment.class);
|
||||||
// when(envMock.getRequiredProperty(ClientCredentialService.SEBSERVER_WEBSERVICE_INTERNAL_SECRET_KEY))
|
// when(envMock.getRequiredProperty(ClientCredentialServiceImpl.SEBSERVER_WEBSERVICE_INTERNAL_SECRET_KEY))
|
||||||
// .thenReturn("secret1");
|
// .thenReturn("internalSecret");
|
||||||
//
|
//
|
||||||
// final ClientCredentialService service = new ClientCredentialService(envMock);
|
// final ClientCredentialService service = new ClientCredentialServiceImpl(envMock);
|
||||||
// final String encrypt = service.encrypt("text1");
|
// final CharSequence encrypt = service.encrypt("test");
|
||||||
// final String decrypt = service.decrypt(encrypt);
|
// assertEquals("", encrypt.toString());
|
||||||
// assertEquals("text1", decrypt);
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -23,5 +23,7 @@ sebserver.webservice.api.exam.accessTokenValiditySeconds=1800
|
||||||
sebserver.webservice.api.exam.refreshTokenValiditySeconds=-1
|
sebserver.webservice.api.exam.refreshTokenValiditySeconds=-1
|
||||||
sebserver.webservice.internalSecret=TO_SET
|
sebserver.webservice.internalSecret=TO_SET
|
||||||
sebserver.webservice.api.redirect.unauthorized=none
|
sebserver.webservice.api.redirect.unauthorized=none
|
||||||
|
# comma separated list of known possible OpenEdX API access token request endpoints
|
||||||
|
sebserver.webservice.lms.openedx.api.token.request.paths=/oauth2/access_token
|
||||||
|
|
||||||
management.endpoints.web.base-path=/actuator
|
management.endpoints.web.base-path=/actuator
|
813
src/test/resources/data-test-additional.sql
Normal file
813
src/test/resources/data-test-additional.sql
Normal file
|
@ -0,0 +1,813 @@
|
||||||
|
INSERT IGNORE INTO lms_setup VALUES
|
||||||
|
(1, 1, 'test', 'MOCKUP', 'http://', 'ccdfa2330533ed6c316a8ffbd64a3197d4a79956ac7ee4c1162f7bdb1a27234fe8793615a51074351e', '8d14b78ecdcbec1d010d414a7208dbe5c411f1fa735c35c7427d840453093a3730d1bc0abe13b9b1a8', null, 1)
|
||||||
|
;
|
||||||
|
|
||||||
|
INSERT IGNORE INTO seb_client_configuration VALUES
|
||||||
|
(1, 1, 'test', '2019-07-02 09:22:50', 'test', '98ac3c953abf5948d9d13c81cab580819ee2624c76d6d4147d4896a5b79f49956d382c08c93cb3b9ae350b32', null, 1)
|
||||||
|
;
|
||||||
|
|
||||||
|
INSERT IGNORE INTO exam VALUES
|
||||||
|
(1, 1, 1, 'quiz1', 'super-admin', 'super-admin', 'MANAGED', null, null, 1),
|
||||||
|
(2, 1, 1, 'quiz6', 'super-admin', 'super-admin', 'MANAGED', null, null, 1)
|
||||||
|
;
|
||||||
|
|
||||||
|
INSERT IGNORE INTO indicator VALUES
|
||||||
|
(1, 2, 'LAST_PING', 'Ping', 'dcdcdc')
|
||||||
|
;
|
||||||
|
|
||||||
|
INSERT IGNORE INTO threshold VALUES
|
||||||
|
(1, 1, 1000.0000, '22b14c'),
|
||||||
|
(2, 1, 2000.0000, 'ff7e00'),
|
||||||
|
(3, 1, 5000.0000, 'ed1c24')
|
||||||
|
;
|
||||||
|
|
||||||
|
INSERT IGNORE INTO view VALUES
|
||||||
|
(1, 'general', 4, 1),
|
||||||
|
(2, 'user_interface', 12, 2),
|
||||||
|
(3, 'browser', 12, 3),
|
||||||
|
(4, 'down_upload', 12, 4),
|
||||||
|
(5, 'exam', 12, 5),
|
||||||
|
(6, 'applications', 12, 6),
|
||||||
|
(7, 'resources', 12, 7),
|
||||||
|
(8, 'network', 12, 8),
|
||||||
|
(9, 'security', 12, 9),
|
||||||
|
(10, 'registry', 12, 10),
|
||||||
|
(11, 'hooked_keys', 12, 11);
|
||||||
|
|
||||||
|
INSERT IGNORE INTO configuration_attribute VALUES
|
||||||
|
(1, 'hashedAdminPassword', 'PASSWORD_FIELD', null, null, null, null, null),
|
||||||
|
(2, 'allowQuit', 'CHECKBOX', null, null, null, null, 'true'),
|
||||||
|
(3, 'ignoreExitKeys', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(4, 'hashedQuitPassword', 'PASSWORD_FIELD', null, null, null, null, null),
|
||||||
|
(5, 'exitKey1', 'SINGLE_SELECTION', null, '0,1,2,3,4,5,6,7,8,9,10,11', 'ExitKeySequenceValidator', 'resourceLocTextKey=sebserver.examconfig.props.label.exitKey', '2'),
|
||||||
|
(6, 'exitKey2', 'SINGLE_SELECTION', null, '0,1,2,3,4,5,6,7,8,9,10,11', 'ExitKeySequenceValidator', 'resourceLocTextKey=sebserver.examconfig.props.label.exitKey', '10'),
|
||||||
|
(7, 'exitKey3', 'SINGLE_SELECTION', null, '0,1,2,3,4,5,6,7,8,9,10,11', 'ExitKeySequenceValidator', 'resourceLocTextKey=sebserver.examconfig.props.label.exitKey', '5'),
|
||||||
|
|
||||||
|
(8, 'browserViewMode', 'RADIO_SELECTION', null, '0,1,2', null, null, '0'),
|
||||||
|
(9, 'enableTouchExit', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(10, 'mainBrowserWindowWidth', 'COMBO_SELECTION', null, '50%,100%,800,1000', 'WindowsSizeValidator', null, '100%'),
|
||||||
|
(11, 'mainBrowserWindowHeight', 'COMBO_SELECTION', null, '80%,100%,600,800', 'WindowsSizeValidator', null, '100%'),
|
||||||
|
(12, 'mainBrowserWindowPositioning', 'SINGLE_SELECTION', null, '0,1,2', null, null, '1'),
|
||||||
|
(13, 'enableBrowserWindowToolbar', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(14, 'hideBrowserWindowToolbar', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(15, 'showMenuBar', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(16, 'showTaskBar', 'CHECKBOX', null, null, null, null, 'true'),
|
||||||
|
(17, 'taskBarHeight', 'COMBO_SELECTION', null, '40,60,80', 'IntegerTypeValidator', null, '40'),
|
||||||
|
(18, 'showReloadButton', 'CHECKBOX', null, null, null, null, 'true'),
|
||||||
|
(19, 'showTime', 'CHECKBOX', null, null, null, null, 'true'),
|
||||||
|
(20, 'showInputLanguage', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(21, 'enableZoomPage', 'CHECKBOX', null, null, null, null, 'true'),
|
||||||
|
(22, 'enableZoomText', 'CHECKBOX', null, null, null, null, 'true'),
|
||||||
|
(23, 'zoomMode', 'RADIO_SELECTION', null, '0,1', null, null, '0'),
|
||||||
|
(24, 'audioControlEnabled', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(25, 'audioMute', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(26, 'audioSetVolumeLevel', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(27, 'audioVolumeLevel', 'SLIDER', null, '0,100', null, null, '25'),
|
||||||
|
(28, 'allowSpellCheck', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(29, 'allowDictionaryLookup', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(30, 'allowSpellCheckDictionary', 'MULTI_CHECKBOX_SELECTION', null, 'da-DK,en-AU,en-GB,en-US,es-ES,fr-FR,pt-PT,sv-SE,sv-FI', null, null, 'da-DK,en-AU,en-GB,en-US,es-ES,fr-FR,pt-PT,sv-SE,sv-FI'),
|
||||||
|
|
||||||
|
(31, 'newBrowserWindowByLinkPolicy', 'RADIO_SELECTION', null, '0,1,2', null, null, '2'),
|
||||||
|
(32, 'newBrowserWindowByLinkBlockForeign', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(33, 'newBrowserWindowByLinkWidth', 'COMBO_SELECTION', null, '50%,100%,800,1000', 'WindowsSizeValidator', null, '100%'),
|
||||||
|
(34, 'newBrowserWindowByLinkHeight', 'COMBO_SELECTION', null, '80%,100%,600,800', 'WindowsSizeValidator', null, '100%'),
|
||||||
|
(35, 'newBrowserWindowByLinkPositioning', 'SINGLE_SELECTION', null, '0,1,2', null, null, '2'),
|
||||||
|
(36, 'enablePlugIns', 'CHECKBOX', null, null, null, null, 'true'),
|
||||||
|
(37, 'enableJavaScript', 'CHECKBOX', null, null, null, null, 'true'),
|
||||||
|
(38, 'enableJava', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(39, 'blockPopUpWindows', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(40, 'allowVideoCapture', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(41, 'allowAudioCapture', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(42, 'allowBrowsingBackForward', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(43, 'newBrowserWindowNavigation', 'CHECKBOX', null, null, null, null, 'true'),
|
||||||
|
(44, 'browserWindowAllowReload', 'CHECKBOX', null, null, null, null, 'true'),
|
||||||
|
(45, 'newBrowserWindowAllowReload', 'CHECKBOX', null, null, null, null, 'true'),
|
||||||
|
(46, 'showReloadWarning', 'CHECKBOX', null, null, null, null, 'true'),
|
||||||
|
(47, 'newBrowserWindowShowReloadWarning', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(48, 'removeBrowserProfile', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(49, 'removeLocalStorage', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(50, 'browserUserAgent', 'TEXT_FIELD', null, null, null, null, null),
|
||||||
|
(51, 'browserUserAgentWinDesktopMode', 'RADIO_SELECTION', null, '0,1', null, null, '0'),
|
||||||
|
(52, 'browserUserAgentWinDesktopModeCustom', 'TEXT_FIELD', null, null, null, null, null),
|
||||||
|
(53, 'browserUserAgentWinTouchMode', 'RADIO_SELECTION', null, '0,1,2', null, null, '0'),
|
||||||
|
(54, 'browserUserAgentWinTouchModeCustom', 'TEXT_FIELD', null, null, null, null, null),
|
||||||
|
(55, 'browserUserAgentMac', 'RADIO_SELECTION', null, '0,1', null, null, '0'),
|
||||||
|
(56, 'browserUserAgentMacCustom', 'TEXT_FIELD', null, null, null, null, null),
|
||||||
|
(57, 'enableSebBrowser', 'CHECKBOX', null, null, null, null, 'true'),
|
||||||
|
(58, 'browserWindowTitleSuffix', 'TEXT_FIELD', null, null, null, null, null),
|
||||||
|
|
||||||
|
(59, 'allowDownUploads', 'CHECKBOX', null, null, null, null, 'true'),
|
||||||
|
(60, 'downloadDirectoryWin', 'TEXT_FIELD', null, null, null, null, null),
|
||||||
|
(61, 'downloadDirectoryOSX', 'TEXT_FIELD', null, null, null, null, null),
|
||||||
|
(62, 'openDownloads', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(63, 'chooseFileToUploadPolicy', 'RADIO_SELECTION', null, '0,1,2', null, null, '0'),
|
||||||
|
(64, 'downloadPDFFiles', 'CHECKBOX', null, null, null, null, 'true'),
|
||||||
|
(65, 'allowPDFPlugIn', 'CHECKBOX', null, null, null, null, 'true'),
|
||||||
|
(66, 'downloadAndOpenSebConfig', 'CHECKBOX', null, null, null, null, 'true'),
|
||||||
|
|
||||||
|
(67, 'quitURL', 'TEXT_FIELD', null, null, null, null, null),
|
||||||
|
(68, 'quitURLConfirm', 'CHECKBOX', null, null, null, null, 'true'),
|
||||||
|
(69, 'restartExamUseStartURL', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(70, 'restartExamURL', 'TEXT_FIELD', null, null, null, null, null),
|
||||||
|
(71, 'restartExamText', 'TEXT_FIELD', null, null, null, null, null),
|
||||||
|
(72, 'restartExamPasswordProtected', 'CHECKBOX', null, null, null, null, 'true'),
|
||||||
|
|
||||||
|
(73, 'permittedProcesses', 'TABLE', null, null, null, null, null),
|
||||||
|
(74, 'permittedProcesses.active', 'CHECKBOX', 73, null, null, null, 'true'),
|
||||||
|
(75, 'permittedProcesses.os', 'SINGLE_SELECTION', 73, '0,1', null, null, '0'),
|
||||||
|
(76, 'permittedProcesses.title', 'TEXT_FIELD', 73, null, null, null, ''),
|
||||||
|
(77, 'permittedProcesses.description', 'TEXT_FIELD', 73, null, null, null, ''),
|
||||||
|
(78, 'permittedProcesses.executable', 'TEXT_FIELD', 73, null, null, null, ''),
|
||||||
|
(79, 'permittedProcesses.originalName', 'TEXT_FIELD', 73, null, null, null, ''),
|
||||||
|
(80, 'permittedProcesses.allowedExecutables', 'TEXT_FIELD', 73, null, null, null, ''),
|
||||||
|
(81, 'permittedProcesses.path', 'TEXT_FIELD', 73, null, null, null, ''),
|
||||||
|
(82, 'permittedProcesses.arguments', 'INLINE_TABLE', 73, '1:active:CHECKBOX|4:argument:TEXT_FIELD', null, null, null),
|
||||||
|
(85, 'permittedProcesses.identifier', 'TEXT_FIELD', 73, null, null, null, ''),
|
||||||
|
(86, 'permittedProcesses.iconInTaskbar', 'CHECKBOX', 73, null, null, null, 'true'),
|
||||||
|
(87, 'permittedProcesses.autostart', 'CHECKBOX', 73, null, null, null, 'false'),
|
||||||
|
(88, 'permittedProcesses.runInBackground', 'CHECKBOX', 73, null, null, null, 'false'),
|
||||||
|
(89, 'permittedProcesses.allowUserToChooseApp', 'CHECKBOX', 73, null, null, null, 'false'),
|
||||||
|
(90, 'permittedProcesses.strongKill', 'CHECKBOX', 73, null, null, null, 'false'),
|
||||||
|
(91, 'allowSwitchToApplications', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(92, 'allowFlashFullscreen', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
|
||||||
|
(93, 'prohibitedProcesses', 'TABLE', null, null, null, null, null),
|
||||||
|
(94, 'prohibitedProcesses.active', 'CHECKBOX', 93, null, null, null, 'true'),
|
||||||
|
(95, 'prohibitedProcesses.os', 'SINGLE_SELECTION', 93, '0,1', null, null, '0'),
|
||||||
|
(96, 'prohibitedProcesses.executable', 'TEXT_FIELD', 93, null, null, null, ''),
|
||||||
|
(97, 'prohibitedProcesses.description', 'TEXT_FIELD', 93, null, null, null, ''),
|
||||||
|
(98, 'prohibitedProcesses.originalName', 'TEXT_FIELD', 93, null, null, null, ''),
|
||||||
|
(99, 'prohibitedProcesses.identifier', 'TEXT_FIELD', 93, null, null, null, ''),
|
||||||
|
(100, 'prohibitedProcesses.strongKill', 'CHECKBOX', 93, null, null, null, 'false'),
|
||||||
|
|
||||||
|
(200, 'URLFilterEnable', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(201, 'URLFilterEnableContentFilter', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(202, 'URLFilterRules', 'TABLE', null, null, null, null, null),
|
||||||
|
(203, 'URLFilterRules.active', 'CHECKBOX', 202, null, null, null, 'true'),
|
||||||
|
(204, 'URLFilterRules.regex', 'CHECKBOX', 202, null, null, null, 'false'),
|
||||||
|
(205, 'URLFilterRules.expression', 'TEXT_FIELD', 202, null, null, null, ''),
|
||||||
|
(206, 'URLFilterRules.action', 'SINGLE_SELECTION', 202, '0,1', null, null, ''),
|
||||||
|
|
||||||
|
(210, 'proxySettingsPolicy', 'RADIO_SELECTION', null, '0,1', null, null, '0'),
|
||||||
|
(220, 'proxies', 'COMPOSITE_TABLE', null, 'active,TABLE_ENTRY|autoDiscovery,autoConfiguration,http,https,ftp,socks,rtsp', null, null, null),
|
||||||
|
(221, 'ExcludeSimpleHostnames', 'CHECKBOX', 220, null, null, 'showInView=true,createDefaultValue=true', 'false'),
|
||||||
|
(222, 'ExceptionsList', 'TEXT_AREA', 220, null, null, 'showInView=true,createDefaultValue=true', null),
|
||||||
|
(223, 'FTPPassive', 'CHECKBOX', 220, null, null, 'showInView=true,createDefaultValue=true', 'true'),
|
||||||
|
(231, 'AutoDiscoveryEnabled', 'CHECKBOX', 220, null, null, 'groupId=autoDiscovery,createDefaultValue=true', 'false'),
|
||||||
|
(233, 'AutoConfigurationEnabled', 'CHECKBOX', 220, null, null, 'groupId=autoConfiguration,createDefaultValue=true', 'false'),
|
||||||
|
(234, 'AutoConfigurationURL', 'TEXT_FIELD', 220, null, null, 'groupId=autoConfiguration,createDefaultValue=true', null),
|
||||||
|
(235, 'AutoConfigurationJavaScript', 'TEXT_AREA', 220, null, null, 'groupId=autoConfiguration,createDefaultValue=true', null),
|
||||||
|
(236, 'HTTPEnable', 'CHECKBOX', 220, null, null, 'groupId=http,createDefaultValue=true', 'false'),
|
||||||
|
(237, 'HTTPProxy', 'TEXT_FIELD', 220, null, null, 'groupId=http,createDefaultValue=true', null),
|
||||||
|
(238, 'HTTPPort', 'INTEGER', 220, null, null, 'groupId=http,createDefaultValue=true', '80'),
|
||||||
|
(239, 'HTTPRequiresPassword', 'CHECKBOX', 220, null, null, 'groupId=http,createDefaultValue=true', 'false'),
|
||||||
|
(240, 'HTTPUsername', 'TEXT_FIELD', 220, null, null, 'groupId=http,createDefaultValue=true', null),
|
||||||
|
(241, 'HTTPPassword', 'TEXT_FIELD', 220, null, null, 'groupId=http,createDefaultValue=true', null),
|
||||||
|
(242, 'HTTPSEnable', 'CHECKBOX', 220, null, null, 'groupId=https,createDefaultValue=true', 'false'),
|
||||||
|
(243, 'HTTPSProxy', 'TEXT_FIELD', 220, null, null, 'groupId=https,createDefaultValue=true', null),
|
||||||
|
(244, 'HTTPSPort', 'INTEGER', 220, null, null, 'groupId=https,createDefaultValue=true', '443'),
|
||||||
|
(245, 'HTTPSRequiresPassword', 'CHECKBOX', 220, null, null, 'groupId=https,createDefaultValue=true', 'false'),
|
||||||
|
(246, 'HTTPSUsername', 'TEXT_FIELD', 220, null, null, 'groupId=https,createDefaultValue=true', null),
|
||||||
|
(247, 'HTTPSPassword', 'TEXT_FIELD', 220, null, null, 'groupId=https,createDefaultValue=true', null),
|
||||||
|
(248, 'FTPEnable', 'CHECKBOX', 220, null, null, 'groupId=ftp,createDefaultValue=true', 'false'),
|
||||||
|
(249, 'FTPProxy', 'TEXT_FIELD', 220, null, null, 'groupId=ftp,createDefaultValue=true', null),
|
||||||
|
(250, 'FTPPort', 'INTEGER', 220, null, null, 'groupId=ftp,createDefaultValue=true', '21'),
|
||||||
|
(251, 'FTPRequiresPassword', 'CHECKBOX', 220, null, null, 'groupId=ftp,createDefaultValue=true', 'false'),
|
||||||
|
(252, 'FTPUsername', 'TEXT_FIELD', 220, null, null, 'groupId=ftp,createDefaultValue=true', null),
|
||||||
|
(253, 'FTPPassword', 'TEXT_FIELD', 220, null, null, 'groupId=ftp,createDefaultValue=true', null),
|
||||||
|
(254, 'SOCKSEnable', 'CHECKBOX', 220, null, null, 'groupId=socks,createDefaultValue=true', 'false'),
|
||||||
|
(255, 'SOCKSProxy', 'TEXT_FIELD', 220, null, null, 'groupId=socks,createDefaultValue=true', null),
|
||||||
|
(256, 'SOCKSPort', 'INTEGER', 220, null, null, 'groupId=socks,createDefaultValue=true', '1080'),
|
||||||
|
(257, 'SOCKSRequiresPassword', 'CHECKBOX', 220, null, null, 'groupId=socks,createDefaultValue=true', 'false'),
|
||||||
|
(258, 'SOCKSUsername', 'TEXT_FIELD', 220, null, null, 'groupId=socks,createDefaultValue=true', null),
|
||||||
|
(259, 'SOCKSPassword', 'TEXT_FIELD', 220, null, null, 'groupId=socks,createDefaultValue=true', null),
|
||||||
|
(260, 'RTSPEnable', 'CHECKBOX', 220, null, null, 'groupId=rtsp,createDefaultValue=true', 'false'),
|
||||||
|
(261, 'RTSPProxy', 'TEXT_FIELD', 220, null, null, 'groupId=rtsp,createDefaultValue=true', null),
|
||||||
|
(262, 'RTSPPort', 'INTEGER', 220, null, null, 'groupId=rtsp,createDefaultValue=true', '1080'),
|
||||||
|
(263, 'RTSPRequiresPassword', 'CHECKBOX', 220, null, null, 'groupId=rtsp,createDefaultValue=true', 'false'),
|
||||||
|
(264, 'RTSPUsername', 'TEXT_FIELD', 220, null, null, 'groupId=rtsp,createDefaultValue=true', null),
|
||||||
|
(265, 'RTSPPassword', 'TEXT_FIELD', 220, null, null, 'groupId=rtsp,createDefaultValue=true', null),
|
||||||
|
|
||||||
|
|
||||||
|
(300, 'sebServicePolicy', 'RADIO_SELECTION', null, '0,1,2', null, null, '2'),
|
||||||
|
(301, 'kioskMode', 'RADIO_SELECTION', null, '0,1,2', null, null, '0'),
|
||||||
|
(302, 'allowVirtualMachine', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(303, 'allowScreenSharing', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(304, 'enablePrivateClipboard', 'CHECKBOX', null, null, null, null, 'true'),
|
||||||
|
(305, 'enableLogging', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(306, 'logDirectoryWin', 'TEXT_FIELD', null, null, null, null, ''),
|
||||||
|
(307, 'logDirectoryOSX', 'TEXT_FIELD', null, null, null, null, '~/Documents'),
|
||||||
|
(308, 'minMacOSVersion', 'SINGLE_SELECTION', null, '0,1,2,3,4,5,6,7', null, null, '0'),
|
||||||
|
(309, 'enableAppSwitcherCheck', 'CHECKBOX', null, null, null, null, 'true'),
|
||||||
|
(310, 'forceAppFolderInstall', 'CHECKBOX', null, null, null, null, 'true'),
|
||||||
|
(311, 'allowUserAppFolderInstall', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(312, 'allowSiri', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(313, 'detectStoppedProcess', 'CHECKBOX', null, null, null, null, 'true'),
|
||||||
|
(314, 'allowDisplayMirroring', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(315, 'allowedDisplaysMaxNumber', 'COMBO_SELECTION', null, '1,2,3', null, null, '1'),
|
||||||
|
(316, 'allowedDisplayBuiltin', 'CHECKBOX', null, null, null, null, 'true'),
|
||||||
|
|
||||||
|
(400, 'insideSebEnableSwitchUser', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(401, 'insideSebEnableLockThisComputer', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(402, 'insideSebEnableChangeAPassword', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(403, 'insideSebEnableStartTaskManager', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(404, 'insideSebEnableLogOff', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(405, 'insideSebEnableShutDown', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(406, 'insideSebEnableEaseOfAccess', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(407, 'insideSebEnableVmWareClientShade', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(408, 'insideSebEnableNetworkConnectionSelector', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
|
||||||
|
(500, 'enableEsc', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(501, 'enablePrintScreen', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(502, 'enableCtrlEsc', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(503, 'enableAltEsc', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(504, 'enableAltTab', 'CHECKBOX', null, null, null, null, 'true'),
|
||||||
|
(505, 'enableAltF4', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(506, 'enableStartMenu', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(507, 'enableRightMouse', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(508, 'enableAltMouseWheel', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
|
||||||
|
(509, 'enableF1', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(510, 'enableF2', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(511, 'enableF3', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(512, 'enableF4', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(513, 'enableF5', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(514, 'enableF6', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(515, 'enableF7', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(516, 'enableF8', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(517, 'enableF9', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(518, 'enableF10', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(519, 'enableF11', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
(520, 'enableF12', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
|
|
||||||
|
(1000, 'originatorVersion', 'TEXT_FIELD', null, null, null, null, 'SEB_Server_0.3.0'),
|
||||||
|
(1001, 'sebConfigPurpose', 'RADIO_SELECTION', null, '0,1', null, null, '0')
|
||||||
|
|
||||||
|
;
|
||||||
|
INSERT IGNORE INTO orientation VALUES
|
||||||
|
(1, 1, 0, 1, null, 1, 1, 1, 2, 'LEFT'),
|
||||||
|
(2, 2, 0, 1, null, 1, 3, 1, 1, 'LEFT'),
|
||||||
|
(3, 3, 0, 1, null, 1, 4, 1, 1, 'LEFT'),
|
||||||
|
(4, 4, 0, 1, null, 1, 5, 1, 2, 'LEFT'),
|
||||||
|
(5, 5, 0, 1, 'exitSequence', 2, 1, 1, 1, 'NONE'),
|
||||||
|
(6, 6, 0, 1, 'exitSequence', 2, 2, 1, 1, 'NONE'),
|
||||||
|
(7, 7, 0, 1, 'exitSequence', 2, 3, 1, 1, 'NONE'),
|
||||||
|
|
||||||
|
(8, 8, 0, 2, 'browserViewMode', 0, 0, 3, 3, 'NONE'),
|
||||||
|
(9, 9, 0, 2, 'browserViewMode', 3, 2, 4, 1, 'NONE'),
|
||||||
|
(10, 10, 0, 2, 'winsize', 1, 4, 2, 1, 'LEFT'),
|
||||||
|
(11, 11, 0, 2, 'winsize', 1, 5, 2, 1, 'LEFT'),
|
||||||
|
(12, 12, 0, 2, 'winsize', 5, 4, 2, 1, 'LEFT_SPAN'),
|
||||||
|
(13, 13, 0, 2, 'wintoolbar', 0, 6, 3, 1, 'NONE'),
|
||||||
|
(14, 14, 0, 2, 'wintoolbar', 3, 6, 4, 1, 'NONE'),
|
||||||
|
(15, 15, 0, 2, 'wintoolbar', 0, 7, 3, 1, 'NONE'),
|
||||||
|
(16, 16, 0, 2, 'taskbar', 0, 9, 3, 1, 'NONE'),
|
||||||
|
(17, 17, 0, 2, 'taskbar', 5, 9, 2, 1, 'LEFT_SPAN'),
|
||||||
|
(18, 18, 0, 2, 'taskbar', 0, 10, 3, 1, 'NONE'),
|
||||||
|
(19, 19, 0, 2, 'taskbar', 0, 11, 3, 1, 'NONE'),
|
||||||
|
(20, 20, 0, 2, 'taskbar', 0, 12, 3, 1, 'NONE'),
|
||||||
|
(21, 21, 0, 2, 'zoom', 0, 14, 3, 1, 'NONE'),
|
||||||
|
(22, 22, 0, 2, 'zoom', 0, 15, 3, 1, 'NONE'),
|
||||||
|
(23, 23, 0, 2, 'zoomMode', 3, 14, 4, 1, 'NONE'),
|
||||||
|
(24, 24, 0, 2, 'audio', 7, 0, 5, 1, 'NONE'),
|
||||||
|
(25, 25, 0, 2, 'audio', 7, 1, 5, 1, 'NONE'),
|
||||||
|
(26, 26, 0, 2, 'audio', 7, 2, 5, 1, 'NONE'),
|
||||||
|
(27, 27, 0, 2, 'audio', 7, 3, 5, 1, 'NONE'),
|
||||||
|
(28, 28, 0, 2, 'spellcheck', 7, 4, 5, 1, 'NONE'),
|
||||||
|
(29, 29, 0, 2, 'spellcheck', 7, 5, 5, 1, 'NONE'),
|
||||||
|
(30, 30, 0, 2, 'spellcheck', 7, 7, 5, 9, 'TOP'),
|
||||||
|
|
||||||
|
(31, 31, 0, 3, 'newBrowserWindow', 0, 0, 3, 3, 'NONE'),
|
||||||
|
(32, 32, 0, 3, 'newBrowserWindow', 4, 0, 3, 1, 'NONE'),
|
||||||
|
(33, 33, 0, 3, 'newwinsize', 1, 4, 2, 1, 'LEFT'),
|
||||||
|
(34, 34, 0, 3, 'newwinsize', 1, 5, 2, 1, 'LEFT'),
|
||||||
|
(35, 35, 0, 3, 'newwinsize', 5, 4, 2, 1, 'LEFT_SPAN'),
|
||||||
|
(36, 36, 0, 3, 'browserSecurity', 0, 5, 4, 1, 'NONE'),
|
||||||
|
(37, 37, 0, 3, 'browserSecurity', 4, 5, 3, 1, 'NONE'),
|
||||||
|
(38, 38, 0, 3, 'browserSecurity', 0, 6, 4, 1, 'NONE'),
|
||||||
|
(39, 39, 0, 3, 'browserSecurity', 4, 6, 3, 1, 'NONE'),
|
||||||
|
(40, 40, 0, 3, 'browserSecurity', 0, 7, 4, 1, 'NONE'),
|
||||||
|
(41, 41, 0, 3, 'browserSecurity', 4, 7, 3, 1, 'NONE'),
|
||||||
|
(42, 42, 0, 3, 'browserSecurity', 0, 8, 4, 1, 'NONE'),
|
||||||
|
(43, 43, 0, 3, 'browserSecurity', 4, 8, 3, 1, 'NONE'),
|
||||||
|
(44, 44, 0, 3, 'browserSecurity', 0, 9, 4, 1, 'NONE'),
|
||||||
|
(45, 45, 0, 3, 'browserSecurity', 4, 9, 3, 1, 'NONE'),
|
||||||
|
(46, 46, 0, 3, 'browserSecurity', 0, 10, 4, 1, 'NONE'),
|
||||||
|
(47, 47, 0, 3, 'browserSecurity', 4, 10, 3, 1, 'NONE'),
|
||||||
|
(48, 48, 0, 3, 'browserSecurity', 0, 11, 4, 1, 'NONE'),
|
||||||
|
(49, 49, 0, 3, 'browserSecurity', 4, 11, 3, 1, 'NONE'),
|
||||||
|
|
||||||
|
(50, 50, 0, 3, null, 7, 1, 5, 1, 'TOP'),
|
||||||
|
(51, 51, 0, 3, 'userAgentDesktop', 7, 2, 5, 2, 'NONE'),
|
||||||
|
(52, 52, 0, 3, 'userAgentDesktop', 7, 3, 5, 1, 'NONE'),
|
||||||
|
(53, 53, 0, 3, 'userAgentTouch', 7, 4, 5, 3, 'NONE'),
|
||||||
|
(54, 54, 0, 3, 'userAgentTouch', 7, 8, 5, 1, 'NONE'),
|
||||||
|
(55, 55, 0, 3, 'userAgentMac', 7, 9, 5, 2, 'NONE'),
|
||||||
|
(56, 56, 0, 3, 'userAgentMac', 7, 11, 5, 1, 'NONE'),
|
||||||
|
(57, 57, 0, 3, null, 0, 14, 6, 1, 'NONE'),
|
||||||
|
(58, 58, 0, 3, null, 7, 14, 5, 1, 'TOP'),
|
||||||
|
|
||||||
|
(59, 59, 0, 4, null, 0, 0, 8, 1, 'NONE'),
|
||||||
|
(60, 60, 0, 4, null, 3, 1, 5, 1, 'LEFT_SPAN'),
|
||||||
|
(61, 61, 0, 4, null, 3, 2, 5, 1, 'LEFT_SPAN'),
|
||||||
|
(62, 62, 0, 4, null, 0, 3, 8, 1, 'NONE'),
|
||||||
|
(63, 63, 0, 4, null, 0, 5, 8, 2, 'TOP'),
|
||||||
|
(64, 64, 0, 4, null, 0, 8, 8, 1, 'NONE'),
|
||||||
|
(65, 65, 0, 4, null, 0, 9, 8, 1, 'NONE'),
|
||||||
|
(66, 66, 0, 4, null, 0, 10, 8, 1, 'NONE'),
|
||||||
|
|
||||||
|
(67, 67, 0, 5, 'quitLink', 0, 1, 8, 1, 'TOP'),
|
||||||
|
(68, 68, 0, 5, 'quitLink', 0, 2, 8, 1, 'NONE'),
|
||||||
|
(69, 69, 0, 5, 'backToStart', 0, 4, 8, 1, 'NONE'),
|
||||||
|
(70, 70, 0, 5, 'backToStart', 0, 6, 8, 2, 'TOP'),
|
||||||
|
(71, 71, 0, 5, 'backToStart', 0, 8, 8, 2, 'TOP'),
|
||||||
|
(72, 72, 0, 5, 'backToStart', 0, 10, 8, 1, 'NONE'),
|
||||||
|
|
||||||
|
(73, 73, 0, 6, null, 0, 2, 10, 6, 'TOP'),
|
||||||
|
(74, 74, 0, 6, null, 1, 1, 1, 1, 'LEFT'),
|
||||||
|
(75, 75, 0, 6, null, 2, 2, 1, 1, 'LEFT'),
|
||||||
|
(76, 76, 0, 6, null, 4, 4, 2, 1, 'LEFT'),
|
||||||
|
(77, 77, 0, 6, null, 0, 3, 1, 1, 'LEFT'),
|
||||||
|
(78, 78, 0, 6, null, 3, 4, 4, 1, 'LEFT'),
|
||||||
|
(79, 79, 0, 6, null, 0, 5, 1, 1, 'LEFT'),
|
||||||
|
(80, 80, 0, 6, null, 0, 6, 1, 1, 'LEFT'),
|
||||||
|
(81, 81, 0, 6, null, 0, 7, 1, 1, 'LEFT'),
|
||||||
|
|
||||||
|
(82, 82, 0, 6, null, 0, 8, 1, 3, 'LEFT'),
|
||||||
|
|
||||||
|
(85, 85, 0, 6, null, 0, 8, 1, 1, 'LEFT'),
|
||||||
|
(86, 86, 0, 6, null, 0, 7, 1, 1, 'LEFT'),
|
||||||
|
(87, 87, 0, 6, null, 0, 9, 1, 1, 'LEFT'),
|
||||||
|
(88, 88, 0, 6, null, 0, 10, 1, 1, 'LEFT'),
|
||||||
|
(89, 89, 0, 6, null, 0, 11, 1, 1, 'LEFT'),
|
||||||
|
(90, 90, 0, 6, null, 0, 12, 1, 1, 'LEFT'),
|
||||||
|
(91, 91, 0, 6, null, 0, 0, 5, 1, 'NONE'),
|
||||||
|
(92, 92, 0, 6, null, 5, 0, 5, 1, 'NONE'),
|
||||||
|
(93, 93, 0, 6, null, 0, 10, 10, 6, 'TOP'),
|
||||||
|
(94, 94, 0, 6, null, 1, 1, 1, 1, 'LEFT'),
|
||||||
|
(95, 95, 0, 6, null, 2, 2, 1, 1, 'LEFT'),
|
||||||
|
(96, 96, 0, 6, null, 3, 3, 4, 1, 'LEFT'),
|
||||||
|
(97, 97, 0, 6, null, 4, 5, 2, 1, 'LEFT'),
|
||||||
|
(98, 98, 0, 6, null, 0, 4, 1, 1, 'LEFT'),
|
||||||
|
(99, 99, 0, 6, null, 0, 6, 1, 1, 'LEFT'),
|
||||||
|
(100, 100, 0, 6, null, 0, 7, 1, 1, 'LEFT'),
|
||||||
|
|
||||||
|
(200, 200, 0, 8, 'urlFilter', 0, 0, 3, 1, 'NONE'),
|
||||||
|
(201, 201, 0, 8, 'urlFilter', 3, 0, 4, 1, 'NONE'),
|
||||||
|
(202, 202, 0, 8, 'urlFilter', 0, 1, 12, 6, 'NONE'),
|
||||||
|
(203, 203, 0, 8, 'urlFilter', 1, 1, 1, 1, 'LEFT'),
|
||||||
|
(204, 204, 0, 8, 'urlFilter', 2, 2, 1, 1, 'LEFT'),
|
||||||
|
(205, 205, 0, 8, 'urlFilter', 3, 3, 4, 1, 'LEFT'),
|
||||||
|
(206, 206, 0, 8, 'urlFilter', 4, 4, 2, 1, 'LEFT'),
|
||||||
|
|
||||||
|
(210, 210, 0, 8, 'proxies', 0, 6, 5, 2, 'NONE'),
|
||||||
|
(220, 220, 0, 8, 'proxies', 7, 7, 5, 7, 'TOP'),
|
||||||
|
(221, 221, 0, 8, 'proxies', 0, 8, 6, 1, 'NONE'),
|
||||||
|
(222, 222, 0, 8, 'proxies', 0, 10, 6, 2, 'TOP'),
|
||||||
|
(223, 223, 0, 8, 'proxies', 0, 11, 6, 1, 'NONE'),
|
||||||
|
|
||||||
|
(231, 231, 0, 8, 'active', 0, 0, 1, 1, 'LEFT'),
|
||||||
|
|
||||||
|
(233, 233, 0, 8, 'active', 0, 0, 1, 1, 'LEFT'),
|
||||||
|
(234, 234, 0, 8, null, 0, 1, 1, 1, 'LEFT'),
|
||||||
|
(235, 235, 0, 8, null, 0, 2, 1, 1, 'LEFT'),
|
||||||
|
(236, 236, 0, 8, 'active', 0, 0, 1, 1, 'LEFT'),
|
||||||
|
(237, 237, 0, 8, null, 0, 1, 1, 1, 'LEFT'),
|
||||||
|
(238, 238, 0, 8, null, 0, 2, 1, 1, 'LEFT'),
|
||||||
|
(239, 239, 0, 8, null, 0, 3, 1, 1, 'LEFT'),
|
||||||
|
(240, 240, 0, 8, null, 0, 4, 1, 1, 'LEFT'),
|
||||||
|
(241, 241, 0, 8, null, 0, 5, 1, 1, 'LEFT'),
|
||||||
|
(242, 242, 0, 8, 'active', 0, 0, 1, 1, 'LEFT'),
|
||||||
|
(243, 243, 0, 8, null, 0, 1, 1, 1, 'LEFT'),
|
||||||
|
(244, 244, 0, 8, null, 0, 2, 1, 1, 'LEFT'),
|
||||||
|
(245, 245, 0, 8, null, 0, 3, 1, 1, 'LEFT'),
|
||||||
|
(246, 246, 0, 8, null, 0, 4, 1, 1, 'LEFT'),
|
||||||
|
(247, 247, 0, 8, null, 0, 5, 1, 1, 'LEFT'),
|
||||||
|
(248, 248, 0, 8, 'active', 0, 0, 1, 1, 'LEFT'),
|
||||||
|
(249, 249, 0, 8, null, 0, 1, 1, 1, 'LEFT'),
|
||||||
|
(250, 250, 0, 8, null, 0, 2, 1, 1, 'LEFT'),
|
||||||
|
(251, 251, 0, 8, null, 0, 3, 1, 1, 'LEFT'),
|
||||||
|
(252, 252, 0, 8, null, 0, 4, 1, 1, 'LEFT'),
|
||||||
|
(253, 253, 0, 8, null, 0, 5, 1, 1, 'LEFT'),
|
||||||
|
(254, 254, 0, 8, 'active', 0, 0, 1, 1, 'LEFT'),
|
||||||
|
(255, 255, 0, 8, null, 0, 1, 1, 1, 'LEFT'),
|
||||||
|
(256, 256, 0, 8, null, 0, 2, 1, 1, 'LEFT'),
|
||||||
|
(257, 257, 0, 8, null, 0, 3, 1, 1, 'LEFT'),
|
||||||
|
(258, 258, 0, 8, null, 0, 4, 1, 1, 'LEFT'),
|
||||||
|
(259, 259, 0, 8, null, 0, 5, 1, 1, 'LEFT'),
|
||||||
|
(260, 260, 0, 8, 'active', 0, 0, 1, 1, 'LEFT'),
|
||||||
|
(261, 261, 0, 8, null, 0, 1, 1, 1, 'LEFT'),
|
||||||
|
(262, 262, 0, 8, null, 0, 2, 1, 1, 'LEFT'),
|
||||||
|
(263, 263, 0, 8, null, 0, 3, 1, 1, 'LEFT'),
|
||||||
|
(264, 264, 0, 8, null, 0, 4, 1, 1, 'LEFT'),
|
||||||
|
(265, 265, 0, 8, null, 0, 5, 1, 1, 'LEFT'),
|
||||||
|
|
||||||
|
|
||||||
|
(300, 300, 0, 9, 'servicePolicy', 0, 0, 4, 3, 'NONE'),
|
||||||
|
(301, 301, 0, 9, 'kioskMode', 4, 0, 3, 3, 'NONE'),
|
||||||
|
(302, 302, 0, 9, null, 0, 5, 4, 1, 'NONE'),
|
||||||
|
(303, 303, 0, 9, null, 0, 6, 4, 1, 'NONE'),
|
||||||
|
(304, 304, 0, 9, null, 4, 5, 3, 1, 'NONE'),
|
||||||
|
(305, 305, 0, 9, 'logging', 0, 8, 6, 1, 'NONE'),
|
||||||
|
(306, 306, 0, 9, 'logging', 3, 9, 4, 1, 'LEFT_SPAN'),
|
||||||
|
(307, 307, 0, 9, 'logging', 3, 10, 4, 1, 'LEFT_SPAN'),
|
||||||
|
(308, 308, 0, 9, 'macSettings', 7, 1, 5, 1, 'TOP'),
|
||||||
|
(309, 309, 0, 9, 'macSettings', 7, 2, 5, 1, 'NONE'),
|
||||||
|
(310, 310, 0, 9, 'macSettings', 7, 3, 5, 1, 'NONE'),
|
||||||
|
(311, 311, 0, 9, 'macSettings', 7, 4, 5, 1, 'NONE'),
|
||||||
|
(312, 312, 0, 9, 'macSettings', 7, 5, 5, 1, 'NONE'),
|
||||||
|
(313, 313, 0, 9, 'macSettings', 7, 6, 5, 1, 'NONE'),
|
||||||
|
(314, 314, 0, 9, 'macSettings', 7, 7, 5, 1, 'NONE'),
|
||||||
|
(315, 315, 0, 9, 'macSettings', 7, 9, 5, 1, 'TOP'),
|
||||||
|
(316, 316, 0, 9, 'macSettings', 7, 10, 5, 1, 'NONE'),
|
||||||
|
|
||||||
|
(400, 400, 0, 10, 'registry', 0, 1, 4, 1, 'NONE'),
|
||||||
|
(401, 401, 0, 10, 'registry', 0, 2, 4, 1, 'NONE'),
|
||||||
|
(402, 402, 0, 10, 'registry', 0, 3, 4, 1, 'NONE'),
|
||||||
|
(403, 403, 0, 10, 'registry', 0, 4, 4, 1, 'NONE'),
|
||||||
|
(404, 404, 0, 10, 'registry', 0, 5, 4, 1, 'NONE'),
|
||||||
|
(405, 405, 0, 10, 'registry', 0, 6, 4, 1, 'NONE'),
|
||||||
|
(406, 406, 0, 10, 'registry', 0, 7, 4, 1, 'NONE'),
|
||||||
|
(407, 407, 0, 10, 'registry', 0, 8, 4, 1, 'NONE'),
|
||||||
|
(408, 408, 0, 10, 'registry', 0, 9, 4, 1, 'NONE'),
|
||||||
|
|
||||||
|
(500, 500, 0, 11, 'specialKeys', 0, 1, 3, 1, 'NONE'),
|
||||||
|
(501, 501, 0, 11, 'specialKeys', 0, 2, 3, 1, 'NONE'),
|
||||||
|
(502, 502, 0, 11, 'specialKeys', 0, 3, 3, 1, 'NONE'),
|
||||||
|
(503, 503, 0, 11, 'specialKeys', 0, 4, 3, 1, 'NONE'),
|
||||||
|
(504, 504, 0, 11, 'specialKeys', 0, 5, 3, 1, 'NONE'),
|
||||||
|
(505, 505, 0, 11, 'specialKeys', 0, 6, 3, 1, 'NONE'),
|
||||||
|
(506, 506, 0, 11, 'specialKeys', 0, 7, 3, 1, 'NONE'),
|
||||||
|
(507, 507, 0, 11, 'specialKeys', 0, 8, 3, 1, 'NONE'),
|
||||||
|
(508, 508, 0, 11, 'specialKeys', 0, 9, 3, 1, 'NONE'),
|
||||||
|
|
||||||
|
(509, 509, 0, 11, 'functionKeys', 3, 1, 3, 1, 'NONE'),
|
||||||
|
(510, 510, 0, 11, 'functionKeys', 3, 2, 3, 1, 'NONE'),
|
||||||
|
(511, 511, 0, 11, 'functionKeys', 3, 3, 3, 1, 'NONE'),
|
||||||
|
(512, 512, 0, 11, 'functionKeys', 3, 4, 3, 1, 'NONE'),
|
||||||
|
(513, 513, 0, 11, 'functionKeys', 3, 5, 3, 1, 'NONE'),
|
||||||
|
(514, 514, 0, 11, 'functionKeys', 3, 6, 3, 1, 'NONE'),
|
||||||
|
(515, 515, 0, 11, 'functionKeys', 3, 7, 3, 1, 'NONE'),
|
||||||
|
(516, 516, 0, 11, 'functionKeys', 3, 8, 3, 1, 'NONE'),
|
||||||
|
(517, 517, 0, 11, 'functionKeys', 3, 9, 3, 1, 'NONE'),
|
||||||
|
(518, 518, 0, 11, 'functionKeys', 3, 10, 3, 1, 'NONE'),
|
||||||
|
(519, 519, 0, 11, 'functionKeys', 3, 11, 3, 1, 'NONE'),
|
||||||
|
(520, 520, 0, 11, 'functionKeys', 3, 12, 3, 1, 'NONE')
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
INSERT IGNORE INTO configuration_node VALUES
|
||||||
|
(1, 1, 0, 'super-admin', 'test', null, 'EXAM_CONFIG', 'READY_TO_USE')
|
||||||
|
;
|
||||||
|
|
||||||
|
INSERT IGNORE INTO configuration VALUES
|
||||||
|
(1, 1, 1, 'v0', '2019-07-02 12:59:32', 0),
|
||||||
|
(2, 1, 1, null, null, 1)
|
||||||
|
;
|
||||||
|
|
||||||
|
INSERT IGNORE INTO configuration_value VALUES
|
||||||
|
(1,1,1,1,0,NULL),
|
||||||
|
(2,1,1,2,0,'true'),
|
||||||
|
(3,1,1,3,0,'false'),
|
||||||
|
(4,1,1,4,0,NULL),
|
||||||
|
(5,1,1,5,0,'2'),
|
||||||
|
(6,1,1,6,0,'10'),
|
||||||
|
(7,1,1,7,0,'5'),
|
||||||
|
(8,1,1,8,0,'0'),
|
||||||
|
(9,1,1,9,0,'false'),
|
||||||
|
(10,1,1,10,0,'100%'),
|
||||||
|
(11,1,1,11,0,'100%'),
|
||||||
|
(12,1,1,12,0,'1'),
|
||||||
|
(13,1,1,13,0,'false'),
|
||||||
|
(14,1,1,14,0,'false'),
|
||||||
|
(15,1,1,15,0,'false'),
|
||||||
|
(16,1,1,16,0,'true'),
|
||||||
|
(17,1,1,17,0,'40'),
|
||||||
|
(18,1,1,18,0,'true'),
|
||||||
|
(19,1,1,19,0,'true'),
|
||||||
|
(20,1,1,20,0,'false'),
|
||||||
|
(21,1,1,21,0,'true'),
|
||||||
|
(22,1,1,22,0,'true'),
|
||||||
|
(23,1,1,23,0,'0'),
|
||||||
|
(24,1,1,24,0,'false'),
|
||||||
|
(25,1,1,25,0,'false'),
|
||||||
|
(26,1,1,26,0,'false'),
|
||||||
|
(27,1,1,27,0,'25'),
|
||||||
|
(28,1,1,28,0,'false'),
|
||||||
|
(29,1,1,29,0,'false'),
|
||||||
|
(30,1,1,30,0,'da-DK,en-AU,en-GB,en-US,es-ES,fr-FR,pt-PT,sv-SE,sv-FI'),
|
||||||
|
(31,1,1,31,0,'2'),
|
||||||
|
(32,1,1,32,0,'false'),
|
||||||
|
(33,1,1,33,0,'100%'),
|
||||||
|
(34,1,1,34,0,'100%'),
|
||||||
|
(35,1,1,35,0,'2'),
|
||||||
|
(36,1,1,36,0,'true'),
|
||||||
|
(37,1,1,37,0,'true'),
|
||||||
|
(38,1,1,38,0,'false'),
|
||||||
|
(39,1,1,39,0,'false'),
|
||||||
|
(40,1,1,40,0,'false'),
|
||||||
|
(41,1,1,41,0,'false'),
|
||||||
|
(42,1,1,42,0,'false'),
|
||||||
|
(43,1,1,43,0,'true'),
|
||||||
|
(44,1,1,44,0,'true'),
|
||||||
|
(45,1,1,45,0,'true'),
|
||||||
|
(46,1,1,46,0,'true'),
|
||||||
|
(47,1,1,47,0,'false'),
|
||||||
|
(48,1,1,48,0,'false'),
|
||||||
|
(49,1,1,49,0,'false'),
|
||||||
|
(50,1,1,50,0,NULL),
|
||||||
|
(51,1,1,51,0,'0'),
|
||||||
|
(52,1,1,52,0,NULL),
|
||||||
|
(53,1,1,53,0,'0'),
|
||||||
|
(54,1,1,54,0,NULL),
|
||||||
|
(55,1,1,55,0,'0'),
|
||||||
|
(56,1,1,56,0,NULL),
|
||||||
|
(57,1,1,57,0,'true'),
|
||||||
|
(58,1,1,58,0,NULL),
|
||||||
|
(59,1,1,59,0,'true'),
|
||||||
|
(60,1,1,60,0,NULL),
|
||||||
|
(61,1,1,61,0,NULL),
|
||||||
|
(62,1,1,62,0,'false'),
|
||||||
|
(63,1,1,63,0,'0'),
|
||||||
|
(64,1,1,64,0,'true'),
|
||||||
|
(65,1,1,65,0,'true'),
|
||||||
|
(66,1,1,66,0,'true'),
|
||||||
|
(67,1,1,67,0,NULL),
|
||||||
|
(68,1,1,68,0,'true'),
|
||||||
|
(69,1,1,69,0,'false'),
|
||||||
|
(70,1,1,70,0,NULL),
|
||||||
|
(71,1,1,71,0,NULL),
|
||||||
|
(72,1,1,72,0,'true'),
|
||||||
|
(73,1,1,73,0,NULL),
|
||||||
|
(74,1,1,91,0,'false'),
|
||||||
|
(75,1,1,92,0,'false'),
|
||||||
|
(76,1,1,93,0,NULL),
|
||||||
|
(77,1,1,200,0,'false'),
|
||||||
|
(78,1,1,201,0,'false'),
|
||||||
|
(79,1,1,202,0,NULL),
|
||||||
|
(80,1,1,210,0,'0'),
|
||||||
|
(81,1,1,220,0,NULL),
|
||||||
|
(82,1,1,221,0,'false'),
|
||||||
|
(83,1,1,222,0,NULL),
|
||||||
|
(84,1,1,223,0,'true'),
|
||||||
|
(85,1,1,231,0,'false'),
|
||||||
|
(86,1,1,233,0,'false'),
|
||||||
|
(87,1,1,234,0,NULL),
|
||||||
|
(88,1,1,235,0,NULL),
|
||||||
|
(89,1,1,236,0,'false'),
|
||||||
|
(90,1,1,237,0,NULL),
|
||||||
|
(91,1,1,238,0,'80'),
|
||||||
|
(92,1,1,239,0,'false'),
|
||||||
|
(93,1,1,240,0,NULL),
|
||||||
|
(94,1,1,241,0,NULL),
|
||||||
|
(95,1,1,242,0,'false'),
|
||||||
|
(96,1,1,243,0,NULL),
|
||||||
|
(97,1,1,244,0,'443'),
|
||||||
|
(98,1,1,245,0,'false'),
|
||||||
|
(99,1,1,246,0,NULL),
|
||||||
|
(100,1,1,247,0,NULL),
|
||||||
|
(101,1,1,248,0,'false'),
|
||||||
|
(102,1,1,249,0,NULL),
|
||||||
|
(103,1,1,250,0,'21'),
|
||||||
|
(104,1,1,251,0,'false'),
|
||||||
|
(105,1,1,252,0,NULL),
|
||||||
|
(106,1,1,253,0,NULL),
|
||||||
|
(107,1,1,254,0,'false'),
|
||||||
|
(108,1,1,255,0,NULL),
|
||||||
|
(109,1,1,256,0,'1080'),
|
||||||
|
(110,1,1,257,0,'false'),
|
||||||
|
(111,1,1,258,0,NULL),
|
||||||
|
(112,1,1,259,0,NULL),
|
||||||
|
(113,1,1,260,0,'false'),
|
||||||
|
(114,1,1,261,0,NULL),
|
||||||
|
(115,1,1,262,0,'1080'),
|
||||||
|
(116,1,1,263,0,'false'),
|
||||||
|
(117,1,1,264,0,NULL),
|
||||||
|
(118,1,1,265,0,NULL),
|
||||||
|
(119,1,1,300,0,'2'),
|
||||||
|
(120,1,1,301,0,'0'),
|
||||||
|
(121,1,1,302,0,'false'),
|
||||||
|
(122,1,1,303,0,'false'),
|
||||||
|
(123,1,1,304,0,'true'),
|
||||||
|
(124,1,1,305,0,'false'),
|
||||||
|
(125,1,1,306,0,''),
|
||||||
|
(126,1,1,307,0,'~/Documents'),
|
||||||
|
(127,1,1,308,0,'0'),
|
||||||
|
(128,1,1,309,0,'true'),
|
||||||
|
(129,1,1,310,0,'true'),
|
||||||
|
(130,1,1,311,0,'false'),
|
||||||
|
(131,1,1,312,0,'false'),
|
||||||
|
(132,1,1,313,0,'true'),
|
||||||
|
(133,1,1,314,0,'false'),
|
||||||
|
(134,1,1,315,0,'1'),
|
||||||
|
(135,1,1,316,0,'true'),
|
||||||
|
(136,1,1,400,0,'false'),
|
||||||
|
(137,1,1,401,0,'false'),
|
||||||
|
(138,1,1,402,0,'false'),
|
||||||
|
(139,1,1,403,0,'false'),
|
||||||
|
(140,1,1,404,0,'false'),
|
||||||
|
(141,1,1,405,0,'false'),
|
||||||
|
(142,1,1,406,0,'false'),
|
||||||
|
(143,1,1,407,0,'false'),
|
||||||
|
(144,1,1,408,0,'false'),
|
||||||
|
(145,1,1,500,0,'false'),
|
||||||
|
(146,1,1,501,0,'false'),
|
||||||
|
(147,1,1,502,0,'false'),
|
||||||
|
(148,1,1,503,0,'false'),
|
||||||
|
(149,1,1,504,0,'true'),
|
||||||
|
(150,1,1,505,0,'false'),
|
||||||
|
(151,1,1,506,0,'false'),
|
||||||
|
(152,1,1,507,0,'false'),
|
||||||
|
(153,1,1,508,0,'false'),
|
||||||
|
(154,1,1,509,0,'false'),
|
||||||
|
(155,1,1,510,0,'false'),
|
||||||
|
(156,1,1,511,0,'false'),
|
||||||
|
(157,1,1,512,0,'false'),
|
||||||
|
(158,1,1,513,0,'false'),
|
||||||
|
(159,1,1,514,0,'false'),
|
||||||
|
(160,1,1,515,0,'false'),
|
||||||
|
(161,1,1,516,0,'false'),
|
||||||
|
(162,1,1,517,0,'false'),
|
||||||
|
(163,1,1,518,0,'false'),
|
||||||
|
(164,1,1,519,0,'false'),
|
||||||
|
(165,1,1,520,0,'false'),
|
||||||
|
(166,1,1,1000,0,'SEB_Server_0.3.0'),
|
||||||
|
(167,1,1,1001,0,'0'),
|
||||||
|
(168,1,2,1,0,NULL),
|
||||||
|
(169,1,2,2,0,'true'),
|
||||||
|
(170,1,2,3,0,'false'),
|
||||||
|
(171,1,2,4,0,NULL),
|
||||||
|
(172,1,2,5,0,'2'),
|
||||||
|
(173,1,2,6,0,'10'),
|
||||||
|
(174,1,2,7,0,'5'),
|
||||||
|
(175,1,2,8,0,'0'),
|
||||||
|
(176,1,2,9,0,'false'),
|
||||||
|
(177,1,2,10,0,'100%'),
|
||||||
|
(178,1,2,11,0,'100%'),
|
||||||
|
(179,1,2,12,0,'1'),
|
||||||
|
(180,1,2,13,0,'false'),
|
||||||
|
(181,1,2,14,0,'false'),
|
||||||
|
(182,1,2,15,0,'false'),
|
||||||
|
(183,1,2,16,0,'true'),
|
||||||
|
(184,1,2,17,0,'40'),
|
||||||
|
(185,1,2,18,0,'true'),
|
||||||
|
(186,1,2,19,0,'true'),
|
||||||
|
(187,1,2,20,0,'false'),
|
||||||
|
(188,1,2,21,0,'true'),
|
||||||
|
(189,1,2,22,0,'true'),
|
||||||
|
(190,1,2,23,0,'0'),
|
||||||
|
(191,1,2,24,0,'false'),
|
||||||
|
(192,1,2,25,0,'false'),
|
||||||
|
(193,1,2,26,0,'false'),
|
||||||
|
(194,1,2,27,0,'25'),
|
||||||
|
(195,1,2,28,0,'false'),
|
||||||
|
(196,1,2,29,0,'false'),
|
||||||
|
(197,1,2,30,0,'da-DK,en-AU,en-GB,en-US,es-ES,fr-FR,pt-PT,sv-SE,sv-FI'),
|
||||||
|
(198,1,2,31,0,'2'),
|
||||||
|
(199,1,2,32,0,'false'),
|
||||||
|
(200,1,2,33,0,'100%'),
|
||||||
|
(201,1,2,34,0,'100%'),
|
||||||
|
(202,1,2,35,0,'2'),
|
||||||
|
(203,1,2,36,0,'true'),
|
||||||
|
(204,1,2,37,0,'true'),
|
||||||
|
(205,1,2,38,0,'false'),
|
||||||
|
(206,1,2,39,0,'false'),
|
||||||
|
(207,1,2,40,0,'false'),
|
||||||
|
(208,1,2,41,0,'false'),
|
||||||
|
(209,1,2,42,0,'false'),
|
||||||
|
(210,1,2,43,0,'true'),
|
||||||
|
(211,1,2,44,0,'true'),
|
||||||
|
(212,1,2,45,0,'true'),
|
||||||
|
(213,1,2,46,0,'true'),
|
||||||
|
(214,1,2,47,0,'false'),
|
||||||
|
(215,1,2,48,0,'false'),
|
||||||
|
(216,1,2,49,0,'false'),
|
||||||
|
(217,1,2,50,0,NULL),
|
||||||
|
(218,1,2,51,0,'0'),
|
||||||
|
(219,1,2,52,0,NULL),
|
||||||
|
(220,1,2,53,0,'0'),
|
||||||
|
(221,1,2,54,0,NULL),
|
||||||
|
(222,1,2,55,0,'0'),
|
||||||
|
(223,1,2,56,0,NULL),
|
||||||
|
(224,1,2,57,0,'true'),
|
||||||
|
(225,1,2,58,0,NULL),
|
||||||
|
(226,1,2,59,0,'true'),
|
||||||
|
(227,1,2,60,0,NULL),
|
||||||
|
(228,1,2,61,0,NULL),
|
||||||
|
(229,1,2,62,0,'false'),
|
||||||
|
(230,1,2,63,0,'0'),
|
||||||
|
(231,1,2,64,0,'true'),
|
||||||
|
(232,1,2,65,0,'true'),
|
||||||
|
(233,1,2,66,0,'true'),
|
||||||
|
(234,1,2,67,0,NULL),
|
||||||
|
(235,1,2,68,0,'true'),
|
||||||
|
(236,1,2,69,0,'false'),
|
||||||
|
(237,1,2,70,0,NULL),
|
||||||
|
(238,1,2,71,0,NULL),
|
||||||
|
(239,1,2,72,0,'true'),
|
||||||
|
(240,1,2,73,0,NULL),
|
||||||
|
(241,1,2,91,0,'false'),
|
||||||
|
(242,1,2,92,0,'false'),
|
||||||
|
(243,1,2,93,0,NULL),
|
||||||
|
(244,1,2,200,0,'false'),
|
||||||
|
(245,1,2,201,0,'false'),
|
||||||
|
(246,1,2,202,0,NULL),
|
||||||
|
(247,1,2,210,0,'0'),
|
||||||
|
(248,1,2,220,0,NULL),
|
||||||
|
(249,1,2,221,0,'false'),
|
||||||
|
(250,1,2,222,0,NULL),
|
||||||
|
(251,1,2,223,0,'true'),
|
||||||
|
(252,1,2,231,0,'false'),
|
||||||
|
(253,1,2,233,0,'false'),
|
||||||
|
(254,1,2,234,0,NULL),
|
||||||
|
(255,1,2,235,0,NULL),
|
||||||
|
(256,1,2,236,0,'false'),
|
||||||
|
(257,1,2,237,0,NULL),
|
||||||
|
(258,1,2,238,0,'80'),
|
||||||
|
(259,1,2,239,0,'false'),
|
||||||
|
(260,1,2,240,0,NULL),
|
||||||
|
(261,1,2,241,0,NULL),
|
||||||
|
(262,1,2,242,0,'false'),
|
||||||
|
(263,1,2,243,0,NULL),
|
||||||
|
(264,1,2,244,0,'443'),
|
||||||
|
(265,1,2,245,0,'false'),
|
||||||
|
(266,1,2,246,0,NULL),
|
||||||
|
(267,1,2,247,0,NULL),
|
||||||
|
(268,1,2,248,0,'false'),
|
||||||
|
(269,1,2,249,0,NULL),
|
||||||
|
(270,1,2,250,0,'21'),
|
||||||
|
(271,1,2,251,0,'false'),
|
||||||
|
(272,1,2,252,0,NULL),
|
||||||
|
(273,1,2,253,0,NULL),
|
||||||
|
(274,1,2,254,0,'false'),
|
||||||
|
(275,1,2,255,0,NULL),
|
||||||
|
(276,1,2,256,0,'1080'),
|
||||||
|
(277,1,2,257,0,'false'),
|
||||||
|
(278,1,2,258,0,NULL),
|
||||||
|
(279,1,2,259,0,NULL),
|
||||||
|
(280,1,2,260,0,'false'),
|
||||||
|
(281,1,2,261,0,NULL),
|
||||||
|
(282,1,2,262,0,'1080'),
|
||||||
|
(283,1,2,263,0,'false'),
|
||||||
|
(284,1,2,264,0,NULL),
|
||||||
|
(285,1,2,265,0,NULL),
|
||||||
|
(286,1,2,300,0,'2'),
|
||||||
|
(287,1,2,301,0,'0'),
|
||||||
|
(288,1,2,302,0,'false'),
|
||||||
|
(289,1,2,303,0,'false'),
|
||||||
|
(290,1,2,304,0,'true'),
|
||||||
|
(291,1,2,305,0,'false'),
|
||||||
|
(292,1,2,306,0,''),
|
||||||
|
(293,1,2,307,0,'~/Documents'),
|
||||||
|
(294,1,2,308,0,'0'),
|
||||||
|
(295,1,2,309,0,'true'),
|
||||||
|
(296,1,2,310,0,'true'),
|
||||||
|
(297,1,2,311,0,'false'),
|
||||||
|
(298,1,2,312,0,'false'),
|
||||||
|
(299,1,2,313,0,'true'),
|
||||||
|
(300,1,2,314,0,'false'),
|
||||||
|
(301,1,2,315,0,'1'),
|
||||||
|
(302,1,2,316,0,'true'),
|
||||||
|
(303,1,2,400,0,'false'),
|
||||||
|
(304,1,2,401,0,'false'),
|
||||||
|
(305,1,2,402,0,'false'),
|
||||||
|
(306,1,2,403,0,'false'),
|
||||||
|
(307,1,2,404,0,'false'),
|
||||||
|
(308,1,2,405,0,'false'),
|
||||||
|
(309,1,2,406,0,'false'),
|
||||||
|
(310,1,2,407,0,'false'),
|
||||||
|
(311,1,2,408,0,'false'),
|
||||||
|
(312,1,2,500,0,'false'),
|
||||||
|
(313,1,2,501,0,'false'),
|
||||||
|
(314,1,2,502,0,'false'),
|
||||||
|
(315,1,2,503,0,'false'),
|
||||||
|
(316,1,2,504,0,'true'),
|
||||||
|
(317,1,2,505,0,'false'),
|
||||||
|
(318,1,2,506,0,'false'),
|
||||||
|
(319,1,2,507,0,'false'),
|
||||||
|
(320,1,2,508,0,'false'),
|
||||||
|
(321,1,2,509,0,'false'),
|
||||||
|
(322,1,2,510,0,'false'),
|
||||||
|
(323,1,2,511,0,'false'),
|
||||||
|
(324,1,2,512,0,'false'),
|
||||||
|
(325,1,2,513,0,'false'),
|
||||||
|
(326,1,2,514,0,'false'),
|
||||||
|
(327,1,2,515,0,'false'),
|
||||||
|
(328,1,2,516,0,'false'),
|
||||||
|
(329,1,2,517,0,'false'),
|
||||||
|
(330,1,2,518,0,'false'),
|
||||||
|
(331,1,2,519,0,'false'),
|
||||||
|
(332,1,2,520,0,'false'),
|
||||||
|
(333,1,2,1000,0,'SEB_Server_0.3.0'),
|
||||||
|
(334,1,2,1001,0,'0')
|
||||||
|
;
|
||||||
|
|
||||||
|
INSERT IGNORE INTO exam_configuration_map VALUES
|
||||||
|
(1, 1, 2, 1, null, null)
|
||||||
|
;
|
||||||
|
|
|
@ -84,21 +84,26 @@ DROP TABLE IF EXISTS `client_connection` ;
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `client_connection` (
|
CREATE TABLE IF NOT EXISTS `client_connection` (
|
||||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
`institution_id` BIGINT UNSIGNED NOT NULL,
|
||||||
`exam_id` BIGINT UNSIGNED NULL,
|
`exam_id` BIGINT UNSIGNED NULL,
|
||||||
`status` VARCHAR(45) NOT NULL,
|
`status` VARCHAR(45) NOT NULL,
|
||||||
`connection_token` VARCHAR(255) NOT NULL,
|
`connection_token` VARCHAR(255) NOT NULL,
|
||||||
`user_name` VARCHAR(255) NOT NULL,
|
`exam_user_session_identifer` VARCHAR(255) NULL,
|
||||||
`VDI` BIT(1) NOT NULL,
|
|
||||||
`client_address` VARCHAR(45) NOT NULL,
|
`client_address` VARCHAR(45) NOT NULL,
|
||||||
`virtual_client_address` VARCHAR(45) NULL,
|
`virtual_client_address` VARCHAR(45) NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
INDEX `connection_exam_ref_idx` (`exam_id` ASC),
|
INDEX `connection_exam_ref_idx` (`exam_id` ASC),
|
||||||
|
INDEX `clientConnectionInstitutionRef_idx` (`institution_id` ASC),
|
||||||
CONSTRAINT `clientConnectionExamRef`
|
CONSTRAINT `clientConnectionExamRef`
|
||||||
FOREIGN KEY (`exam_id`)
|
FOREIGN KEY (`exam_id`)
|
||||||
REFERENCES `exam` (`id`)
|
REFERENCES `exam` (`id`)
|
||||||
ON DELETE NO ACTION
|
ON DELETE NO ACTION
|
||||||
ON UPDATE NO ACTION)
|
ON UPDATE NO ACTION,
|
||||||
;
|
CONSTRAINT `clientConnectionInstitutionRef`
|
||||||
|
FOREIGN KEY (`institution_id`)
|
||||||
|
REFERENCES `institution` (`id`)
|
||||||
|
ON DELETE NO ACTION
|
||||||
|
ON UPDATE NO ACTION);
|
||||||
|
|
||||||
|
|
||||||
-- -----------------------------------------------------
|
-- -----------------------------------------------------
|
||||||
|
|
Loading…
Reference in a new issue