SEBSERV-270 fixed and service test and validation improvements

This commit is contained in:
anhefti 2022-02-28 13:44:46 +01:00
parent f0166afd6a
commit 1d6bd86b57
7 changed files with 48 additions and 38 deletions

View file

@ -11,6 +11,7 @@ package ch.ethz.seb.sebserver.gbl.model.exam;
import java.util.EnumSet; import java.util.EnumSet;
import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.validator.constraints.URL; import org.hibernate.validator.constraints.URL;
import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonCreator;
@ -110,9 +111,9 @@ public class ProctoringServiceSettings implements Entity {
this.collectingRoomSize = (collectingRoomSize != null) ? collectingRoomSize : 20; this.collectingRoomSize = (collectingRoomSize != null) ? collectingRoomSize : 20;
this.enabledFeatures = enabledFeatures != null ? enabledFeatures : EnumSet.allOf(ProctoringFeature.class); this.enabledFeatures = enabledFeatures != null ? enabledFeatures : EnumSet.allOf(ProctoringFeature.class);
this.serviceInUse = serviceInUse; this.serviceInUse = serviceInUse;
this.appKey = appKey; this.appKey = StringUtils.trim(appKey);
this.appSecret = appSecret; this.appSecret = appSecret;
this.sdkKey = sdkKey; this.sdkKey = StringUtils.trim(sdkKey);
this.sdkSecret = sdkSecret; this.sdkSecret = sdkSecret;
this.useZoomAppClientForCollectingRoom = BooleanUtils.toBoolean(useZoomAppClientForCollectingRoom); this.useZoomAppClientForCollectingRoom = BooleanUtils.toBoolean(useZoomAppClientForCollectingRoom);
} }

View file

@ -265,12 +265,14 @@ public class ExamProctoringSettings {
.addField(FormBuilder.text( .addField(FormBuilder.text(
ProctoringServiceSettings.ATTR_SERVER_URL, ProctoringServiceSettings.ATTR_SERVER_URL,
SEB_PROCTORING_FORM_URL, SEB_PROCTORING_FORM_URL,
proctoringSettings.serverURL)) proctoringSettings.serverURL)
.mandatory())
.addField(FormBuilder.text( .addField(FormBuilder.text(
ProctoringServiceSettings.ATTR_APP_KEY, ProctoringServiceSettings.ATTR_APP_KEY,
SEB_PROCTORING_FORM_APPKEY, SEB_PROCTORING_FORM_APPKEY,
proctoringSettings.appKey)) proctoringSettings.appKey)
.mandatory())
.withEmptyCellSeparation(false) .withEmptyCellSeparation(false)
.addField(FormBuilder.password( .addField(FormBuilder.password(
@ -278,7 +280,8 @@ public class ExamProctoringSettings {
SEB_PROCTORING_FORM_SECRET, SEB_PROCTORING_FORM_SECRET,
(proctoringSettings.appSecret != null) (proctoringSettings.appSecret != null)
? String.valueOf(proctoringSettings.appSecret) ? String.valueOf(proctoringSettings.appSecret)
: null)) : null)
.mandatory())
.addField(FormBuilder.text( .addField(FormBuilder.text(
ProctoringServiceSettings.ATTR_SDK_KEY, ProctoringServiceSettings.ATTR_SDK_KEY,

View file

@ -141,25 +141,40 @@ public class JitsiProctoringService implements ExamProctoringService {
"proctoringSettings:serverURL:invalidURL"); "proctoringSettings:serverURL:invalidURL");
} }
if (StringUtils.isBlank(proctoringSettings.appKey)) {
throw new APIMessageException(Arrays.asList(
APIMessage.fieldValidationError(ProctoringServiceSettings.ATTR_APP_KEY,
"proctoringSettings:appKey:notNull"),
APIMessage.ErrorMessage.EXTERNAL_SERVICE_BINDING_ERROR.of()));
}
if (StringUtils.isBlank(proctoringSettings.appSecret)) {
throw new APIMessageException(Arrays.asList(
APIMessage.fieldValidationError(ProctoringServiceSettings.ATTR_APP_SECRET,
"proctoringSettings:appSecret:notNull"),
APIMessage.ErrorMessage.EXTERNAL_SERVICE_BINDING_ERROR.of()));
}
final ClientHttpRequestFactory clientHttpRequestFactory = this.clientHttpRequestFactoryService final ClientHttpRequestFactory clientHttpRequestFactory = this.clientHttpRequestFactoryService
.getClientHttpRequestFactory() .getClientHttpRequestFactory()
.getOrThrow(); .getOrThrow();
try { try {
final String testURL = proctoringSettings.serverURL + "/external_api.js";
final RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory); final RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);
final ResponseEntity<String> result = final ResponseEntity<String> result =
restTemplate.getForEntity(proctoringSettings.serverURL, String.class); restTemplate.getForEntity(testURL, String.class);
if (result.getStatusCode() != HttpStatus.OK) { if (result.getStatusCode() != HttpStatus.OK) {
throw new APIMessageException(Arrays.asList( throw new APIMessageException(Arrays.asList(
APIMessage.fieldValidationError(ProctoringServiceSettings.ATTR_SERVER_URL, APIMessage.fieldValidationError(ProctoringServiceSettings.ATTR_SERVER_URL,
"proctoringSettings:serverURL:url.invalid"), "proctoringSettings:serverURL:url.noservice"),
APIMessage.ErrorMessage.EXTERNAL_SERVICE_BINDING_ERROR.of())); APIMessage.ErrorMessage.EXTERNAL_SERVICE_BINDING_ERROR.of()));
} }
} catch (final Exception e) { } catch (final Exception e) {
log.error("Failed to access proctoring service: {}", e.getMessage()); log.error("Failed to access proctoring service: {}", e.getMessage());
throw new APIMessageException(Arrays.asList( throw new APIMessageException(Arrays.asList(
APIMessage.fieldValidationError(ProctoringServiceSettings.ATTR_SERVER_URL, APIMessage.fieldValidationError(ProctoringServiceSettings.ATTR_SERVER_URL,
"proctoringSettings:serverURL:url.invalid"), "proctoringSettings:serverURL:url.noservice"),
APIMessage.ErrorMessage.EXTERNAL_SERVICE_BINDING_ERROR.of(e))); APIMessage.ErrorMessage.EXTERNAL_SERVICE_BINDING_ERROR.of(e)));
} }

View file

@ -172,6 +172,20 @@ public class ZoomProctoringService implements ExamProctoringService {
"proctoringSettings:serverURL:invalidURL"); "proctoringSettings:serverURL:invalidURL");
} }
if (StringUtils.isBlank(proctoringSettings.appKey)) {
throw new APIMessageException(Arrays.asList(
APIMessage.fieldValidationError(ProctoringServiceSettings.ATTR_APP_KEY,
"proctoringSettings:appKey:notNull"),
APIMessage.ErrorMessage.EXTERNAL_SERVICE_BINDING_ERROR.of()));
}
if (StringUtils.isBlank(proctoringSettings.appSecret)) {
throw new APIMessageException(Arrays.asList(
APIMessage.fieldValidationError(ProctoringServiceSettings.ATTR_APP_SECRET,
"proctoringSettings:appSecret:notNull"),
APIMessage.ErrorMessage.EXTERNAL_SERVICE_BINDING_ERROR.of()));
}
try { try {
final ClientCredentials credentials = new ClientCredentials( final ClientCredentials credentials = new ClientCredentials(
@ -192,10 +206,10 @@ public class ZoomProctoringService implements ExamProctoringService {
APIMessage.ErrorMessage.EXTERNAL_SERVICE_BINDING_ERROR.of())); APIMessage.ErrorMessage.EXTERNAL_SERVICE_BINDING_ERROR.of()));
} }
} catch (final Exception e) { } catch (final Exception e) {
log.error("Failed to access Zoom service at: {}", proctoringSettings.serverURL, e); log.error("Failed to access Zoom service at: {}", proctoringSettings.serverURL, e.getMessage());
throw new APIMessageException(Arrays.asList( throw new APIMessageException(Arrays.asList(
APIMessage.fieldValidationError(ProctoringServiceSettings.ATTR_SERVER_URL, APIMessage.fieldValidationError(ProctoringServiceSettings.ATTR_SERVER_URL,
"proctoringSettings:serverURL:url.invalid"), "proctoringSettings:serverURL:url.noservice"),
APIMessage.ErrorMessage.EXTERNAL_SERVICE_BINDING_ERROR.of())); APIMessage.ErrorMessage.EXTERNAL_SERVICE_BINDING_ERROR.of()));
} }

View file

@ -16,7 +16,8 @@ import org.apache.commons.lang3.StringUtils;
import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringServiceSettings; import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringServiceSettings;
import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringServiceSettings.ProctoringServerType; import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringServiceSettings.ProctoringServerType;
public class ProctoringSettingsValidator implements ConstraintValidator<ValidProctoringSettings, ProctoringServiceSettings> { public class ProctoringSettingsValidator
implements ConstraintValidator<ValidProctoringSettings, ProctoringServiceSettings> {
@Override @Override
public boolean isValid(final ProctoringServiceSettings value, final ConstraintValidatorContext context) { public boolean isValid(final ProctoringServiceSettings value, final ConstraintValidatorContext context) {
@ -25,33 +26,8 @@ public class ProctoringSettingsValidator implements ConstraintValidator<ValidPro
} }
if (value.enableProctoring) { if (value.enableProctoring) {
if (value.serverType == ProctoringServerType.JITSI_MEET) { if (value.serverType == ProctoringServerType.JITSI_MEET || value.serverType == ProctoringServerType.ZOOM) {
boolean passed = true; boolean passed = true;
if (StringUtils.isBlank(value.serverURL)) {
context.disableDefaultConstraintViolation();
context
.buildConstraintViolationWithTemplate("proctoringSettings:serverURL:notNull")
.addPropertyNode("serverURL").addConstraintViolation();
passed = false;
}
// try {
//
// if (!InetAddress.getByName(new URI(value.serverURL).getHost()).isReachable(5000)) {
// context.disableDefaultConstraintViolation();
// context
// .buildConstraintViolationWithTemplate("proctoringSettings:serverURL:serverNotAvailable")
// .addPropertyNode("serverURL").addConstraintViolation();
// passed = false;
// }
// } catch (final Exception e) {
// context.disableDefaultConstraintViolation();
// context
// .buildConstraintViolationWithTemplate("proctoringSettings:serverURL:serverNotAvailable")
// .addPropertyNode("serverURL").addConstraintViolation();
// passed = false;
// }
if (StringUtils.isBlank(value.appKey)) { if (StringUtils.isBlank(value.appKey)) {
context.disableDefaultConstraintViolation(); context.disableDefaultConstraintViolation();
context context

View file

@ -379,7 +379,7 @@ public class ExamAdministrationController extends EntityController<Exam, Exam> {
return this.entityDAO.byPK(examId) return this.entityDAO.byPK(examId)
.flatMap(this.authorization::checkModify) .flatMap(this.authorization::checkModify)
.map(exam -> { .map(exam -> {
if (proctoringServiceSettings.enableProctoring) { if (StringUtils.isNotBlank(proctoringServiceSettings.serverURL)) {
this.examAdminService.getExamProctoringService(proctoringServiceSettings.serverType) this.examAdminService.getExamProctoringService(proctoringServiceSettings.serverType)
.flatMap(service -> service.testExamProctoring(proctoringServiceSettings)) .flatMap(service -> service.testExamProctoring(proctoringServiceSettings))
.getOrThrow(); .getOrThrow();

View file

@ -95,6 +95,7 @@ sebserver.form.validation.fieldError.exists=This name already exists. Please cho
sebserver.form.validation.fieldError.email=Invalid mail address sebserver.form.validation.fieldError.email=Invalid mail address
sebserver.form.validation.fieldError.serverNotAvailable=No service seems to be available within the given URL sebserver.form.validation.fieldError.serverNotAvailable=No service seems to be available within the given URL
sebserver.form.validation.fieldError.url.invalid=Invalid URL. The given URL cannot be reached. sebserver.form.validation.fieldError.url.invalid=Invalid URL. The given URL cannot be reached.
sebserver.form.validation.fieldError.url.noservice=The expected service is not available within the given URL and API access.
sebserver.form.validation.fieldError.thresholdDuplicate=There are duplicate threshold values. sebserver.form.validation.fieldError.thresholdDuplicate=There are duplicate threshold values.
sebserver.form.validation.fieldError.thresholdEmpty=There are empty threshold entries. sebserver.form.validation.fieldError.thresholdEmpty=There are empty threshold entries.
sebserver.error.unexpected=Unexpected Error sebserver.error.unexpected=Unexpected Error