fixes for testing version 0.2

This commit is contained in:
anhefti 2019-04-08 21:11:01 +02:00
parent e85f240aec
commit 7afa633a3c
19 changed files with 231 additions and 68 deletions

View file

@ -46,6 +46,10 @@ public final class API {
public static final String LMS_SETUP_TEST_ENDPOINT = LMS_SETUP_ENDPOINT public static final String LMS_SETUP_TEST_ENDPOINT = LMS_SETUP_ENDPOINT
+ LMS_SETUP_TEST_PATH_SEGMENT + LMS_SETUP_TEST_PATH_SEGMENT
+ MODEL_ID_VAR_PATH_SEGMENT; + MODEL_ID_VAR_PATH_SEGMENT;
public static final String LMS_SETUP_TEST_AD_HOC_PATH_SEGMENT = "/adhoc";
public static final String LMS_SETUP_TEST_AD_HOC_ENDPOINT = LMS_SETUP_ENDPOINT
+ LMS_SETUP_TEST_PATH_SEGMENT
+ LMS_SETUP_TEST_AD_HOC_PATH_SEGMENT;
public static final String USER_ACCOUNT_ENDPOINT = "/useraccount"; public static final String USER_ACCOUNT_ENDPOINT = "/useraccount";

View file

@ -195,9 +195,7 @@ public class ExamForm implements TemplateComposer {
"sebserver.exam.form.status", "sebserver.exam.form.status",
i18nSupport.getText(new LocTextKey("sebserver.exam.status." + examStatus.name()))) i18nSupport.getText(new LocTextKey("sebserver.exam.status." + examStatus.name())))
.readonly(true)) .readonly(true))
.addFieldIf( .addField(FormBuilder.multiComboSelection(
isNotNew,
() -> FormBuilder.multiComboSelection(
Domain.EXAM.ATTR_SUPPORTER, Domain.EXAM.ATTR_SUPPORTER,
"sebserver.exam.form.supporter", "sebserver.exam.form.supporter",
StringUtils.join(exam.supporter, Constants.LIST_SEPARATOR_CHAR), StringUtils.join(exam.supporter, Constants.LIST_SEPARATOR_CHAR),
@ -228,17 +226,6 @@ public class ExamForm implements TemplateComposer {
.withExec(this::cancelModify) .withExec(this::cancelModify)
.publishIf(() -> !readonly); .publishIf(() -> !readonly);
// .newAction(ActionDefinition.EXAM_DEACTIVATE)
// .withEntityKey(entityKey)
// .withSimpleRestCall(restService, DeactivateExam.class)
// .withConfirm(PageUtils.confirmDeactivation(exam, restService))
// .publishIf(() -> writeGrant && readonly && exam.isActive())
//
// .newAction(ActionDefinition.EXAM_ACTIVATE)
// .withEntityKey(entityKey)
// .withSimpleRestCall(restService, ActivateExam.class)
// .publishIf(() -> writeGrant && readonly && !exam.isActive());
// additional data in read-only view // additional data in read-only view
if (readonly) { if (readonly) {
@ -250,6 +237,9 @@ public class ExamForm implements TemplateComposer {
final EntityTable<Indicator> indicatorTable = final EntityTable<Indicator> indicatorTable =
this.pageService.entityTableBuilder(restService.getRestCall(GetIndicators.class)) this.pageService.entityTableBuilder(restService.getRestCall(GetIndicators.class))
.withRestCallAdapter(builder -> builder.withQueryParam(
Indicator.FILTER_ATTR_EXAM,
entityKey.modelId))
.withEmptyMessage(new LocTextKey("sebserver.exam.indicator.list.empty")) .withEmptyMessage(new LocTextKey("sebserver.exam.indicator.list.empty"))
.withPaging(5) .withPaging(5)
.hideNavigation() .hideNavigation()

View file

@ -129,9 +129,7 @@ public class InstitutionForm implements TemplateComposer {
Domain.INSTITUTION.ATTR_URL_SUFFIX, Domain.INSTITUTION.ATTR_URL_SUFFIX,
"sebserver.institution.form.urlSuffix", "sebserver.institution.form.urlSuffix",
institution.urlSuffix)) institution.urlSuffix))
.addFieldIf( .addField(FormBuilder.imageUpload(
() -> !isNew && modifyGrant,
() -> FormBuilder.imageUpload(
Domain.INSTITUTION.ATTR_LOGO_IMAGE, Domain.INSTITUTION.ATTR_LOGO_IMAGE,
"sebserver.institution.form.logoImage", "sebserver.institution.form.logoImage",
institution.logoImage)) institution.logoImage))

View file

@ -9,6 +9,7 @@
package ch.ethz.seb.sebserver.gui.content; package ch.ethz.seb.sebserver.gui.content;
import java.util.function.BooleanSupplier; import java.util.function.BooleanSupplier;
import java.util.function.Function;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
@ -47,6 +48,7 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.GetLmsSe
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.NewLmsSetup; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.NewLmsSetup;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.SaveLmsSetup; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.SaveLmsSetup;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.TestLmsSetup; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.TestLmsSetup;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.TestLmsSetupAdHoc;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.EntityGrantCheck; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.EntityGrantCheck;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@ -155,21 +157,15 @@ public class LmsSetupForm implements TemplateComposer {
(lmsType != null) ? lmsType.name() : null, (lmsType != null) ? lmsType.name() : null,
this.resourceService::lmsTypeResources) this.resourceService::lmsTypeResources)
.readonlyIf(isNotNew)) .readonlyIf(isNotNew))
.addFieldIf( .addField(FormBuilder.text(
() -> isNotNew.getAsBoolean(),
() -> FormBuilder.text(
Domain.LMS_SETUP.ATTR_LMS_URL, Domain.LMS_SETUP.ATTR_LMS_URL,
"sebserver.lmssetup.form.url", "sebserver.lmssetup.form.url",
lmsSetup.getLmsApiUrl())) lmsSetup.getLmsApiUrl()))
.addFieldIf( .addField(FormBuilder.text(
() -> isNotNew.getAsBoolean(),
() -> FormBuilder.text(
Domain.LMS_SETUP.ATTR_LMS_CLIENTNAME, Domain.LMS_SETUP.ATTR_LMS_CLIENTNAME,
"sebserver.lmssetup.form.clientname.lms", "sebserver.lmssetup.form.clientname.lms",
lmsSetup.getLmsAuthName())) lmsSetup.getLmsAuthName()))
.addFieldIf( .addField(FormBuilder.text(
() -> isNotNew.getAsBoolean(),
() -> FormBuilder.text(
Domain.LMS_SETUP.ATTR_LMS_CLIENTSECRET, Domain.LMS_SETUP.ATTR_LMS_CLIENTSECRET,
"sebserver.lmssetup.form.secret.lms") "sebserver.lmssetup.form.secret.lms")
.asPasswordField()) .asPasswordField())
@ -196,6 +192,12 @@ public class LmsSetupForm implements TemplateComposer {
.ignoreMoveAwayFromEdit() .ignoreMoveAwayFromEdit()
.publishIf(() -> modifyGrant && isNotNew.getAsBoolean() && !readonly) .publishIf(() -> modifyGrant && isNotNew.getAsBoolean() && !readonly)
.newAction(ActionDefinition.LMS_SETUP_TEST_AND_SAVE)
.withEntityKey(entityKey)
.withExec(action -> this.testAdHoc(action, formHandle))
.ignoreMoveAwayFromEdit()
.publishIf(() -> modifyGrant && isNew.getAsBoolean() && !readonly)
.newAction(ActionDefinition.LMS_SETUP_DEACTIVATE) .newAction(ActionDefinition.LMS_SETUP_DEACTIVATE)
.withEntityKey(entityKey) .withEntityKey(entityKey)
.withSimpleRestCall(restService, DeactivateLmsSetup.class) .withSimpleRestCall(restService, DeactivateLmsSetup.class)
@ -236,6 +238,40 @@ public class LmsSetupForm implements TemplateComposer {
return testLmsSetup; return testLmsSetup;
} }
/** LmsSetup test action implementation */
private PageAction testAdHoc(final PageAction action, final FormHandle<LmsSetup> formHandle) {
// reset previous errors
formHandle.process(
name -> true,
fieldAccessor -> fieldAccessor.resetError());
// first test the connection on ad hoc object
final Result<LmsSetupTestResult> result = this.resourceService.getRestService()
.getBuilder(TestLmsSetupAdHoc.class)
.withFormBinding(formHandle.getFormBinding())
.call();
// ... and handle the response
if (result.hasError()) {
if (formHandle.handleError(result.getError())) {
throw new PageMessageException(
new LocTextKey("sebserver.lmssetup.action.test.missingParameter"));
}
}
return handleTestResult(
action,
a -> {
// try to save the LmsSetup
final PageAction processFormSave = formHandle.processFormSave(a);
processFormSave.pageContext().publishInfo(
new LocTextKey("sebserver.lmssetup.action.test.ok"));
return processFormSave;
},
result.getOrThrow());
}
/** LmsSetup test action implementation */ /** LmsSetup test action implementation */
private PageAction testLmsSetup(final PageAction action, final FormHandle<LmsSetup> formHandle) { private PageAction testLmsSetup(final PageAction action, final FormHandle<LmsSetup> formHandle) {
// If we are in edit-mode we have to save the form before testing // If we are in edit-mode we have to save the form before testing
@ -262,13 +298,24 @@ public class LmsSetupForm implements TemplateComposer {
} }
} }
final LmsSetupTestResult testResult = result.getOrThrow(); return handleTestResult(
action,
if (testResult.isOk()) { a -> {
action.pageContext().publishInfo( action.pageContext().publishInfo(
new LocTextKey("sebserver.lmssetup.action.test.ok")); new LocTextKey("sebserver.lmssetup.action.test.ok"));
return action; return action;
},
result.getOrThrow());
}
private PageAction handleTestResult(
final PageAction action,
final Function<PageAction, PageAction> onOK,
final LmsSetupTestResult testResult) {
if (testResult.isOk()) {
return onOK.apply(action);
} else if (StringUtils.isNoneBlank(testResult.tokenRequestError)) { } else if (StringUtils.isNoneBlank(testResult.tokenRequestError)) {
throw new PageMessageException( throw new PageMessageException(
new LocTextKey("sebserver.lmssetup.action.test.tokenRequestError", new LocTextKey("sebserver.lmssetup.action.test.tokenRequestError",

View file

@ -117,7 +117,7 @@ public class UserAccountChangePasswordForm implements TemplateComposer {
pageContext.getShell(), pageContext.getShell(),
this.i18nSupport.getText("sebserver.login.password.change"), this.i18nSupport.getText("sebserver.login.password.change"),
this.i18nSupport.getText("sebserver.login.password.change.success"), this.i18nSupport.getText("sebserver.login.password.change.success"),
SWT.ERROR); SWT.ICON_INFORMATION);
error.open(null); error.open(null);
} }
return saveAction; return saveAction;

View file

@ -138,6 +138,9 @@ public class UserAccountForm implements TemplateComposer {
.putStaticValueIf(isNotNew, .putStaticValueIf(isNotNew,
Domain.USER.ATTR_INSTITUTION_ID, Domain.USER.ATTR_INSTITUTION_ID,
String.valueOf(userAccount.getInstitutionId())) String.valueOf(userAccount.getInstitutionId()))
.putStaticValue(
Domain.USER.ATTR_LANGUAGE,
"en")
.addFieldIf( .addFieldIf(
isSEBAdmin, isSEBAdmin,
() -> FormBuilder.singleSelection( () -> FormBuilder.singleSelection(
@ -158,12 +161,12 @@ public class UserAccountForm implements TemplateComposer {
Domain.USER.ATTR_EMAIL, Domain.USER.ATTR_EMAIL,
"sebserver.useraccount.form.mail", "sebserver.useraccount.form.mail",
userAccount.getEmail())) userAccount.getEmail()))
.addField(FormBuilder.singleSelection( // .addField(FormBuilder.singleSelection(
Domain.USER.ATTR_LANGUAGE, // Domain.USER.ATTR_LANGUAGE,
"sebserver.useraccount.form.language", // "sebserver.useraccount.form.language",
userAccount.getLanguage().getLanguage(), // userAccount.getLanguage().getLanguage(),
this.resourceService::languageResources) // this.resourceService::languageResources)
.readonly(true)) // .readonly(true))
.addField(FormBuilder.singleSelection( .addField(FormBuilder.singleSelection(
Domain.USER.ATTR_TIMEZONE, Domain.USER.ATTR_TIMEZONE,
"sebserver.useraccount.form.timezone", "sebserver.useraccount.form.timezone",

View file

@ -150,6 +150,11 @@ public enum ActionDefinition {
ImageIcon.TEST, ImageIcon.TEST,
PageStateDefinition.LMS_SETUP_EDIT, PageStateDefinition.LMS_SETUP_EDIT,
ActionCategory.FORM), ActionCategory.FORM),
LMS_SETUP_TEST_AND_SAVE(
new LocTextKey("sebserver.lmssetup.action.testsave"),
ImageIcon.TEST,
PageStateDefinition.LMS_SETUP_VIEW,
ActionCategory.FORM),
LMS_SETUP_CANCEL_MODIFY( LMS_SETUP_CANCEL_MODIFY(
new LocTextKey("sebserver.overall.action.modify.cancel"), new LocTextKey("sebserver.overall.action.modify.cancel"),
ImageIcon.CANCEL, ImageIcon.CANCEL,

View file

@ -9,6 +9,7 @@
package ch.ethz.seb.sebserver.gui.form; package ch.ethz.seb.sebserver.gui.form;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Predicate;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -23,6 +24,7 @@ import ch.ethz.seb.sebserver.gui.service.page.FieldValidationError;
import ch.ethz.seb.sebserver.gui.service.page.PageContext; import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.PageService; import ch.ethz.seb.sebserver.gui.service.page.PageService;
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction; import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.FormBinding;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCallError; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCallError;
@ -51,6 +53,10 @@ public class FormHandle<T extends Entity> {
this.i18nSupport = pageService.getI18nSupport(); this.i18nSupport = pageService.getI18nSupport();
} }
public FormBinding getFormBinding() {
return this.form;
}
/** Process an API post request to send and save the form field values /** Process an API post request to send and save the form field values
* to the webservice and publishes a page event to return to read-only-view * to the webservice and publishes a page event to return to read-only-view
* to indicate that the data was successfully saved or process an validation * to indicate that the data was successfully saved or process an validation
@ -69,10 +75,12 @@ public class FormHandle<T extends Entity> {
* *
* @return the response result of the post (or put) RestCall */ * @return the response result of the post (or put) RestCall */
public Result<T> doAPIPost() { public Result<T> doAPIPost() {
// reset all errors that may still be displayed
this.form.process( this.form.process(
name -> true, name -> true,
fieldAccessor -> fieldAccessor.resetError()); fieldAccessor -> fieldAccessor.resetError());
// post
return this.post return this.post
.newBuilder() .newBuilder()
.withFormBinding(this.form) .withFormBinding(this.form)
@ -135,8 +143,11 @@ public class FormHandle<T extends Entity> {
(Object[]) valError.getAttributes()))); (Object[]) valError.getAttributes())));
} }
public FormHandle<T> process(final Consumer<Form> consumer) { public FormHandle<T> process(
consumer.accept(this.form); final Predicate<String> nameFilter,
final Consumer<FormFieldAccessor> processor) {
this.form.process(nameFilter, processor);
return this; return this;
} }

View file

@ -13,6 +13,7 @@ import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Function;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -186,6 +187,10 @@ public abstract class RestCall<T> {
return this; return this;
} }
public RestCallBuilder apply(final Function<RestCallBuilder, RestCallBuilder> f) {
return f.apply(this);
}
public RestCallBuilder withBody(final Object body) { public RestCallBuilder withBody(final Object body) {
if (body instanceof String) { if (body instanceof String) {
this.body = String.valueOf(body); this.body = String.valueOf(body);

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.core.type.TypeReference;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetupTestResult;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
@Lazy
@Component
@GuiProfile
public class TestLmsSetupAdHoc extends RestCall<LmsSetupTestResult> {
protected TestLmsSetupAdHoc() {
super(new TypeKey<>(
CallType.UNDEFINED,
EntityType.LMS_SETUP,
new TypeReference<LmsSetupTestResult>() {
}),
HttpMethod.PUT,
MediaType.APPLICATION_JSON_UTF8,
API.LMS_SETUP_TEST_AD_HOC_ENDPOINT);
}
}

View file

@ -56,6 +56,7 @@ public class EntityTable<ROW extends Entity> {
final PageService pageService; final PageService pageService;
final WidgetFactory widgetFactory; final WidgetFactory widgetFactory;
final RestCall<Page<ROW>> restCall; final RestCall<Page<ROW>> restCall;
final Function<RestCall<Page<ROW>>.RestCallBuilder, RestCall<Page<ROW>>.RestCallBuilder> restCallAdapter;
final I18nSupport i18nSupport; final I18nSupport i18nSupport;
final List<ColumnDefinition<ROW>> columns; final List<ColumnDefinition<ROW>> columns;
@ -78,6 +79,7 @@ public class EntityTable<ROW extends Entity> {
final int type, final int type,
final Composite parent, final Composite parent,
final RestCall<Page<ROW>> restCall, final RestCall<Page<ROW>> restCall,
final Function<RestCall<Page<ROW>>.RestCallBuilder, RestCall<Page<ROW>>.RestCallBuilder> restCallAdapter,
final PageService pageService, final PageService pageService,
final List<ColumnDefinition<ROW>> columns, final List<ColumnDefinition<ROW>> columns,
final List<TableRowAction> actions, final List<TableRowAction> actions,
@ -91,6 +93,7 @@ public class EntityTable<ROW extends Entity> {
this.i18nSupport = pageService.getI18nSupport(); this.i18nSupport = pageService.getI18nSupport();
this.widgetFactory = pageService.getWidgetFactory(); this.widgetFactory = pageService.getWidgetFactory();
this.restCall = restCall; this.restCall = restCall;
this.restCallAdapter = (restCallAdapter != null) ? restCallAdapter : Function.identity();
this.columns = Utils.immutableListOf(columns); this.columns = Utils.immutableListOf(columns);
this.actions = Utils.immutableListOf(actions); this.actions = Utils.immutableListOf(actions);
this.emptyMessage = emptyMessage; this.emptyMessage = emptyMessage;
@ -288,6 +291,7 @@ public class EntityTable<ROW extends Entity> {
.withPaging(pageNumber, pageSize) .withPaging(pageNumber, pageSize)
.withSorting(sortColumn, sortOrder) .withSorting(sortColumn, sortOrder)
.withQueryParams((this.filter != null) ? this.filter.getFilterParameter() : null) .withQueryParams((this.filter != null) ? this.filter.getFilterParameter() : null)
.apply(this.restCallAdapter)
.call() .call()
.map(this::createTableRowsFromPage) .map(this::createTableRowsFromPage)
.map(this.navigator::update) .map(this.navigator::update)

View file

@ -50,6 +50,7 @@ public class TableBuilder<ROW extends Entity> {
private int pageSize = -1; private int pageSize = -1;
private int type = SWT.NONE; private int type = SWT.NONE;
private boolean hideNavigation = false; private boolean hideNavigation = false;
private Function<RestCall<Page<ROW>>.RestCallBuilder, RestCall<Page<ROW>>.RestCallBuilder> restCallAdapter;;
public TableBuilder( public TableBuilder(
final PageService pageService, final PageService pageService,
@ -94,6 +95,12 @@ public class TableBuilder<ROW extends Entity> {
return this; return this;
} }
public TableBuilder<ROW> withRestCallAdapter(
final Function<RestCall<Page<ROW>>.RestCallBuilder, RestCall<Page<ROW>>.RestCallBuilder> adapter) {
this.restCallAdapter = adapter;
return this;
}
public TableBuilder<ROW> withMultiselection() { public TableBuilder<ROW> withMultiselection() {
this.type |= SWT.MULTI; this.type |= SWT.MULTI;
return this; return this;
@ -125,6 +132,7 @@ public class TableBuilder<ROW extends Entity> {
this.type, this.type,
parent, parent,
this.restCall, this.restCall,
this.restCallAdapter,
this.pageService, this.pageService,
this.columns, this.columns,
this.actions, this.actions,

View file

@ -197,7 +197,9 @@ public class ExamDAOImpl implements ExamDAO {
exam.lmsSetupId, exam.lmsSetupId,
exam.externalId, exam.externalId,
exam.owner, exam.owner,
null, (exam.supporter != null)
? StringUtils.join(exam.supporter, Constants.LIST_SEPARATOR_CHAR)
: null,
(exam.type != null) ? exam.type.name() : ExamType.UNDEFINED.name(), (exam.type != null) ? exam.type.name() : ExamType.UNDEFINED.name(),
null, null,
BooleanUtils.toInteger(true)); BooleanUtils.toInteger(true));

View file

@ -45,14 +45,14 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.dao.TransactionHandler;
public class LmsSetupDAOImpl implements LmsSetupDAO { public class LmsSetupDAOImpl implements LmsSetupDAO {
private final LmsSetupRecordMapper lmsSetupRecordMapper; private final LmsSetupRecordMapper lmsSetupRecordMapper;
private final ClientCredentialService internalEncryptionService; private final ClientCredentialService clientCredentialService;
protected LmsSetupDAOImpl( protected LmsSetupDAOImpl(
final LmsSetupRecordMapper lmsSetupRecordMapper, final LmsSetupRecordMapper lmsSetupRecordMapper,
final ClientCredentialService internalEncryptionService) { final ClientCredentialService clientCredentialService) {
this.lmsSetupRecordMapper = lmsSetupRecordMapper; this.lmsSetupRecordMapper = lmsSetupRecordMapper;
this.internalEncryptionService = internalEncryptionService; this.clientCredentialService = clientCredentialService;
} }
@Override @Override
@ -130,7 +130,7 @@ public class LmsSetupDAOImpl implements LmsSetupDAO {
public Result<LmsSetup> save(final LmsSetup lmsSetup) { public Result<LmsSetup> save(final LmsSetup lmsSetup) {
return Result.tryCatch(() -> { return Result.tryCatch(() -> {
final ClientCredentials lmsCredentials = this.internalEncryptionService.encryptedClientCredentials( final ClientCredentials lmsCredentials = this.clientCredentialService.encryptedClientCredentials(
new ClientCredentials( new ClientCredentials(
lmsSetup.lmsAuthName, lmsSetup.lmsAuthName,
lmsSetup.lmsAuthSecret, lmsSetup.lmsAuthSecret,
@ -159,7 +159,7 @@ public class LmsSetupDAOImpl implements LmsSetupDAO {
public Result<LmsSetup> createNew(final LmsSetup lmsSetup) { public Result<LmsSetup> createNew(final LmsSetup lmsSetup) {
return Result.tryCatch(() -> { return Result.tryCatch(() -> {
final ClientCredentials lmsCredentials = this.internalEncryptionService.encryptedClientCredentials( final ClientCredentials lmsCredentials = this.clientCredentialService.encryptedClientCredentials(
new ClientCredentials( new ClientCredentials(
lmsSetup.lmsAuthName, lmsSetup.lmsAuthName,
lmsSetup.lmsAuthSecret, lmsSetup.lmsAuthSecret,
@ -311,8 +311,8 @@ public class LmsSetupDAOImpl implements LmsSetupDAO {
record.getLmsClientsecret(), record.getLmsClientsecret(),
record.getLmsRestApiToken()); record.getLmsRestApiToken());
final CharSequence plainClientId = this.internalEncryptionService.getPlainClientId(clientCredentials); final CharSequence plainClientId = this.clientCredentialService.getPlainClientId(clientCredentials);
final CharSequence plainAccessToken = this.internalEncryptionService.getPlainAccessToken(clientCredentials); final CharSequence plainAccessToken = this.clientCredentialService.getPlainAccessToken(clientCredentials);
return Result.tryCatch(() -> new LmsSetup( return Result.tryCatch(() -> new LmsSetup(
record.getId(), record.getId(),

View file

@ -19,6 +19,8 @@ import org.joda.time.DateTime;
import ch.ethz.seb.sebserver.gbl.model.Page; import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gbl.model.exam.QuizData; import ch.ethz.seb.sebserver.gbl.model.exam.QuizData;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetupTestResult;
import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
@ -44,6 +46,13 @@ public interface LmsAPIService {
* @return LmsAPITemplate for specified LmsSetup configuration */ * @return LmsAPITemplate for specified LmsSetup configuration */
Result<LmsAPITemplate> getLmsAPITemplate(String lmsSetupId); Result<LmsAPITemplate> getLmsAPITemplate(String lmsSetupId);
/** This can be used to test an LmsSetup connection parameter without saving or heaving
* an already persistent version of an LmsSetup.
*
* @param lmsSetup
* @return */
LmsSetupTestResult testAdHoc(LmsSetup lmsSetup);
/** Get a LmsAPITemplate for specified LmsSetup configuration by primary key /** Get a LmsAPITemplate for specified LmsSetup configuration by primary key
* *
* @param lmsSetupId the primary key of the LmsSetup * @param lmsSetupId the primary key of the LmsSetup

View file

@ -28,6 +28,7 @@ import ch.ethz.seb.sebserver.gbl.async.AsyncService;
import ch.ethz.seb.sebserver.gbl.model.Page; import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gbl.model.exam.QuizData; import ch.ethz.seb.sebserver.gbl.model.exam.QuizData;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup; import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetupTestResult;
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.client.ClientCredentialService; import ch.ethz.seb.sebserver.webservice.servicelayer.client.ClientCredentialService;
@ -140,6 +141,17 @@ public class LmsAPIServiceImpl implements LmsAPIService {
.flatMap(this::getLmsAPITemplate); .flatMap(this::getLmsAPITemplate);
} }
@Override
public LmsSetupTestResult testAdHoc(final LmsSetup lmsSetup) {
final ClientCredentials lmsCredentials = this.clientCredentialService.encryptedClientCredentials(
new ClientCredentials(
lmsSetup.lmsAuthName,
lmsSetup.lmsAuthSecret,
lmsSetup.lmsRestApiToken));
return createLmsSetupTemplate(lmsSetup, lmsCredentials).testLmsSetup();
}
private Result<LmsAPITemplate> getLmsAPITemplate(final LmsSetup lmsSetup) { private Result<LmsAPITemplate> getLmsAPITemplate(final LmsSetup lmsSetup) {
return Result.tryCatch(() -> { return Result.tryCatch(() -> {
LmsAPITemplate lmsAPITemplate = getFromCache(lmsSetup); LmsAPITemplate lmsAPITemplate = getFromCache(lmsSetup);
@ -176,6 +188,10 @@ public class LmsAPIServiceImpl implements LmsAPIService {
.getLmsAPIAccessCredentials(lmsSetup.getModelId()) .getLmsAPIAccessCredentials(lmsSetup.getModelId())
.getOrThrow(); .getOrThrow();
return createLmsSetupTemplate(lmsSetup, credentials);
}
private LmsAPITemplate createLmsSetupTemplate(final LmsSetup lmsSetup, final ClientCredentials credentials) {
switch (lmsSetup.lmsType) { switch (lmsSetup.lmsType) {
case MOCKUP: case MOCKUP:
return new MockupLmsAPITemplate( return new MockupLmsAPITemplate(
@ -231,5 +247,4 @@ public class LmsAPIServiceImpl implements LmsAPIService {
return true; return true;
} }
} }
} }

View file

@ -8,10 +8,13 @@
package ch.ethz.seb.sebserver.webservice.weblayer.api; package ch.ethz.seb.sebserver.webservice.weblayer.api;
import javax.validation.Valid;
import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.SqlTable;
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;
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;
@ -77,7 +80,7 @@ public class LmsSetupController extends ActivatableEntityController<LmsSetup, Lm
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 LmsSetupTestResult connectionReport( public LmsSetupTestResult testLms(
@RequestParam( @RequestParam(
name = Entity.FILTER_ATTR_INSTITUTION, name = Entity.FILTER_ATTR_INSTITUTION,
required = true, required = true,
@ -100,6 +103,23 @@ public class LmsSetupController extends ActivatableEntityController<LmsSetup, Lm
return result; return result;
} }
@RequestMapping(
path = API.LMS_SETUP_TEST_PATH_SEGMENT + API.LMS_SETUP_TEST_AD_HOC_PATH_SEGMENT,
method = RequestMethod.PUT,
consumes = MediaType.APPLICATION_JSON_UTF8_VALUE,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public LmsSetupTestResult testLmsAdHoc(@Valid @RequestBody final LmsSetup lmsSetup) {
this.authorization.checkModify(lmsSetup);
final LmsSetupTestResult result = this.lmsAPIService.testAdHoc(lmsSetup);
if (result.missingLMSSetupAttribute != null && !result.missingLMSSetupAttribute.isEmpty()) {
throw new APIMessageException(result.missingLMSSetupAttribute);
}
return result;
}
@Override @Override
protected LmsSetup createNew(final POSTMapper postParams) { protected LmsSetup createNew(final POSTMapper postParams) {
return new LmsSetup(null, postParams); return new LmsSetup(null, postParams);

View file

@ -169,7 +169,8 @@ sebserver.lmssetup.action.new=New LMS Setup
sebserver.lmssetup.action.list.view=View LMS Setup sebserver.lmssetup.action.list.view=View LMS Setup
sebserver.lmssetup.action.list.modify=Edit LMS Setup sebserver.lmssetup.action.list.modify=Edit LMS Setup
sebserver.lmssetup.action.modify=Edit sebserver.lmssetup.action.modify=Edit
sebserver.lmssetup.action.test=Test Setup sebserver.lmssetup.action.test=Test
sebserver.lmssetup.action.testsave=Test And Save
sebserver.lmssetup.action.test.ok=Successfully connected to the course API sebserver.lmssetup.action.test.ok=Successfully connected to the course API
sebserver.lmssetup.action.test.tokenRequestError=The API access was denied: {0} sebserver.lmssetup.action.test.tokenRequestError=The API access was denied: {0}
sebserver.lmssetup.action.test.quizRequestError=Unable to request courses or quizzes from the course API of the LMS. {0} sebserver.lmssetup.action.test.quizRequestError=Unable to request courses or quizzes from the course API of the LMS. {0}

View file

@ -169,7 +169,8 @@ sebserver.lmssetup.action.new=Add LMS Setup
sebserver.lmssetup.action.list.view=View LMS Setup sebserver.lmssetup.action.list.view=View LMS Setup
sebserver.lmssetup.action.list.modify=Edit LMS Setup sebserver.lmssetup.action.list.modify=Edit LMS Setup
sebserver.lmssetup.action.modify=Edit sebserver.lmssetup.action.modify=Edit
sebserver.lmssetup.action.test=Test Setup sebserver.lmssetup.action.test=Test
sebserver.lmssetup.action.testsave=Test And Save
sebserver.lmssetup.action.test.ok=Successfully connected to the course API sebserver.lmssetup.action.test.ok=Successfully connected to the course API
sebserver.lmssetup.action.test.tokenRequestError=The API access was denied: {0} sebserver.lmssetup.action.test.tokenRequestError=The API access was denied: {0}
sebserver.lmssetup.action.test.quizRequestError=Unable to request courses or quizzes from the course API of the LMS. {0} sebserver.lmssetup.action.test.quizRequestError=Unable to request courses or quizzes from the course API of the LMS. {0}