fixes for testing version 0.2
This commit is contained in:
		
							parent
							
								
									e85f240aec
								
							
						
					
					
						commit
						7afa633a3c
					
				
					 19 changed files with 231 additions and 68 deletions
				
			
		|  | @ -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"; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -195,13 +195,11 @@ 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, |                         Domain.EXAM.ATTR_SUPPORTER, | ||||||
|                         () -> FormBuilder.multiComboSelection( |                         "sebserver.exam.form.supporter", | ||||||
|                                 Domain.EXAM.ATTR_SUPPORTER, |                         StringUtils.join(exam.supporter, Constants.LIST_SEPARATOR_CHAR), | ||||||
|                                 "sebserver.exam.form.supporter", |                         this.resourceService::examSupporterResources)) | ||||||
|                                 StringUtils.join(exam.supporter, Constants.LIST_SEPARATOR_CHAR), |  | ||||||
|                                 this.resourceService::examSupporterResources)) |  | ||||||
| 
 | 
 | ||||||
|                 .buildFor(importFromQuizData |                 .buildFor(importFromQuizData | ||||||
|                         ? restService.getRestCall(ImportAsExam.class) |                         ? restService.getRestCall(ImportAsExam.class) | ||||||
|  | @ -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() | ||||||
|  |  | ||||||
|  | @ -129,12 +129,10 @@ 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, |                         Domain.INSTITUTION.ATTR_LOGO_IMAGE, | ||||||
|                         () -> FormBuilder.imageUpload( |                         "sebserver.institution.form.logoImage", | ||||||
|                                 Domain.INSTITUTION.ATTR_LOGO_IMAGE, |                         institution.logoImage)) | ||||||
|                                 "sebserver.institution.form.logoImage", |  | ||||||
|                                 institution.logoImage)) |  | ||||||
|                 .buildFor((isNew) |                 .buildFor((isNew) | ||||||
|                         ? this.restService.getRestCall(NewInstitution.class) |                         ? this.restService.getRestCall(NewInstitution.class) | ||||||
|                         : this.restService.getRestCall(SaveInstitution.class)); |                         : this.restService.getRestCall(SaveInstitution.class)); | ||||||
|  |  | ||||||
|  | @ -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,24 +157,18 @@ 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(), |                         Domain.LMS_SETUP.ATTR_LMS_URL, | ||||||
|                         () -> FormBuilder.text( |                         "sebserver.lmssetup.form.url", | ||||||
|                                 Domain.LMS_SETUP.ATTR_LMS_URL, |                         lmsSetup.getLmsApiUrl())) | ||||||
|                                 "sebserver.lmssetup.form.url", |                 .addField(FormBuilder.text( | ||||||
|                                 lmsSetup.getLmsApiUrl())) |                         Domain.LMS_SETUP.ATTR_LMS_CLIENTNAME, | ||||||
|                 .addFieldIf( |                         "sebserver.lmssetup.form.clientname.lms", | ||||||
|                         () -> isNotNew.getAsBoolean(), |                         lmsSetup.getLmsAuthName())) | ||||||
|                         () -> FormBuilder.text( |                 .addField(FormBuilder.text( | ||||||
|                                 Domain.LMS_SETUP.ATTR_LMS_CLIENTNAME, |                         Domain.LMS_SETUP.ATTR_LMS_CLIENTSECRET, | ||||||
|                                 "sebserver.lmssetup.form.clientname.lms", |                         "sebserver.lmssetup.form.secret.lms") | ||||||
|                                 lmsSetup.getLmsAuthName())) |                         .asPasswordField()) | ||||||
|                 .addFieldIf( |  | ||||||
|                         () -> isNotNew.getAsBoolean(), |  | ||||||
|                         () -> FormBuilder.text( |  | ||||||
|                                 Domain.LMS_SETUP.ATTR_LMS_CLIENTSECRET, |  | ||||||
|                                 "sebserver.lmssetup.form.secret.lms") |  | ||||||
|                                 .asPasswordField()) |  | ||||||
| 
 | 
 | ||||||
|                 .buildFor((entityKey == null) |                 .buildFor((entityKey == null) | ||||||
|                         ? restService.getRestCall(NewLmsSetup.class) |                         ? restService.getRestCall(NewLmsSetup.class) | ||||||
|  | @ -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, | ||||||
|  |                 a -> { | ||||||
|  |                     action.pageContext().publishInfo( | ||||||
|  |                             new LocTextKey("sebserver.lmssetup.action.test.ok")); | ||||||
|  | 
 | ||||||
|  |                     return action; | ||||||
|  |                 }, | ||||||
|  |                 result.getOrThrow()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private PageAction handleTestResult( | ||||||
|  |             final PageAction action, | ||||||
|  |             final Function<PageAction, PageAction> onOK, | ||||||
|  |             final LmsSetupTestResult testResult) { | ||||||
| 
 | 
 | ||||||
|         if (testResult.isOk()) { |         if (testResult.isOk()) { | ||||||
|             action.pageContext().publishInfo( |             return onOK.apply(action); | ||||||
|                     new LocTextKey("sebserver.lmssetup.action.test.ok")); |  | ||||||
| 
 |  | ||||||
|             return 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", | ||||||
|  |  | ||||||
|  | @ -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; | ||||||
|  |  | ||||||
|  | @ -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", | ||||||
|  |  | ||||||
|  | @ -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, | ||||||
|  |  | ||||||
|  | @ -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; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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); | ||||||
|  |  | ||||||
|  | @ -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); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -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) | ||||||
|  |  | ||||||
|  | @ -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, | ||||||
|  |  | ||||||
|  | @ -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)); | ||||||
|  |  | ||||||
|  | @ -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(), | ||||||
|  |  | ||||||
|  | @ -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 | ||||||
|  |  | ||||||
|  | @ -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; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -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); | ||||||
|  |  | ||||||
|  | @ -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} | ||||||
|  |  | ||||||
|  | @ -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} | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 anhefti
						anhefti