SEBSERV-417 improved error and waning handling and logging
This commit is contained in:
parent
dc98f451fa
commit
c4dc211cb6
21 changed files with 344 additions and 84 deletions
|
@ -12,6 +12,12 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
|
||||||
public interface Activatable {
|
public interface Activatable {
|
||||||
|
|
||||||
|
public enum ActivationAction {
|
||||||
|
NONE,
|
||||||
|
ACTIVATE,
|
||||||
|
DEACTIVATE
|
||||||
|
}
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
boolean isActive();
|
boolean isActive();
|
||||||
|
|
||||||
|
|
|
@ -514,6 +514,11 @@ public class LmsSetupForm implements TemplateComposer {
|
||||||
Utils.escapeHTML_XML_EcmaScript(error.message)));
|
Utils.escapeHTML_XML_EcmaScript(error.message)));
|
||||||
return onOK.apply(locTextKey);
|
return onOK.apply(locTextKey);
|
||||||
}
|
}
|
||||||
|
case APPLY_FULL_INTEGRATION: {
|
||||||
|
throw new PageMessageException(new LocTextKey(
|
||||||
|
"sebserver.lmssetup.action.test.fullintegration.error",
|
||||||
|
Utils.formatHTMLLinesForceEscaped(Utils.escapeHTML_XML_EcmaScript(error.message))));
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
throw new PageMessageException(new LocTextKey(
|
throw new PageMessageException(new LocTextKey(
|
||||||
"sebserver.lmssetup.action.test.unknownError",
|
"sebserver.lmssetup.action.test.unknownError",
|
||||||
|
|
|
@ -192,6 +192,7 @@ public class LmsSetupList implements TemplateComposer {
|
||||||
.publishIf(userGrant::im, false)
|
.publishIf(userGrant::im, false)
|
||||||
|
|
||||||
.newAction(ActionDefinition.LMS_SETUP_TOGGLE_ACTIVITY)
|
.newAction(ActionDefinition.LMS_SETUP_TOGGLE_ACTIVITY)
|
||||||
|
.withAttribute(PageContext.CONTEXTUAL_ERROR_KEY, "sebserver.lmssetup.action.activation.error")
|
||||||
.withSelect(
|
.withSelect(
|
||||||
table.getGrantedSelection(currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION),
|
table.getGrantedSelection(currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION),
|
||||||
this.pageService.activationToggleActionFunction(
|
this.pageService.activationToggleActionFunction(
|
||||||
|
|
|
@ -52,6 +52,7 @@ public interface PageContext {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String CONTEXTUAL_ERROR_KEY = "ERROR_MESSAGE_KEY";
|
||||||
/** The resource-bundle key of the generic load entity error message. */
|
/** The resource-bundle key of the generic load entity error message. */
|
||||||
String GENERIC_LOAD_ERROR_TEXT_KEY = "sebserver.error.get.entity";
|
String GENERIC_LOAD_ERROR_TEXT_KEY = "sebserver.error.get.entity";
|
||||||
String GENERIC_REMOVE_ERROR_TEXT_KEY = "sebserver.error.remove.entity";
|
String GENERIC_REMOVE_ERROR_TEXT_KEY = "sebserver.error.remove.entity";
|
||||||
|
|
|
@ -326,9 +326,15 @@ public class PageServiceImpl implements PageService {
|
||||||
|
|
||||||
if (!errors.isEmpty()) {
|
if (!errors.isEmpty()) {
|
||||||
final String entityTypeName = this.resourceService.getEntityTypeName(entityType);
|
final String entityTypeName = this.resourceService.getEntityTypeName(entityType);
|
||||||
|
final String errorMessageKey = action.pageContext().getAttribute(PageContext.CONTEXTUAL_ERROR_KEY);
|
||||||
throw new MultiPageMessageException(
|
throw new MultiPageMessageException(
|
||||||
new LocTextKey(PageContext.GENERIC_ACTIVATE_ERROR_TEXT_KEY, entityTypeName),
|
new LocTextKey(
|
||||||
|
(errorMessageKey != null)
|
||||||
|
? errorMessageKey
|
||||||
|
: PageContext.GENERIC_ACTIVATE_ERROR_TEXT_KEY,
|
||||||
|
entityTypeName),
|
||||||
errors);
|
errors);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return action;
|
return action;
|
||||||
|
|
|
@ -144,9 +144,6 @@ public class LmsSetupDAOImpl implements LmsSetupDAO {
|
||||||
|
|
||||||
return this.lmsSetupRecordMapper.selectIdsByExample()
|
return this.lmsSetupRecordMapper.selectIdsByExample()
|
||||||
.where(
|
.where(
|
||||||
LmsSetupRecordDynamicSqlSupport.active,
|
|
||||||
isEqualTo(1))
|
|
||||||
.and(
|
|
||||||
lmsType,
|
lmsType,
|
||||||
isIn(types))
|
isIn(types))
|
||||||
.build()
|
.build()
|
||||||
|
|
|
@ -14,6 +14,7 @@ import java.util.Collection;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
|
||||||
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.gbl.util.Utils;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.impl.ExamDeletionEvent;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.impl.ExamDeletionEvent;
|
||||||
|
@ -31,6 +32,8 @@ public interface FullLmsIntegrationService {
|
||||||
@EventListener
|
@EventListener
|
||||||
void notifyLmsSetupChange(final LmsSetupChangeEvent event);
|
void notifyLmsSetupChange(final LmsSetupChangeEvent event);
|
||||||
|
|
||||||
|
Result<LmsSetup> applyLMSSetupDeactivation(LmsSetup lmsSetup);
|
||||||
|
|
||||||
@EventListener
|
@EventListener
|
||||||
void notifyExamTemplateChange(final ExamTemplateChangeEvent event);
|
void notifyExamTemplateChange(final ExamTemplateChangeEvent event);
|
||||||
@EventListener(ConnectionConfigurationChangeEvent.class)
|
@EventListener(ConnectionConfigurationChangeEvent.class)
|
||||||
|
|
|
@ -10,7 +10,10 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.lms;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.SEBRestriction;
|
import ch.ethz.seb.sebserver.gbl.model.exam.SEBRestriction;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.LmsSetupChangeEvent;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
|
||||||
public interface SEBRestrictionService {
|
public interface SEBRestrictionService {
|
||||||
|
|
||||||
|
@ -67,4 +70,9 @@ public interface SEBRestrictionService {
|
||||||
|
|
||||||
Result<Exam> applyQuitPassword(final Exam exam);
|
Result<Exam> applyQuitPassword(final Exam exam);
|
||||||
|
|
||||||
|
@EventListener
|
||||||
|
void notifyLmsSetupChange(final LmsSetupChangeEvent event);
|
||||||
|
|
||||||
|
Result<LmsSetup> applyLMSSetupDeactivation(LmsSetup lmsSetup);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import ch.ethz.seb.sebserver.gbl.Constants;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
|
import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.Activatable;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
||||||
|
@ -137,7 +138,6 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
||||||
.getClientHttpRequestFactory()
|
.getClientHttpRequestFactory()
|
||||||
.onSuccess(this.restTemplate::setRequestFactory)
|
.onSuccess(this.restTemplate::setRequestFactory)
|
||||||
.onError(error -> log.warn("Failed to set HTTP request factory: ", error));
|
.onError(error -> log.warn("Failed to set HTTP request factory: ", error));
|
||||||
//this.restTemplate.setErrorHandler(new OAuth2AuthorizationContextHolder.OAuth2AuthorizationContext.ErrorHandler(this.resource));
|
|
||||||
this.restTemplate
|
this.restTemplate
|
||||||
.getMessageConverters()
|
.getMessageConverters()
|
||||||
.add(0, new StringHttpMessageConverter(StandardCharsets.UTF_8));
|
.add(0, new StringHttpMessageConverter(StandardCharsets.UTF_8));
|
||||||
|
@ -164,19 +164,46 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lmsSetup.active) {
|
if (event.activation == Activatable.ActivationAction.NONE) {
|
||||||
if (!lmsSetup.integrationActive) {
|
if (!lmsSetup.integrationActive) {
|
||||||
applyFullLmsIntegration(lmsSetup.id)
|
applyFullLmsIntegration(lmsSetup.id)
|
||||||
.onError(error -> log.warn("Failed to update LMS integration for: {}", lmsSetup, error))
|
.onError(error -> log.warn("Failed to update LMS integration for: {} error {}", lmsSetup, error.getMessage()))
|
||||||
.onSuccess(data -> log.debug("Successfully updated LMS integration for: {} data: {}", lmsSetup, data));
|
.onSuccess(data -> log.debug("Successfully updated LMS integration for: {} data: {}", lmsSetup, data));
|
||||||
}
|
}
|
||||||
} else if (lmsSetup.integrationActive) {
|
} else if (event.activation == Activatable.ActivationAction.ACTIVATE) {
|
||||||
deleteFullLmsIntegration(lmsSetup.id)
|
applyFullLmsIntegration(lmsSetup.id)
|
||||||
.onError(error -> log.warn("Failed to delete LMS integration for: {}", lmsSetup, error))
|
.map(data -> reapplyExistingExams(data,lmsSetup))
|
||||||
.onSuccess(data -> log.debug("Successfully deleted LMS integration for: {} data: {}", lmsSetup, data));
|
.onError(error -> log.warn("Failed to update LMS integration for: {} error {}", lmsSetup, error.getMessage()))
|
||||||
|
.onSuccess(data -> log.debug("Successfully updated LMS integration for: {} data: {}", lmsSetup, data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<LmsSetup> applyLMSSetupDeactivation(final LmsSetup lmsSetup) {
|
||||||
|
if (!lmsSetup.getLmsType().features.contains(LmsSetup.Features.LMS_FULL_INTEGRATION)) {
|
||||||
|
return Result.of(lmsSetup);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.tryCatch(() -> {
|
||||||
|
|
||||||
|
// remove all active exam data for involved exams before deactivate them
|
||||||
|
this.examDAO
|
||||||
|
.allActiveForLMSSetup(Arrays.asList(lmsSetup.id))
|
||||||
|
.getOrThrow()
|
||||||
|
.forEach( exam -> {
|
||||||
|
this.teacherAccountServiceImpl.deactivateTeacherAccountsForExam(exam)
|
||||||
|
.map(e -> applyExamData(e, true))
|
||||||
|
.onError(error -> log.warn("Failed delete teacher accounts for exam: {}", exam.name));
|
||||||
|
});
|
||||||
|
|
||||||
|
// delete full integration on Moodle side before deactivate LMS Setup
|
||||||
|
this.deleteFullLmsIntegration(lmsSetup.id)
|
||||||
|
.getOrThrow();
|
||||||
|
|
||||||
|
return lmsSetup;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void notifyExamTemplateChange(final ExamTemplateChangeEvent event) {
|
public void notifyExamTemplateChange(final ExamTemplateChangeEvent event) {
|
||||||
final ExamTemplate examTemplate = event.getExamTemplate();
|
final ExamTemplate examTemplate = event.getExamTemplate();
|
||||||
|
@ -257,8 +284,6 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result<Boolean> deleteFullLmsIntegration(final Long lmsSetupId) {
|
public Result<Boolean> deleteFullLmsIntegration(final Long lmsSetupId) {
|
||||||
return lmsSetupDAO
|
return lmsSetupDAO
|
||||||
|
@ -327,28 +352,24 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// TODO this is hardcoded for Testing, below out-commented code is real business
|
final Result<Exam> examResult = lmsSetupDAO
|
||||||
|
.getLmsSetupIdByConnectionId(lmsUUID)
|
||||||
|
.flatMap(lmsAPITemplateCacheService::getLmsAPITemplate)
|
||||||
|
.map(findQuizData(courseId, quizId))
|
||||||
|
.flatMap(this::findExam);
|
||||||
|
|
||||||
this.connectionConfigurationService.exportSEBClientConfiguration(out, "1", null);
|
if (examResult.hasError()) {
|
||||||
|
throw new APIMessage.APIMessageException(APIMessage.ErrorMessage.ILLEGAL_API_ARGUMENT.of("Exam not found"));
|
||||||
|
}
|
||||||
|
|
||||||
// final Result<Exam> examResult = lmsSetupDAO
|
final Exam exam = examResult.get();
|
||||||
// .getLmsSetupIdByConnectionId(lmsUUID)
|
|
||||||
// .flatMap(lmsAPIService::getLmsAPITemplate)
|
final String connectionConfigId = getConnectionConfigurationId(exam);
|
||||||
// .map(findQuizData(courseId, quizId))
|
if (StringUtils.isBlank(connectionConfigId)) {
|
||||||
// .flatMap(this::findExam);
|
throw new APIMessage.APIMessageException(APIMessage.ErrorMessage.ILLEGAL_API_ARGUMENT.of("No active Connection Configuration found"));
|
||||||
//
|
}
|
||||||
// if (examResult.hasError()) {
|
|
||||||
// throw new APIMessage.APIMessageException(APIMessage.ErrorMessage.ILLEGAL_API_ARGUMENT.of("Exam not found"));
|
this.connectionConfigurationService.exportSEBClientConfiguration(out, connectionConfigId, exam.id);
|
||||||
// }
|
|
||||||
//
|
|
||||||
// final Exam exam = examResult.get();
|
|
||||||
//
|
|
||||||
// final String connectionConfigId = getConnectionConfigurationId(exam);
|
|
||||||
// if (StringUtils.isBlank(connectionConfigId)) {
|
|
||||||
// throw new APIMessage.APIMessageException(APIMessage.ErrorMessage.ILLEGAL_API_ARGUMENT.of("No active Connection Configuration found"));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// this.connectionConfigurationService.exportSEBClientConfiguration(out, connectionConfigId, exam.id);
|
|
||||||
return Result.EMPTY;
|
return Result.EMPTY;
|
||||||
|
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
|
@ -356,6 +377,17 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private LmsSetup reapplyExistingExams(
|
||||||
|
final IntegrationData integrationData,
|
||||||
|
final LmsSetup lmsSetup) {
|
||||||
|
|
||||||
|
examDAO.allActiveForLMSSetup(Arrays.asList(lmsSetup.id))
|
||||||
|
.getOrThrow()
|
||||||
|
.forEach(exam -> applyExamData(exam, false));
|
||||||
|
|
||||||
|
return lmsSetup;
|
||||||
|
}
|
||||||
|
|
||||||
private String getConnectionConfigurationId(final Exam exam) {
|
private String getConnectionConfigurationId(final Exam exam) {
|
||||||
String connectionConfigId = exam.getAdditionalAttribute(Exam.ADDITIONAL_ATTR_DEFAULT_CONNECTION_CONFIGURATION);
|
String connectionConfigId = exam.getAdditionalAttribute(Exam.ADDITIONAL_ATTR_DEFAULT_CONNECTION_CONFIGURATION);
|
||||||
if (StringUtils.isBlank(connectionConfigId)) {
|
if (StringUtils.isBlank(connectionConfigId)) {
|
||||||
|
|
|
@ -36,6 +36,8 @@ public class LmsAPITemplateAdapter implements LmsAPITemplate {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(LmsAPITemplateAdapter.class);
|
private static final Logger log = LoggerFactory.getLogger(LmsAPITemplateAdapter.class);
|
||||||
|
|
||||||
|
private static final int DEFAULT_ATTEMPTS = 1;
|
||||||
|
|
||||||
private final CourseAccessAPI courseAccessAPI;
|
private final CourseAccessAPI courseAccessAPI;
|
||||||
private final SEBRestrictionAPI sebRestrictionAPI;
|
private final SEBRestrictionAPI sebRestrictionAPI;
|
||||||
|
|
||||||
|
@ -78,7 +80,7 @@ public class LmsAPITemplateAdapter implements LmsAPITemplate {
|
||||||
environment.getProperty(
|
environment.getProperty(
|
||||||
"sebserver.webservice.circuitbreaker.lmsTestRequest.attempts",
|
"sebserver.webservice.circuitbreaker.lmsTestRequest.attempts",
|
||||||
Integer.class,
|
Integer.class,
|
||||||
2),
|
DEFAULT_ATTEMPTS),
|
||||||
environment.getProperty(
|
environment.getProperty(
|
||||||
"sebserver.webservice.circuitbreaker.lmsTestRequest.blockingTime",
|
"sebserver.webservice.circuitbreaker.lmsTestRequest.blockingTime",
|
||||||
Long.class,
|
Long.class,
|
||||||
|
@ -92,7 +94,7 @@ public class LmsAPITemplateAdapter implements LmsAPITemplate {
|
||||||
environment.getProperty(
|
environment.getProperty(
|
||||||
"sebserver.webservice.circuitbreaker.lmsAccessRequest.attempts",
|
"sebserver.webservice.circuitbreaker.lmsAccessRequest.attempts",
|
||||||
Integer.class,
|
Integer.class,
|
||||||
2),
|
DEFAULT_ATTEMPTS),
|
||||||
environment.getProperty(
|
environment.getProperty(
|
||||||
"sebserver.webservice.circuitbreaker.lmsAccessRequest.blockingTime",
|
"sebserver.webservice.circuitbreaker.lmsAccessRequest.blockingTime",
|
||||||
Long.class,
|
Long.class,
|
||||||
|
@ -106,7 +108,7 @@ public class LmsAPITemplateAdapter implements LmsAPITemplate {
|
||||||
environment.getProperty(
|
environment.getProperty(
|
||||||
"sebserver.webservice.circuitbreaker.applyExamDataRequest.attempts",
|
"sebserver.webservice.circuitbreaker.applyExamDataRequest.attempts",
|
||||||
Integer.class,
|
Integer.class,
|
||||||
2),
|
DEFAULT_ATTEMPTS),
|
||||||
environment.getProperty(
|
environment.getProperty(
|
||||||
"sebserver.webservice.circuitbreaker.applyExamDataRequest.blockingTime",
|
"sebserver.webservice.circuitbreaker.applyExamDataRequest.blockingTime",
|
||||||
Long.class,
|
Long.class,
|
||||||
|
@ -120,7 +122,7 @@ public class LmsAPITemplateAdapter implements LmsAPITemplate {
|
||||||
environment.getProperty(
|
environment.getProperty(
|
||||||
"sebserver.webservice.circuitbreaker.lmsTestRequest.attempts",
|
"sebserver.webservice.circuitbreaker.lmsTestRequest.attempts",
|
||||||
Integer.class,
|
Integer.class,
|
||||||
2),
|
DEFAULT_ATTEMPTS),
|
||||||
environment.getProperty(
|
environment.getProperty(
|
||||||
"sebserver.webservice.circuitbreaker.lmsTestRequest.blockingTime",
|
"sebserver.webservice.circuitbreaker.lmsTestRequest.blockingTime",
|
||||||
Long.class,
|
Long.class,
|
||||||
|
@ -134,7 +136,7 @@ public class LmsAPITemplateAdapter implements LmsAPITemplate {
|
||||||
environment.getProperty(
|
environment.getProperty(
|
||||||
"sebserver.webservice.circuitbreaker.quizzesRequest.attempts",
|
"sebserver.webservice.circuitbreaker.quizzesRequest.attempts",
|
||||||
Integer.class,
|
Integer.class,
|
||||||
1),
|
DEFAULT_ATTEMPTS),
|
||||||
environment.getProperty(
|
environment.getProperty(
|
||||||
"sebserver.webservice.circuitbreaker.quizzesRequest.blockingTime",
|
"sebserver.webservice.circuitbreaker.quizzesRequest.blockingTime",
|
||||||
Long.class,
|
Long.class,
|
||||||
|
@ -148,7 +150,7 @@ public class LmsAPITemplateAdapter implements LmsAPITemplate {
|
||||||
environment.getProperty(
|
environment.getProperty(
|
||||||
"sebserver.webservice.circuitbreaker.quizzesRequest.attempts",
|
"sebserver.webservice.circuitbreaker.quizzesRequest.attempts",
|
||||||
Integer.class,
|
Integer.class,
|
||||||
1),
|
DEFAULT_ATTEMPTS),
|
||||||
environment.getProperty(
|
environment.getProperty(
|
||||||
"sebserver.webservice.circuitbreaker.quizzesRequest.blockingTime",
|
"sebserver.webservice.circuitbreaker.quizzesRequest.blockingTime",
|
||||||
Long.class,
|
Long.class,
|
||||||
|
@ -162,7 +164,7 @@ public class LmsAPITemplateAdapter implements LmsAPITemplate {
|
||||||
environment.getProperty(
|
environment.getProperty(
|
||||||
"sebserver.webservice.circuitbreaker.quizzesRequest.attempts",
|
"sebserver.webservice.circuitbreaker.quizzesRequest.attempts",
|
||||||
Integer.class,
|
Integer.class,
|
||||||
1),
|
DEFAULT_ATTEMPTS),
|
||||||
environment.getProperty(
|
environment.getProperty(
|
||||||
"sebserver.webservice.circuitbreaker.quizzesRequest.blockingTime",
|
"sebserver.webservice.circuitbreaker.quizzesRequest.blockingTime",
|
||||||
Long.class,
|
Long.class,
|
||||||
|
@ -176,7 +178,7 @@ public class LmsAPITemplateAdapter implements LmsAPITemplate {
|
||||||
environment.getProperty(
|
environment.getProperty(
|
||||||
"sebserver.webservice.circuitbreaker.chaptersRequest.attempts",
|
"sebserver.webservice.circuitbreaker.chaptersRequest.attempts",
|
||||||
Integer.class,
|
Integer.class,
|
||||||
1),
|
DEFAULT_ATTEMPTS),
|
||||||
environment.getProperty(
|
environment.getProperty(
|
||||||
"sebserver.webservice.circuitbreaker.chaptersRequest.blockingTime",
|
"sebserver.webservice.circuitbreaker.chaptersRequest.blockingTime",
|
||||||
Long.class,
|
Long.class,
|
||||||
|
@ -204,7 +206,7 @@ public class LmsAPITemplateAdapter implements LmsAPITemplate {
|
||||||
environment.getProperty(
|
environment.getProperty(
|
||||||
"sebserver.webservice.circuitbreaker.sebrestriction.attempts",
|
"sebserver.webservice.circuitbreaker.sebrestriction.attempts",
|
||||||
Integer.class,
|
Integer.class,
|
||||||
1),
|
DEFAULT_ATTEMPTS),
|
||||||
environment.getProperty(
|
environment.getProperty(
|
||||||
"sebserver.webservice.circuitbreaker.sebrestriction.blockingTime",
|
"sebserver.webservice.circuitbreaker.sebrestriction.blockingTime",
|
||||||
Long.class,
|
Long.class,
|
||||||
|
@ -218,7 +220,7 @@ public class LmsAPITemplateAdapter implements LmsAPITemplate {
|
||||||
environment.getProperty(
|
environment.getProperty(
|
||||||
"sebserver.webservice.circuitbreaker.examRequest.attempts",
|
"sebserver.webservice.circuitbreaker.examRequest.attempts",
|
||||||
Integer.class,
|
Integer.class,
|
||||||
2),
|
DEFAULT_ATTEMPTS),
|
||||||
environment.getProperty(
|
environment.getProperty(
|
||||||
"sebserver.webservice.circuitbreaker.examRequest.blockingTime",
|
"sebserver.webservice.circuitbreaker.examRequest.blockingTime",
|
||||||
Long.class,
|
Long.class,
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl;
|
package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.Activatable;
|
||||||
import org.springframework.context.ApplicationEvent;
|
import org.springframework.context.ApplicationEvent;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
|
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
|
||||||
|
@ -16,8 +17,11 @@ public class LmsSetupChangeEvent extends ApplicationEvent {
|
||||||
|
|
||||||
private static final long serialVersionUID = -7239994198026689531L;
|
private static final long serialVersionUID = -7239994198026689531L;
|
||||||
|
|
||||||
public LmsSetupChangeEvent(final LmsSetup source) {
|
public final Activatable.ActivationAction activation;
|
||||||
|
|
||||||
|
public LmsSetupChangeEvent(final LmsSetup source, final Activatable.ActivationAction activation) {
|
||||||
super(source);
|
super(source);
|
||||||
|
this.activation = activation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LmsSetup getLmsSetup() {
|
public LmsSetup getLmsSetup() {
|
||||||
|
|
|
@ -17,6 +17,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.lms.FullLmsIntegrationServi
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplate;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplate;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplateCacheService;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplateCacheService;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsTestService;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsTestService;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleResponseException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
@ -58,27 +59,8 @@ public class LmsTestServiceImpl implements LmsTestService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (template.lmsSetup().getLmsType().features.contains(LmsSetup.Features.LMS_FULL_INTEGRATION)) {
|
final LmsSetupTestResult lmsSetupTestResult = fullIntegrationTest(template);
|
||||||
final Long lmsSetupId = template.lmsSetup().id;
|
if (lmsSetupTestResult != null) return lmsSetupTestResult;
|
||||||
final LmsSetupTestResult lmsSetupTestResult = template.testFullIntegrationAPI();
|
|
||||||
if (!lmsSetupTestResult.isOk()) {
|
|
||||||
lmsAPITemplateCacheService.clearCache(template.lmsSetup().getModelId());
|
|
||||||
this.lmsSetupDAO
|
|
||||||
.setIntegrationActive(lmsSetupId, false)
|
|
||||||
.onError(er -> log.error("Failed to mark LMS integration inactive", er));
|
|
||||||
return lmsSetupTestResult;
|
|
||||||
} else {
|
|
||||||
|
|
||||||
final Result<FullLmsIntegrationService.IntegrationData> integrationDataResult = fullLmsIntegrationService
|
|
||||||
.applyFullLmsIntegration(template.lmsSetup().id);
|
|
||||||
|
|
||||||
if (integrationDataResult.hasError()) {
|
|
||||||
return LmsSetupTestResult.ofFullIntegrationAPIError(
|
|
||||||
template.lmsSetup().lmsType,
|
|
||||||
"Failed to apply full LMS integration");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return LmsSetupTestResult.ofOkay(template.lmsSetup().getLmsType());
|
return LmsSetupTestResult.ofOkay(template.lmsSetup().getLmsType());
|
||||||
}
|
}
|
||||||
|
@ -110,13 +92,44 @@ public class LmsTestServiceImpl implements LmsTestService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lmsType.features.contains(LmsSetup.Features.LMS_FULL_INTEGRATION)) {
|
final LmsSetupTestResult lmsSetupTestResult = fullIntegrationTest(lmsSetupTemplate);
|
||||||
final LmsSetupTestResult lmsSetupTestResult = lmsSetupTemplate.testFullIntegrationAPI();
|
if (lmsSetupTestResult != null) return lmsSetupTestResult;
|
||||||
if (!lmsSetupTestResult.isOk()) {
|
|
||||||
return lmsSetupTestResult;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return LmsSetupTestResult.ofOkay(lmsSetupTemplate.lmsSetup().getLmsType());
|
return LmsSetupTestResult.ofOkay(lmsSetupTemplate.lmsSetup().getLmsType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private LmsSetupTestResult fullIntegrationTest(final LmsAPITemplate template) {
|
||||||
|
if (template.lmsSetup().getLmsType().features.contains(LmsSetup.Features.LMS_FULL_INTEGRATION)) {
|
||||||
|
final Long lmsSetupId = template.lmsSetup().id;
|
||||||
|
final LmsSetupTestResult lmsSetupTestResult = template.testFullIntegrationAPI();
|
||||||
|
if (!lmsSetupTestResult.isOk()) {
|
||||||
|
lmsAPITemplateCacheService.clearCache(template.lmsSetup().getModelId());
|
||||||
|
this.lmsSetupDAO
|
||||||
|
.setIntegrationActive(lmsSetupId, false)
|
||||||
|
.onError(er -> log.error("Failed to mark LMS integration inactive", er));
|
||||||
|
return lmsSetupTestResult;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
final Result<FullLmsIntegrationService.IntegrationData> integrationDataResult = fullLmsIntegrationService
|
||||||
|
.applyFullLmsIntegration(template.lmsSetup().id);
|
||||||
|
|
||||||
|
if (integrationDataResult.hasError()) {
|
||||||
|
Throwable error = integrationDataResult.getError();
|
||||||
|
if (error instanceof RuntimeException) {
|
||||||
|
error = error.getCause();
|
||||||
|
}
|
||||||
|
if (error != null && error instanceof MoodleResponseException) {
|
||||||
|
return LmsSetupTestResult.ofFullIntegrationAPIError(
|
||||||
|
template.lmsSetup().lmsType,
|
||||||
|
error.getMessage());
|
||||||
|
} else {
|
||||||
|
return LmsSetupTestResult.ofFullIntegrationAPIError(
|
||||||
|
template.lmsSetup().lmsType,
|
||||||
|
"Failed to apply full LMS integration");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.gbl.model.Activatable;
|
||||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.AdditionalAttributeRecord;
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.AdditionalAttributeRecord;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.exam.ExamConfigurationValueService;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.exam.ExamConfigurationValueService;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
@ -106,6 +107,53 @@ public class SEBRestrictionServiceImpl implements SEBRestrictionService {
|
||||||
.onError(t -> log.error("Failed to quit password for Exam: {}", exam, t));
|
.onError(t -> log.error("Failed to quit password for Exam: {}", exam, t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notifyLmsSetupChange(final LmsSetupChangeEvent event) {
|
||||||
|
final LmsSetup lmsSetup = event.getLmsSetup();
|
||||||
|
// only relevant for LMS Setups with SEB restriction feature
|
||||||
|
if (!lmsSetup.lmsType.features.contains(Features.SEB_RESTRICTION)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (event.activation == Activatable.ActivationAction.ACTIVATE) {
|
||||||
|
examDAO.allActiveForLMSSetup(Arrays.asList(lmsSetup.id))
|
||||||
|
.getOrThrow()
|
||||||
|
.forEach(exam -> {
|
||||||
|
try {
|
||||||
|
this.applySEBRestrictionIfExamRunning(exam);
|
||||||
|
} catch (final Exception e) {
|
||||||
|
log.warn("Failed to update SEB restriction for exam: {} error: {}", exam.name, e.getMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (final Exception e) {
|
||||||
|
log.error("Failed to update SEB restriction for re-activated exams: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<LmsSetup> applyLMSSetupDeactivation(final LmsSetup lmsSetup) {
|
||||||
|
|
||||||
|
return Result.tryCatch(() -> {
|
||||||
|
// only relevant for LMS Setups with SEB restriction feature
|
||||||
|
if (!lmsSetup.lmsType.features.contains(Features.SEB_RESTRICTION)) {
|
||||||
|
return lmsSetup;
|
||||||
|
}
|
||||||
|
|
||||||
|
examDAO.allActiveForLMSSetup(Arrays.asList(lmsSetup.id))
|
||||||
|
.getOrThrow()
|
||||||
|
.forEach( exam -> {
|
||||||
|
this.releaseSEBClientRestriction(exam)
|
||||||
|
.onError(error -> log.warn(
|
||||||
|
"Failed to release SEB Restriction for Exam: {} error: {}",
|
||||||
|
exam.name,
|
||||||
|
error.getMessage()));
|
||||||
|
});
|
||||||
|
|
||||||
|
return lmsSetup;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private Exam applySEBRestrictionIfExamRunning(final Exam exam) {
|
private Exam applySEBRestrictionIfExamRunning(final Exam exam) {
|
||||||
if (exam.status != Exam.ExamStatus.RUNNING) {
|
if (exam.status != Exam.ExamStatus.RUNNING) {
|
||||||
return exam;
|
return exam;
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle;
|
package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle;
|
||||||
|
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
|
import java.net.URLDecoder;
|
||||||
|
import java.net.URLEncoder;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -310,8 +312,6 @@ public class MoodleRestTemplateFactoryImpl implements MoodleRestTemplateFactory
|
||||||
return callMoodleAPIFunction(functionName, null, null);
|
return callMoodleAPIFunction(functionName, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String callMoodleAPIFunction(
|
public String callMoodleAPIFunction(
|
||||||
final String functionName,
|
final String functionName,
|
||||||
|
@ -338,6 +338,14 @@ public class MoodleRestTemplateFactoryImpl implements MoodleRestTemplateFactory
|
||||||
|
|
||||||
final String body = createMoodleFormPostBody(queryAttributes);
|
final String body = createMoodleFormPostBody(queryAttributes);
|
||||||
|
|
||||||
|
// TODO remove this after testing
|
||||||
|
try {
|
||||||
|
final String uriString = URLDecoder.decode(queryParam.toUriString(), "UTF8");
|
||||||
|
log.info("POST To Moodle URI (decoded UTF8): {}, body: {}", uriString, body);
|
||||||
|
} catch (final Exception e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
final HttpHeaders headers = new HttpHeaders();
|
final HttpHeaders headers = new HttpHeaders();
|
||||||
headers.set(
|
headers.set(
|
||||||
HttpHeaders.CONTENT_TYPE,
|
HttpHeaders.CONTENT_TYPE,
|
||||||
|
|
|
@ -105,9 +105,9 @@ public class MoodlePluginFullIntegration implements FullLmsIntegrationAPI {
|
||||||
final String connectionJSON = jsonMapper.writeValueAsString(data);
|
final String connectionJSON = jsonMapper.writeValueAsString(data);
|
||||||
final MoodleAPIRestTemplate rest = getRestTemplate().getOrThrow();
|
final MoodleAPIRestTemplate rest = getRestTemplate().getOrThrow();
|
||||||
|
|
||||||
//if (log.isDebugEnabled()) {
|
if (log.isDebugEnabled()) {
|
||||||
log.info("Try to connect to Moodle Plugin 2.0 with: {}", connectionJSON);
|
log.debug("Try to connect to Moodle Plugin 2.0 with: {}", connectionJSON);
|
||||||
//}
|
}
|
||||||
|
|
||||||
final MultiValueMap<String, String> queryAttributes = new LinkedMultiValueMap<>();
|
final MultiValueMap<String, String> queryAttributes = new LinkedMultiValueMap<>();
|
||||||
queryAttributes.add(ATTRIBUTE_CONNECTION, connectionJSON);
|
queryAttributes.add(ATTRIBUTE_CONNECTION, connectionJSON);
|
||||||
|
@ -141,17 +141,19 @@ public class MoodlePluginFullIntegration implements FullLmsIntegrationAPI {
|
||||||
fullConnectionApplyResponse.warnings.stream()
|
fullConnectionApplyResponse.warnings.stream()
|
||||||
.filter(w -> Objects.equals(w.warningcode, "connectiondoesntmatch"))
|
.filter(w -> Objects.equals(w.warningcode, "connectiondoesntmatch"))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.ifPresent( w -> {
|
.ifPresent(w -> {
|
||||||
|
throw new MoodleResponseException("Failed to apply SEB Server connection due to connection mismatch\n There seems to be another SEB Server already connected to this LMS instance", response);
|
||||||
throw new MoodleResponseException("Failed to apply SEB Server connection due to connection mismatch", response);
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (log.isDebugEnabled()) {
|
if (log.isDebugEnabled()) {
|
||||||
log.debug("Got warnings from Moodle: {}", response);
|
log.debug("Got warnings from Moodle: {}", response);
|
||||||
}
|
}
|
||||||
|
} catch (final MoodleResponseException mre) {
|
||||||
|
throw mre;
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
log.warn("Failed to parse Moodle warnings. Error: {}", e.getMessage());
|
log.warn("Failed to parse Moodle warnings. Error: {}", e.getMessage());
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (log.isDebugEnabled()) {
|
if (log.isDebugEnabled()) {
|
||||||
|
|
|
@ -8,6 +8,10 @@
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.webservice.servicelayer.session;
|
package ch.ethz.seb.sebserver.webservice.servicelayer.session;
|
||||||
|
|
||||||
|
/** Defines a exam update task. Exam update tasks are called in a fixed time interval on the master
|
||||||
|
* Webservice instance to update various exam data like state, LMS data and so on.
|
||||||
|
* A ExamUpdateTask can define a processing order on with the overall scheduler acts. Lower order first processed.
|
||||||
|
*/
|
||||||
public interface ExamUpdateTask {
|
public interface ExamUpdateTask {
|
||||||
|
|
||||||
int examUpdateTaskProcessingOrder();
|
int examUpdateTaskProcessingOrder();
|
||||||
|
|
|
@ -218,7 +218,12 @@ public abstract class ActivatableEntityController<T extends GrantEntity & Activa
|
||||||
(active) ? BulkActionType.ACTIVATE : BulkActionType.DEACTIVATE,
|
(active) ? BulkActionType.ACTIVATE : BulkActionType.DEACTIVATE,
|
||||||
entityType,
|
entityType,
|
||||||
new EntityName(modelId, entityType, entity.getName())));
|
new EntityName(modelId, entityType, entity.getName())));
|
||||||
this.notifySaved(this.entityDAO.byModelId(entity.getModelId()).getOrThrow());
|
final T savedEntity = this.entityDAO.byModelId(entity.getModelId()).getOrThrow();
|
||||||
|
this.notifySaved(
|
||||||
|
savedEntity,
|
||||||
|
active
|
||||||
|
? Activatable.ActivationAction.ACTIVATE
|
||||||
|
: Activatable.ActivationAction.DEACTIVATE);
|
||||||
return createReport;
|
return createReport;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -703,6 +703,10 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Result<T> notifySaved(final T entity) {
|
protected Result<T> notifySaved(final T entity) {
|
||||||
|
return notifySaved(entity, Activatable.ActivationAction.NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Result<T> notifySaved(final T entity, final Activatable.ActivationAction activationAction) {
|
||||||
return Result.of(entity);
|
return Result.of(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,13 @@ package ch.ethz.seb.sebserver.webservice.weblayer.api;
|
||||||
|
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.Activatable;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.FullLmsIntegrationService;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsTestService;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsTestService;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.SEBRestrictionService;
|
||||||
import org.mybatis.dynamic.sql.SqlTable;
|
import org.mybatis.dynamic.sql.SqlTable;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.context.ApplicationEventPublisher;
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
@ -50,8 +55,12 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationSe
|
||||||
@RequestMapping("${sebserver.webservice.api.admin.endpoint}" + API.LMS_SETUP_ENDPOINT)
|
@RequestMapping("${sebserver.webservice.api.admin.endpoint}" + API.LMS_SETUP_ENDPOINT)
|
||||||
public class LmsSetupController extends ActivatableEntityController<LmsSetup, LmsSetup> {
|
public class LmsSetupController extends ActivatableEntityController<LmsSetup, LmsSetup> {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(LmsSetupController.class);
|
||||||
|
|
||||||
private final LmsAPIService lmsAPIService;
|
private final LmsAPIService lmsAPIService;
|
||||||
private final LmsTestService lmsTestService;
|
private final LmsTestService lmsTestService;
|
||||||
|
private final SEBRestrictionService sebRestrictionService;
|
||||||
|
private final FullLmsIntegrationService fullLmsIntegrationService;
|
||||||
final ApplicationEventPublisher applicationEventPublisher;
|
final ApplicationEventPublisher applicationEventPublisher;
|
||||||
|
|
||||||
public LmsSetupController(
|
public LmsSetupController(
|
||||||
|
@ -63,6 +72,8 @@ public class LmsSetupController extends ActivatableEntityController<LmsSetup, Lm
|
||||||
final PaginationService paginationService,
|
final PaginationService paginationService,
|
||||||
final BeanValidationService beanValidationService,
|
final BeanValidationService beanValidationService,
|
||||||
final LmsTestService lmsTestService,
|
final LmsTestService lmsTestService,
|
||||||
|
final SEBRestrictionService sebRestrictionService,
|
||||||
|
final FullLmsIntegrationService fullLmsIntegrationService,
|
||||||
final ApplicationEventPublisher applicationEventPublisher) {
|
final ApplicationEventPublisher applicationEventPublisher) {
|
||||||
|
|
||||||
super(authorization,
|
super(authorization,
|
||||||
|
@ -74,6 +85,8 @@ public class LmsSetupController extends ActivatableEntityController<LmsSetup, Lm
|
||||||
|
|
||||||
this.lmsAPIService = lmsAPIService;
|
this.lmsAPIService = lmsAPIService;
|
||||||
this.lmsTestService = lmsTestService;
|
this.lmsTestService = lmsTestService;
|
||||||
|
this.sebRestrictionService = sebRestrictionService;
|
||||||
|
this.fullLmsIntegrationService = fullLmsIntegrationService;
|
||||||
this.applicationEventPublisher = applicationEventPublisher;
|
this.applicationEventPublisher = applicationEventPublisher;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,9 +161,43 @@ public class LmsSetupController extends ActivatableEntityController<LmsSetup, Lm
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Result<LmsSetup> notifySaved(final LmsSetup entity) {
|
protected Result<LmsSetup> notifySaved(final LmsSetup entity, final Activatable.ActivationAction activation) {
|
||||||
this.applicationEventPublisher.publishEvent(new LmsSetupChangeEvent(entity));
|
this.applicationEventPublisher.publishEvent(new LmsSetupChangeEvent(entity, activation));
|
||||||
return super.notifySaved(entity);
|
return super.notifySaved(entity, activation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Result<LmsSetup> validForActivation(final LmsSetup entity, final boolean activation) {
|
||||||
|
return super.validForActivation(entity, activation)
|
||||||
|
.map(lmsSetup -> {
|
||||||
|
if (!activation) {
|
||||||
|
// on deactivation remove all SEB restrictions and delete full integration if in place
|
||||||
|
return sebRestrictionService
|
||||||
|
.applyLMSSetupDeactivation(lmsSetup)
|
||||||
|
.flatMap(fullLmsIntegrationService::applyLMSSetupDeactivation)
|
||||||
|
.getOrThrow();
|
||||||
|
}
|
||||||
|
return entity;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Result<LmsSetup> validForDelete(final LmsSetup entity) {
|
||||||
|
return Result.tryCatch(() -> {
|
||||||
|
// if there is a SEB Restriction involved, release all SEB Restriction for exams
|
||||||
|
if (entity.lmsType.features.contains(LmsSetup.Features.SEB_RESTRICTION)) {
|
||||||
|
sebRestrictionService
|
||||||
|
.applyLMSSetupDeactivation(entity)
|
||||||
|
.getOrThrow();
|
||||||
|
}
|
||||||
|
// if there is a full LMS integration involved, delete it first on LMS
|
||||||
|
if (entity.lmsType.features.contains(LmsSetup.Features.LMS_FULL_INTEGRATION)) {
|
||||||
|
fullLmsIntegrationService
|
||||||
|
.deleteFullLmsIntegration(entity.id)
|
||||||
|
.getOrThrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
return entity;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -347,6 +347,8 @@ sebserver.lmssetup.type.OPEN_EDX=Open edX
|
||||||
sebserver.lmssetup.type.ANS_DELFT=Ans Delft
|
sebserver.lmssetup.type.ANS_DELFT=Ans Delft
|
||||||
sebserver.lmssetup.type.OPEN_OLAT=OLAT
|
sebserver.lmssetup.type.OPEN_OLAT=OLAT
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
sebserver.lmssetup.list.actions=
|
sebserver.lmssetup.list.actions=
|
||||||
sebserver.lmssetup.list.action.no.modify.privilege=No Access: A Assessment Tool Setup from other institution cannot be modified.
|
sebserver.lmssetup.list.action.no.modify.privilege=No Access: A Assessment Tool Setup from other institution cannot be modified.
|
||||||
sebserver.lmssetup.list.empty=No Assessment Tool Setup can be found. Please adapt the filter or create a new Assessment Tool Setup
|
sebserver.lmssetup.list.empty=No Assessment Tool Setup can be found. Please adapt the filter or create a new Assessment Tool Setup
|
||||||
|
@ -378,6 +380,7 @@ sebserver.lmssetup.action.test.tokenRequestError=The API access was denied:<br/>
|
||||||
sebserver.lmssetup.action.test.quizRequestError=Unable to request courses or exams from the course API of the Assessment Tool. {0}
|
sebserver.lmssetup.action.test.quizRequestError=Unable to request courses or exams from the course API of the Assessment Tool. {0}
|
||||||
sebserver.lmssetup.action.test.quizRestrictionError=Unable to access course restriction API of the Assessment Tool. {0}
|
sebserver.lmssetup.action.test.quizRestrictionError=Unable to access course restriction API of the Assessment Tool. {0}
|
||||||
sebserver.lmssetup.action.test.features.error=The API access was granted but there is some missing functionality:<br/><br/>- Course Access: {0}<br/>- SEB Restriction: {1}
|
sebserver.lmssetup.action.test.features.error=The API access was granted but there is some missing functionality:<br/><br/>- Course Access: {0}<br/>- SEB Restriction: {1}
|
||||||
|
sebserver.lmssetup.action.test.fullintegration.error=Full Assessment Tool Integration failed due to:<br/><br/> {0}
|
||||||
sebserver.lmssetup.action.test.missingParameter=There is one or more missing connection parameter.<br/>Please check the connection parameter for this Assessment Tool Setup
|
sebserver.lmssetup.action.test.missingParameter=There is one or more missing connection parameter.<br/>Please check the connection parameter for this Assessment Tool Setup
|
||||||
sebserver.lmssetup.action.test.unknownError=An unexpected error happened while trying to connect to the Assessment Tool course API. {0}
|
sebserver.lmssetup.action.test.unknownError=An unexpected error happened while trying to connect to the Assessment Tool course API. {0}
|
||||||
sebserver.lmssetup.action.test.quizRequestError.moodle.missing.plugin=Moodle SEB Server integration plugin cannot be detected on this Moodle server.<br/>Please consider using the origin "Moodle" Assessment Tool Setup type or install the SEB Server integration plugin on this Moodle server.<br/><br/>For further information please refer to the <a target="_blank" href="https://seb-server.readthedocs.io/en/latest/#">documentation</a>
|
sebserver.lmssetup.action.test.quizRequestError.moodle.missing.plugin=Moodle SEB Server integration plugin cannot be detected on this Moodle server.<br/>Please consider using the origin "Moodle" Assessment Tool Setup type or install the SEB Server integration plugin on this Moodle server.<br/><br/>For further information please refer to the <a target="_blank" href="https://seb-server.readthedocs.io/en/latest/#">documentation</a>
|
||||||
|
@ -387,6 +390,7 @@ sebserver.lmssetup.action.save=Save Assessment Tool Setup
|
||||||
sebserver.lmssetup.action.activate=Activate Assessment Tool Setup
|
sebserver.lmssetup.action.activate=Activate Assessment Tool Setup
|
||||||
sebserver.lmssetup.action.deactivate=Deactivate Assessment Tool Setup
|
sebserver.lmssetup.action.deactivate=Deactivate Assessment Tool Setup
|
||||||
sebserver.lmssetup.action.delete=Delete Assessment Tool Setup
|
sebserver.lmssetup.action.delete=Delete Assessment Tool Setup
|
||||||
|
sebserver.lmssetup.action.activation.error=Failed to activate/deactivate Assessment Tool Setup.<br/>Please open the Assessment Tool Setup and test the connection and make sure connection data is correct.
|
||||||
|
|
||||||
sebserver.lmssetup.info.pleaseSelect=At first please select an Assessment Tool Setup from the list
|
sebserver.lmssetup.info.pleaseSelect=At first please select an Assessment Tool Setup from the list
|
||||||
|
|
||||||
|
|
60
src/test/java/ch/ethz/seb/sebserver/gbl/JSONParserTest.java
Normal file
60
src/test/java/ch/ethz/seb/sebserver/gbl/JSONParserTest.java
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 ETH Zürich, IT Services
|
||||||
|
*
|
||||||
|
* 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.gbl;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class JSONParserTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSpecialChar1() throws JsonProcessingException {
|
||||||
|
final String json = """
|
||||||
|
{"meta_data": {
|
||||||
|
"param1": "value—dvgswg",
|
||||||
|
"param2": "value2-dvgswg",
|
||||||
|
"param3": "value3",
|
||||||
|
"param4": "value4-%ç/&=&&çETZGFIUZHàPIHBNHK VG$ä$à£à!èéLèPLIOU=(&&(Rç%çE"
|
||||||
|
}}""";
|
||||||
|
|
||||||
|
final JSONMapper jsonMapper = new JSONMapper();
|
||||||
|
final MetaData metaData = jsonMapper.readValue(json, MetaData.class);
|
||||||
|
assertEquals("MetaData{meta_data={param1=value—dvgswg, param2=value2-dvgswg, param3=value3, param4=value4-%ç/&=&&çETZGFIUZHàPIHBNHK VG$ä$à£à!èéLèPLIOU=(&&(Rç%çE}}", metaData.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public static final class MetaData {
|
||||||
|
@JsonProperty("meta_data")
|
||||||
|
public final Map<String, String> meta_data;
|
||||||
|
|
||||||
|
|
||||||
|
@JsonCreator
|
||||||
|
private MetaData(
|
||||||
|
@JsonProperty("meta_data") final Map<String, String> metaData) {
|
||||||
|
|
||||||
|
meta_data = metaData;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "MetaData{" +
|
||||||
|
"meta_data=" + meta_data +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue