improved SEB Restriction handling error handling and logging

This commit is contained in:
anhefti 2023-12-14 12:12:49 +01:00
parent 0544d7a799
commit fc310597e6
19 changed files with 77 additions and 139 deletions

View file

@ -177,9 +177,7 @@ public final class CircuitBreaker<T> {
this.state = State.HALF_OPEN; this.state = State.HALF_OPEN;
this.failingCount.set(0); this.failingCount.set(0);
return Result.ofError(new RuntimeException( return result;
"Set CircuitBeaker to half-open state. Cause: " + result.getError(),
result.getError()));
} else { } else {
// try again // try again
return protectedRun(supplier); return protectedRun(supplier);
@ -258,7 +256,7 @@ public final class CircuitBreaker<T> {
return Result.ofError(e); return Result.ofError(e);
} catch (final ExecutionException e) { } catch (final ExecutionException e) {
future.cancel(false); future.cancel(false);
if (log.isWarnEnabled()) { if (log.isDebugEnabled()) {
log.warn("Attempt error: {}, {}", e.getMessage(), this.state); log.warn("Attempt error: {}, {}", e.getMessage(), this.state);
} }
final Throwable cause = e.getCause(); final Throwable cause = e.getCause();

View file

@ -142,7 +142,8 @@ public final class Result<T> {
if (this.error instanceof RuntimeException) { if (this.error instanceof RuntimeException) {
throw (RuntimeException) this.error; throw (RuntimeException) this.error;
} else { } else {
throw new RuntimeException("RuntimeExceptionWrapper cause: " + this.error.getMessage(), this.error); String cause = this.error.getMessage() != null ? this.error.getMessage() : this.error.toString();
throw new RuntimeException("RuntimeExceptionWrapper cause: " + cause, this.error);
} }
} }

View file

@ -238,7 +238,7 @@ public class ExamForm implements TemplateComposer {
.withURIVariable(API.PARAM_MODEL_ID, exam.getModelId()) .withURIVariable(API.PARAM_MODEL_ID, exam.getModelId())
.call() .call()
.onError(e -> log.error("Unexpected error while trying to verify seb restriction settings: ", e)) .onError(e -> log.error("Unexpected error while trying to verify seb restriction settings: ", e))
.getOr(false); .getOr(exam.sebRestriction);
final boolean sebRestrictionMismatch = readonly && final boolean sebRestrictionMismatch = readonly &&
sebRestrictionAvailable && sebRestrictionAvailable &&
isRestricted != exam.sebRestriction && isRestricted != exam.sebRestriction &&
@ -525,7 +525,6 @@ public class ExamForm implements TemplateComposer {
final boolean newExam = exam.id == null; final boolean newExam = exam.id == null;
final boolean hasLMS = exam.lmsSetupId != null; final boolean hasLMS = exam.lmsSetupId != null;
final boolean importFromLMS = newExam && hasLMS; final boolean importFromLMS = newExam && hasLMS;
final DateTimeZone timeZone = this.pageService.getCurrentUser().get().timeZone;
final LocTextKey statusTitle = new LocTextKey("sebserver.exam.status." + exam.status.name()); final LocTextKey statusTitle = new LocTextKey("sebserver.exam.status." + exam.status.name());
return this.pageService.formBuilder(formContext.copyOf(content)) return this.pageService.formBuilder(formContext.copyOf(content))
@ -585,9 +584,7 @@ public class ExamForm implements TemplateComposer {
exam.getDescription()) exam.getDescription())
.asArea() .asArea()
.readonly(hasLMS)) .readonly(hasLMS))
.withAdditionalValueMapping( .withAdditionalValueMapping(QuizData.QUIZ_ATTR_DESCRIPTION)
QuizData.QUIZ_ATTR_DESCRIPTION,
QuizData.QUIZ_ATTR_DESCRIPTION)
.addField(FormBuilder.dateTime( .addField(FormBuilder.dateTime(
Domain.EXAM.ATTR_QUIZ_START_TIME, Domain.EXAM.ATTR_QUIZ_START_TIME,
@ -599,11 +596,8 @@ public class ExamForm implements TemplateComposer {
.addField(FormBuilder.dateTime( .addField(FormBuilder.dateTime(
Domain.EXAM.ATTR_QUIZ_END_TIME, Domain.EXAM.ATTR_QUIZ_END_TIME,
FORM_END_TIME_TEXT_KEY, FORM_END_TIME_TEXT_KEY,
exam.endTime != null exam.endTime)
? exam.endTime .readonly(hasLMS))
: DateTime.now(timeZone).plusHours(1))
.readonly(hasLMS)
.mandatory(!hasLMS))
.addField(FormBuilder.text( .addField(FormBuilder.text(
QuizData.QUIZ_ATTR_START_URL, QuizData.QUIZ_ATTR_START_URL,
@ -611,9 +605,7 @@ public class ExamForm implements TemplateComposer {
exam.getStartURL()) exam.getStartURL())
.readonly(hasLMS) .readonly(hasLMS)
.mandatory(!hasLMS)) .mandatory(!hasLMS))
.withAdditionalValueMapping( .withAdditionalValueMapping(QuizData.QUIZ_ATTR_START_URL)
QuizData.QUIZ_ATTR_START_URL,
QuizData.QUIZ_ATTR_START_URL)
.addField(FormBuilder.singleSelection( .addField(FormBuilder.singleSelection(
Domain.EXAM.ATTR_TYPE, Domain.EXAM.ATTR_TYPE,
@ -636,6 +628,7 @@ public class ExamForm implements TemplateComposer {
} }
private Exam newExamNoLMS() { private Exam newExamNoLMS() {
final DateTimeZone timeZone = this.pageService.getCurrentUser().get().timeZone;
return new Exam( return new Exam(
null, null,
this.pageService.getCurrentUser().get().institutionId, this.pageService.getCurrentUser().get().institutionId,
@ -643,8 +636,8 @@ public class ExamForm implements TemplateComposer {
UUID.randomUUID().toString(), UUID.randomUUID().toString(),
true, true,
null, null,
null, DateTime.now(timeZone),
null, DateTime.now(timeZone).plusHours(1),
Exam.ExamType.UNDEFINED, Exam.ExamType.UNDEFINED,
null, null,
null, null,

View file

@ -23,10 +23,11 @@ public class DateTimeSelectorFieldBuilder extends FieldBuilder<DateTime> {
final Composite fieldGrid = createFieldGrid(builder.formParent, this.spanInput); final Composite fieldGrid = createFieldGrid(builder.formParent, this.spanInput);
if (readonly) { if (readonly) {
final Text label = new Text(fieldGrid, SWT.NONE); final Text readonlyLabel = builder.widgetFactory.textInput(fieldGrid, this.label);
label.setText(builder.i18nSupport.formatDisplayDateTime(value) + " " + builder.i18nSupport.getUsersTimeZoneTitleSuffix()); readonlyLabel.setEditable(false);
label.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, true)); readonlyLabel.setText(builder.i18nSupport.formatDisplayDateWithTimeZone(value));
builder.form.putReadonlyField(this.name, titleLabel, label); readonlyLabel.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, true));
builder.form.putReadonlyField(this.name, titleLabel, readonlyLabel);
return; return;
} }

View file

@ -16,7 +16,6 @@ import java.util.function.Predicate;
import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gui.widget.*; import ch.ethz.seb.sebserver.gui.widget.*;
import com.fasterxml.jackson.databind.JsonNode;
import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.eclipse.rap.rwt.RWT; import org.eclipse.rap.rwt.RWT;
@ -105,6 +104,10 @@ public final class Form implements FormBinding {
this.additionalAttributeMapping.put(fieldName, attrName); this.additionalAttributeMapping.put(fieldName, attrName);
} }
public void putAdditionalValueMapping(final String fieldName) {
this.additionalAttributeMapping.put(fieldName, fieldName);
}
public String getStaticValue(final String name) { public String getStaticValue(final String name) {
return this.staticValues.get(name); return this.staticValues.get(name);
} }
@ -188,7 +191,7 @@ public final class Form implements FormBinding {
Form removeField(final String name) { Form removeField(final String name) {
if (this.formFields.containsKey(name)) { if (this.formFields.containsKey(name)) {
final List<FormFieldAccessor> list = this.formFields.remove(name); final List<FormFieldAccessor> list = this.formFields.remove(name);
list.forEach(ffa -> ffa.dispose()); list.forEach(FormFieldAccessor::dispose);
} }
return this; return this;
@ -318,7 +321,7 @@ public final class Form implements FormBinding {
additionalAttrs.put(entry.getValue(), fieldValue); additionalAttrs.put(entry.getValue(), fieldValue);
} }
} }
if (additionalAttrs != null) { if (!additionalAttrs.isEmpty()) {
this.objectRoot.putIfAbsent( this.objectRoot.putIfAbsent(
API.PARAM_ADDITIONAL_ATTRIBUTES, API.PARAM_ADDITIONAL_ATTRIBUTES,
jsonMapper.valueToTree(additionalAttrs)); jsonMapper.valueToTree(additionalAttrs));

View file

@ -152,6 +152,21 @@ public class FormBuilder {
return this; return this;
} }
public FormBuilder withAdditionalValueMapping(final String fieldName) {
this.form.putAdditionalValueMapping(fieldName);
return this;
}
public FormBuilder withAdditionalValueMappingIf(
final BooleanSupplier condition,
final Supplier<String> fieldNameSupplier) {
if (condition.getAsBoolean()) {
this.form.putAdditionalValueMapping(fieldNameSupplier.get());
}
return this;
}
public FormBuilder addFieldIf( public FormBuilder addFieldIf(
final BooleanSupplier condition, final BooleanSupplier condition,
final Supplier<FieldBuilder<?>> templateSupplier) { final Supplier<FieldBuilder<?>> templateSupplier) {

View file

@ -11,6 +11,7 @@ package ch.ethz.seb.sebserver.gui.service.i18n;
import java.util.Collection; import java.util.Collection;
import java.util.Locale; import java.util.Locale;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import ch.ethz.seb.sebserver.gbl.util.Utils; import ch.ethz.seb.sebserver.gbl.util.Utils;
@ -61,7 +62,9 @@ public interface I18nSupport {
* @param date the DateTime instance * @param date the DateTime instance
* @return date formatted date String to display */ * @return date formatted date String to display */
default String formatDisplayDateWithTimeZone(final DateTime date) { default String formatDisplayDateWithTimeZone(final DateTime date) {
return formatDisplayDateTime(date) + " " + this.getUsersTimeZoneTitleSuffix(); return formatDisplayDateTime(date) + (date != null
? " " + this.getUsersTimeZoneTitleSuffix()
: StringUtils.EMPTY);
} }
/** Format a time-stamp (milliseconds) to a text format to display. /** Format a time-stamp (milliseconds) to a text format to display.

View file

@ -124,7 +124,7 @@ public class ExamAdminServiceImpl implements ExamAdminService {
EntityType.EXAM, EntityType.EXAM,
examId, examId,
Exam.ADDITIONAL_ATTR_SIGNATURE_KEY_SALT, Exam.ADDITIONAL_ATTR_SIGNATURE_KEY_SALT,
KeyGenerators.string().generateKey().toString()); KeyGenerators.string().generateKey());
return exam; return exam;
}).flatMap(this::initAdditionalAttributesForMoodleExams); }).flatMap(this::initAdditionalAttributesForMoodleExams);
@ -204,7 +204,7 @@ public class ExamAdminServiceImpl implements ExamAdminService {
return this.lmsAPIService return this.lmsAPIService
.getLmsAPITemplate(exam.lmsSetupId) .getLmsAPITemplate(exam.lmsSetupId)
.map(lmsAPI -> lmsAPI.hasSEBClientRestriction(exam)) .map(lmsAPI -> lmsAPI.hasSEBClientRestriction(exam))
.onError(error -> log.error("Failed to check SEB restriction: ", error)); .onError(error -> log.warn("Failed to check SEB restriction: {}", error.getMessage()));
} }
@Override @Override
@ -301,7 +301,7 @@ public class ExamAdminServiceImpl implements ExamAdminService {
return getProctoringServiceSettings(exam.id) return getProctoringServiceSettings(exam.id)
.map(settings -> { .map(settings -> {
ProctoringServiceSettings resetSettings; final ProctoringServiceSettings resetSettings;
if (exam.examTemplateId != null) { if (exam.examTemplateId != null) {
// get settings from origin template // get settings from origin template
resetSettings = this.proctoringAdminService resetSettings = this.proctoringAdminService
@ -401,7 +401,7 @@ public class ExamAdminServiceImpl implements ExamAdminService {
.stream() .stream()
.forEach(configNodeId -> { .forEach(configNodeId -> {
if (this.examConfigurationMapDAO.checkNoActiveExamReferences(configNodeId).getOr(false)) { if (this.examConfigurationMapDAO.checkNoActiveExamReferences(configNodeId).getOr(false)) {
log.debug("Also set exam configuration to archived: ", configNodeId); log.debug("Also set exam configuration to archived: {}", configNodeId);
this.configurationNodeDAO.save( this.configurationNodeDAO.save(
new ConfigurationNode( new ConfigurationNode(
configNodeId, null, null, null, null, null, configNodeId, null, null, null, null, null,

View file

@ -23,18 +23,18 @@ public interface SEBRestrictionAPI {
* @return {@link LmsSetupTestResult } instance with the test result report */ * @return {@link LmsSetupTestResult } instance with the test result report */
LmsSetupTestResult testCourseRestrictionAPI(); LmsSetupTestResult testCourseRestrictionAPI();
/** Get SEB restriction data from LMS within a {@link SEBRestrictionData } instance. The available restriction /** Get SEB restriction data from LMS within a {@link SEBRestriction } instance. The available restriction
* details * details
* depends on the type of LMS but shall at least contains the config-key(s) and the browser-exam-key(s). * depends on the type of LMS but shall at least contains the config-key(s) and the browser-exam-key(s).
* *
* @param exam the exam to get the SEB restriction data for * @param exam the exam to get the SEB restriction data for
* @return Result refer to the {@link SEBRestrictionData } instance or to an ResourceNotFoundException if the * @return Result refer to the {@link SEBRestriction } instance or to an ResourceNotFoundException if the
* restriction is * restriction is
* missing or to another exception on unexpected error case */ * missing or to another exception on unexpected error case */
Result<SEBRestriction> getSEBClientRestriction(Exam exam); Result<SEBRestriction> getSEBClientRestriction(Exam exam);
/** Use this to check if there is a SEB restriction available on the LMS for the specified exam. /** Use this to check if there is a SEB restriction available on the LMS for the specified exam.
* * <p>
* A SEB Restriction is available if it can get from LMS and if there is either a Config-Key * A SEB Restriction is available if it can get from LMS and if there is either a Config-Key
* or a BrowserExam-Key set or both. If none of this keys is set, the SEB Restriction is been * or a BrowserExam-Key set or both. If none of this keys is set, the SEB Restriction is been
* considered to not set on the LMS. * considered to not set on the LMS.
@ -42,12 +42,7 @@ public interface SEBRestrictionAPI {
* @param exam exam the exam to get the SEB restriction data for * @param exam exam the exam to get the SEB restriction data for
* @return true if there is a SEB restriction set on the LMS for the exam or false otherwise */ * @return true if there is a SEB restriction set on the LMS for the exam or false otherwise */
default boolean hasSEBClientRestriction(final Exam exam) { default boolean hasSEBClientRestriction(final Exam exam) {
final Result<SEBRestriction> sebClientRestriction = getSEBClientRestriction(exam); return hasSEBClientRestriction(getSEBClientRestriction(exam).getOrThrow());
if (sebClientRestriction.hasError()) {
return false;
}
return hasSEBClientRestriction(sebClientRestriction.get());
} }
default boolean hasSEBClientRestriction(final SEBRestriction sebRestriction) { default boolean hasSEBClientRestriction(final SEBRestriction sebRestriction) {
@ -58,7 +53,7 @@ public interface SEBRestrictionAPI {
* *
* @param exam The exam to apply the restriction for * @param exam The exam to apply the restriction for
* @param sebRestrictionData containing all data for SEB Client restriction to apply to the LMS * @param sebRestrictionData containing all data for SEB Client restriction to apply to the LMS
* @return Result refer to the given {@link SEBRestrictionData } if restriction was successful or to an error if * @return Result refer to the given {@link SEBRestriction } if restriction was successful or to an error if
* not */ * not */
Result<SEBRestriction> applySEBClientRestriction( Result<SEBRestriction> applySEBClientRestriction(
Exam exam, Exam exam,

View file

@ -153,8 +153,11 @@ public class LmsAPIServiceImpl implements LmsAPIService {
} }
if (template.lmsSetup().getLmsType().features.contains(LmsSetup.Features.SEB_RESTRICTION)) { if (template.lmsSetup().getLmsType().features.contains(LmsSetup.Features.SEB_RESTRICTION)) {
this.cache.remove(new CacheKey(template.lmsSetup().getModelId(), 0)); final LmsSetupTestResult lmsSetupTestResult = template.testCourseRestrictionAPI();
return template.testCourseRestrictionAPI(); if (!lmsSetupTestResult.isOk()) {
this.cache.remove(new CacheKey(template.lmsSetup().getModelId(), 0));
}
return lmsSetupTestResult;
} }
return LmsSetupTestResult.ofOkay(template.lmsSetup().getLmsType()); return LmsSetupTestResult.ofOkay(template.lmsSetup().getLmsType());

View file

@ -386,18 +386,12 @@ public class LmsAPITemplateAdapter implements LmsAPITemplate {
return this.restrictionRequest.protectedRun(() -> this.sebRestrictionAPI return this.restrictionRequest.protectedRun(() -> this.sebRestrictionAPI
.getSEBClientRestriction(exam) .getSEBClientRestriction(exam)
.onError(error -> log.error("Failed to get SEB restrictions: {}", error.getMessage()))
.getOrThrow()); .getOrThrow());
} }
@Override @Override
public boolean hasSEBClientRestriction(final Exam exam) { public boolean hasSEBClientRestriction(final Exam exam) {
final Result<SEBRestriction> sebClientRestriction = getSEBClientRestriction(exam); return this.sebRestrictionAPI.hasSEBClientRestriction(getSEBClientRestriction(exam).getOrThrow());
if (sebClientRestriction.hasError()) {
return false;
}
return this.sebRestrictionAPI.hasSEBClientRestriction(sebClientRestriction.get());
} }
@Override @Override

View file

@ -18,6 +18,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.AdditionalAttributeRecord;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -102,7 +103,7 @@ public class SEBRestrictionServiceImpl implements SEBRestrictionService {
.getOrThrow(); .getOrThrow();
configKeys.addAll(generatedKeys); configKeys.addAll(generatedKeys);
if (generatedKeys != null && !generatedKeys.isEmpty()) { if (!generatedKeys.isEmpty()) {
configKeys.addAll(this.lmsAPIService configKeys.addAll(this.lmsAPIService
.getLmsAPITemplate(exam.lmsSetupId) .getLmsAPITemplate(exam.lmsSetupId)
.flatMap(lmsTemplate -> lmsTemplate.getSEBClientRestriction(exam)) .flatMap(lmsTemplate -> lmsTemplate.getSEBClientRestriction(exam))
@ -130,8 +131,8 @@ public class SEBRestrictionServiceImpl implements SEBRestrictionService {
.collect(Collectors.toMap( .collect(Collectors.toMap(
attr -> attr.getName().replace( attr -> attr.getName().replace(
SEB_RESTRICTION_ADDITIONAL_PROPERTY_NAME_PREFIX, SEB_RESTRICTION_ADDITIONAL_PROPERTY_NAME_PREFIX,
""), StringUtils.EMPTY),
attr -> attr.getValue()))); AdditionalAttributeRecord::getValue)));
} catch (final Exception e) { } catch (final Exception e) {
log.error( log.error(
"Failed to load additional SEB restriction properties from AdditionalAttributes of the Exam: {}", "Failed to load additional SEB restriction properties from AdditionalAttributes of the Exam: {}",

View file

@ -8,6 +8,10 @@
package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.mockup; package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.mockup;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -23,6 +27,8 @@ public class MockSEBRestrictionAPI implements SEBRestrictionAPI {
private static final Logger log = LoggerFactory.getLogger(MockSEBRestrictionAPI.class); private static final Logger log = LoggerFactory.getLogger(MockSEBRestrictionAPI.class);
//private Map<Long, Boolean> restrictionDB = new ConcurrentHashMap<>();
@Override @Override
public LmsSetupTestResult testCourseRestrictionAPI() { public LmsSetupTestResult testCourseRestrictionAPI() {
return LmsSetupTestResult.ofOkay(LmsType.MOCKUP); return LmsSetupTestResult.ofOkay(LmsType.MOCKUP);
@ -31,15 +37,6 @@ public class MockSEBRestrictionAPI implements SEBRestrictionAPI {
@Override @Override
public Result<SEBRestriction> getSEBClientRestriction(final Exam exam) { public Result<SEBRestriction> getSEBClientRestriction(final Exam exam) {
log.info("Get SEB Client restriction for Exam: {}", exam); log.info("Get SEB Client restriction for Exam: {}", exam);
// if (BooleanUtils.toBoolean(exam.sebRestriction)) {
// return Result.of(new SEBRestriction(
// exam.id,
// Stream.of("configKey").collect(Collectors.toList()),
// Collections.emptyList(),
// Collections.emptyMap()));
// } else {
// return Result.ofError(new NoSEBRestrictionException());
// }
return Result.ofError(new NoSEBRestrictionException()); return Result.ofError(new NoSEBRestrictionException());
} }

View file

@ -164,7 +164,6 @@ public class MoodleRestTemplateFactoryImpl implements MoodleRestTemplateFactory
public Result<MoodleAPIRestTemplate> createRestTemplate(final String service, final String accessTokenPath) { public Result<MoodleAPIRestTemplate> createRestTemplate(final String service, final String accessTokenPath) {
final LmsSetup lmsSetup = this.apiTemplateDataSupplier.getLmsSetup(); final LmsSetup lmsSetup = this.apiTemplateDataSupplier.getLmsSetup();
return Result.tryCatch(() -> { return Result.tryCatch(() -> {
final ClientCredentials credentials = this.apiTemplateDataSupplier.getLmsClientCredentials(); final ClientCredentials credentials = this.apiTemplateDataSupplier.getLmsClientCredentials();
final ProxyData proxyData = this.apiTemplateDataSupplier.getProxyData(); final ProxyData proxyData = this.apiTemplateDataSupplier.getProxyData();
@ -319,7 +318,7 @@ public class MoodleRestTemplateFactoryImpl implements MoodleRestTemplateFactory
} }
final boolean usePOST = queryAttributes != null && !queryAttributes.isEmpty(); final boolean usePOST = queryAttributes != null && !queryAttributes.isEmpty();
HttpEntity<?> functionReqEntity; final HttpEntity<?> functionReqEntity;
if (usePOST) { if (usePOST) {
final HttpHeaders headers = new HttpHeaders(); final HttpHeaders headers = new HttpHeaders();
headers.set( headers.set(
@ -401,8 +400,7 @@ public class MoodleRestTemplateFactoryImpl implements MoodleRestTemplateFactory
if (moodleToken == null || moodleToken.token == null) { if (moodleToken == null || moodleToken.token == null) {
throw new RuntimeException("Access Token request with 200 but no or invalid token body"); throw new RuntimeException("Access Token request with 200 but no or invalid token body");
} else { } else {
log.info("Successfully get access token from Moodle: {}", log.info("Successfully get access token from Moodle: {}", lmsSetup.name);
lmsSetup);
} }
this.accessToken = moodleToken.token; this.accessToken = moodleToken.token;

View file

@ -1,68 +0,0 @@
/*
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.plugin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetupTestResult;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleAPIRestTemplate;
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleRestTemplateFactory;
@Lazy
@Service
@WebServiceProfile
public class MoodlePluginCheck {
private static final Logger log = LoggerFactory.getLogger(MoodlePluginCheck.class);
/** Used to check if the moodle SEB Server plugin is available for a given LMSSetup.
*
* @param lmsSetup The LMS Setup
* @return true if the SEB Server plugin is available */
public boolean checkPluginAvailable(final MoodleRestTemplateFactory restTemplateFactory) {
try {
log.info("Check Moodle SEB Server Plugin available...");
final LmsSetupTestResult test = restTemplateFactory.test();
if (!test.isOk()) {
log.warn("Failed to check Moodle SEB Server Plugin because of invalid LMS Setup: ", test);
return false;
}
final MoodleAPIRestTemplate restTemplate = restTemplateFactory
.createRestTemplate(MooldePluginLmsAPITemplateFactory.SEB_SERVER_SERVICE_NAME)
.getOrThrow();
try {
restTemplate.testAPIConnection(
MoodlePluginCourseAccess.COURSES_API_FUNCTION_NAME,
MoodlePluginCourseAccess.USERS_API_FUNCTION_NAME);
} catch (final Exception e) {
log.info("Moodle SEB Server Plugin not available: {}", e.getMessage());
return false;
}
log.info("Moodle SEB Server Plugin not available for: {}",
restTemplateFactory.getApiTemplateDataSupplier().getLmsSetup());
return true;
} catch (final Exception e) {
log.error("Failed to check Moodle SEB Server Plugin because of unexpected error: ", e);
return false;
}
}
}

View file

@ -109,6 +109,7 @@ public class MoodlePluginCourseAccess extends AbstractCachedCourseAccess impleme
final boolean applyNameCriteria) { final boolean applyNameCriteria) {
super(cacheManager); super(cacheManager);
this.jsonMapper = jsonMapper; this.jsonMapper = jsonMapper;
this.restTemplateFactory = restTemplateFactory; this.restTemplateFactory = restTemplateFactory;
this.applyNameCriteria = applyNameCriteria; this.applyNameCriteria = applyNameCriteria;
@ -594,7 +595,9 @@ public class MoodlePluginCourseAccess extends AbstractCachedCourseAccess impleme
} }
private Result<MoodleAPIRestTemplate> getRestTemplate() { private Result<MoodleAPIRestTemplate> getRestTemplate() {
if (this.restTemplate == null) { if (this.restTemplate == null) {
final Result<MoodleAPIRestTemplate> templateRequest = this.restTemplateFactory final Result<MoodleAPIRestTemplate> templateRequest = this.restTemplateFactory
.createRestTemplate(MooldePluginLmsAPITemplateFactory.SEB_SERVER_SERVICE_NAME); .createRestTemplate(MooldePluginLmsAPITemplateFactory.SEB_SERVER_SERVICE_NAME);
if (templateRequest.hasError()) { if (templateRequest.hasError()) {

View file

@ -283,13 +283,13 @@ public class MoodlePluginCourseRestriction implements SEBRestrictionAPI {
private Result<MoodleAPIRestTemplate> getRestTemplate() { private Result<MoodleAPIRestTemplate> getRestTemplate() {
if (this.restTemplate == null) { if (this.restTemplate == null) {
final Result<MoodleAPIRestTemplate> templateRequest = this.restTemplateFactory final Result<MoodleAPIRestTemplate> templateRequest = this.restTemplateFactory
.createRestTemplate(MooldePluginLmsAPITemplateFactory.SEB_SERVER_SERVICE_NAME); .createRestTemplate(MooldePluginLmsAPITemplateFactory.SEB_SERVER_SERVICE_NAME);
if (templateRequest.hasError()) { if (templateRequest.hasError()) {
return templateRequest; return templateRequest;
} else { } else {
final MoodleAPIRestTemplate moodleAPIRestTemplate = templateRequest.get(); this.restTemplate = templateRequest.get();
this.restTemplate = moodleAPIRestTemplate;
} }
} }

View file

@ -337,7 +337,7 @@ public class ExamAdministrationController extends EntityController<Exam, Exam> {
return this.examDAO return this.examDAO
.byPK(modelId) .byPK(modelId)
.flatMap(this.examAdminService::isRestricted) .flatMap(this.examAdminService::isRestricted)
.getOrThrow(); .getOr(false);
} }
@RequestMapping( @RequestMapping(
@ -376,7 +376,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)
.flatMap(exam -> this.sebRestrictionService.saveSEBRestrictionToExam(exam, sebRestriction)) .flatMap(exam -> this.sebRestrictionService.saveSEBRestrictionToExam(exam, sebRestriction))
.flatMap(exam -> this.examAdminService.isRestricted(exam).getOrThrow() .flatMap(exam -> this.examAdminService.isRestricted(exam).getOr(false)
? this.applySEBRestriction(exam, true) ? this.applySEBRestriction(exam, true)
: Result.of(exam)) : Result.of(exam))
.getOrThrow(); .getOrThrow();

View file

@ -33,6 +33,7 @@ public class MoodlePluginCourseRestrictionTest {
@Test @Test
public void testSetup() { public void testSetup() {
final MoodlePluginCourseRestriction candidate = crateMockup(); final MoodlePluginCourseRestriction candidate = crateMockup();
assertEquals("MoodlePluginCourseRestriction [restTemplate=null]", candidate.toTestString()); assertEquals("MoodlePluginCourseRestriction [restTemplate=null]", candidate.toTestString());