SEBSERV-417 adapt Moodle API calls, error handling and fixes
This commit is contained in:
		
							parent
							
								
									012b0e2f99
								
							
						
					
					
						commit
						f9de99d9bc
					
				
					 17 changed files with 110 additions and 34 deletions
				
			
		|  | @ -0,0 +1,26 @@ | |||
| /* | ||||
|  *  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.model.user; | ||||
| 
 | ||||
| import ch.ethz.seb.sebserver.gbl.model.EntityKey; | ||||
| import com.fasterxml.jackson.annotation.JsonProperty; | ||||
| 
 | ||||
| public final class LoginForward { | ||||
|     @JsonProperty("entityKey") | ||||
|     public final EntityKey entityKey; | ||||
|     @JsonProperty("actionName") | ||||
|     public final String actionName; | ||||
| 
 | ||||
|     public LoginForward( | ||||
|             @JsonProperty("entityKey") final EntityKey entityKey, | ||||
|             @JsonProperty("actionName") final String actionName) { | ||||
|         this.entityKey = entityKey; | ||||
|         this.actionName = actionName; | ||||
|     } | ||||
| } | ||||
|  | @ -8,7 +8,6 @@ | |||
| 
 | ||||
| package ch.ethz.seb.sebserver.gbl.model.user; | ||||
| 
 | ||||
| import ch.ethz.seb.sebserver.gbl.model.EntityKey; | ||||
| import com.fasterxml.jackson.annotation.JsonCreator; | ||||
| import com.fasterxml.jackson.annotation.JsonProperty; | ||||
| import org.springframework.security.oauth2.common.OAuth2AccessToken; | ||||
|  | @ -19,7 +18,7 @@ public class TokenLoginInfo { | |||
|     @JsonProperty("userUUID") | ||||
|     public final String userUUID; | ||||
|     @JsonProperty("redirect") | ||||
|     public final EntityKey redirect; | ||||
|     public final LoginForward login_forward; | ||||
|     @JsonProperty("login") | ||||
|     public final OAuth2AccessToken login; | ||||
| 
 | ||||
|  | @ -27,12 +26,13 @@ public class TokenLoginInfo { | |||
|     public TokenLoginInfo( | ||||
|             @JsonProperty("username") final String username, | ||||
|             @JsonProperty("userUUID") final String userUUID, | ||||
|             @JsonProperty("redirect") final EntityKey redirect, | ||||
|             @JsonProperty("redirect") final LoginForward login_forward, | ||||
|             @JsonProperty("login") final OAuth2AccessToken login) { | ||||
| 
 | ||||
|         this.username = username; | ||||
|         this.userUUID = userUUID; | ||||
|         this.redirect = redirect; | ||||
|         this.login_forward = login_forward; | ||||
|         this.login = login; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -21,6 +21,8 @@ import javax.servlet.ServletException; | |||
| import javax.servlet.http.HttpServletRequest; | ||||
| import javax.servlet.http.HttpServletResponse; | ||||
| 
 | ||||
| import ch.ethz.seb.sebserver.gbl.model.EntityKey; | ||||
| import ch.ethz.seb.sebserver.gbl.util.Result; | ||||
| import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder; | ||||
| import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.SEBServerAuthorizationContext; | ||||
| import org.apache.commons.codec.binary.Base64InputStream; | ||||
|  |  | |||
|  | @ -8,8 +8,16 @@ | |||
| 
 | ||||
| package ch.ethz.seb.sebserver.gui.content; | ||||
| 
 | ||||
| import javax.servlet.http.HttpServletRequest; | ||||
| import java.util.function.Consumer; | ||||
| 
 | ||||
| import ch.ethz.seb.sebserver.gbl.model.EntityKey; | ||||
| import ch.ethz.seb.sebserver.gbl.model.user.LoginForward; | ||||
| import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; | ||||
| import ch.ethz.seb.sebserver.gbl.util.Result; | ||||
| import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; | ||||
| import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction; | ||||
| import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder; | ||||
| import org.eclipse.rap.rwt.RWT; | ||||
| import org.eclipse.swt.SWT; | ||||
| import org.eclipse.swt.custom.SashForm; | ||||
|  | @ -54,13 +62,19 @@ public class MainPage implements TemplateComposer { | |||
| 
 | ||||
|     private final WidgetFactory widgetFactory; | ||||
|     private final PolyglotPageService polyglotPageService; | ||||
|     private final AuthorizationContextHolder authorizationContextHolder; | ||||
|     private final PageService pageService; | ||||
| 
 | ||||
|     public MainPage( | ||||
|             final WidgetFactory widgetFactory, | ||||
|             final PolyglotPageService polyglotPageService) { | ||||
|             final PolyglotPageService polyglotPageService, | ||||
|             final AuthorizationContextHolder authorizationContextHolder, | ||||
|             final PageService pageService) { | ||||
| 
 | ||||
|         this.widgetFactory = widgetFactory; | ||||
|         this.polyglotPageService = polyglotPageService; | ||||
|         this.authorizationContextHolder = authorizationContextHolder; | ||||
|         this.pageService = pageService; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|  | @ -158,6 +172,19 @@ public class MainPage implements TemplateComposer { | |||
|                 pageContext.copyOf(nav)); | ||||
| 
 | ||||
|         mainSash.setWeights(DEFAULT_SASH_WEIGHTS); | ||||
| 
 | ||||
|         final LoginForward loginForward = authorizationContextHolder | ||||
|                 .getAuthorizationContext() | ||||
|                 .getLoginForward(); | ||||
| 
 | ||||
|         if (loginForward != null) { | ||||
|             final PageAction pageAction = pageService.pageActionBuilder(pageContext) | ||||
|                     .newAction( ActionDefinition.valueOf(loginForward.actionName)) | ||||
|                     .withEntityKey(loginForward.entityKey) | ||||
|                     .create(); | ||||
| 
 | ||||
|             pageService.executePageAction(pageAction); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private static final class ContentActionEventListener implements ActionEventListener { | ||||
|  |  | |||
|  | @ -8,6 +8,7 @@ | |||
| 
 | ||||
| package ch.ethz.seb.sebserver.gui.content.action; | ||||
| 
 | ||||
| import ch.ethz.seb.sebserver.gbl.api.EntityType; | ||||
| import ch.ethz.seb.sebserver.gui.content.activity.PageStateDefinitionImpl; | ||||
| import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; | ||||
| import ch.ethz.seb.sebserver.gui.service.page.PageStateDefinition; | ||||
|  |  | |||
|  | @ -456,8 +456,9 @@ public class LmsSetupForm implements TemplateComposer { | |||
|             } else if (formHandle != null && formHandle.handleError(result.getError())) { | ||||
|                 action.pageContext().notifyActivationError(EntityType.LMS_SETUP, error); | ||||
|             } else { | ||||
|                 result.getOrThrow(); | ||||
|                 action.pageContext().notifyUnexpectedError(result.getError()); | ||||
|             } | ||||
|             return action; | ||||
|         } | ||||
| 
 | ||||
|         return handleTestResult( | ||||
|  |  | |||
|  | @ -15,6 +15,8 @@ import java.nio.charset.StandardCharsets; | |||
| import javax.servlet.http.HttpSession; | ||||
| 
 | ||||
| import ch.ethz.seb.sebserver.gbl.api.API; | ||||
| import ch.ethz.seb.sebserver.gbl.model.EntityKey; | ||||
| import ch.ethz.seb.sebserver.gbl.model.user.LoginForward; | ||||
| import ch.ethz.seb.sebserver.gbl.model.user.TokenLoginInfo; | ||||
| import org.apache.commons.lang3.BooleanUtils; | ||||
| import org.apache.commons.lang3.StringUtils; | ||||
|  | @ -152,6 +154,7 @@ public class OAuth2AuthorizationContextHolder implements AuthorizationContextHol | |||
|         private final String jwtTokenVerificationURI; | ||||
| 
 | ||||
|         private Result<UserInfo> loggedInUser = null; | ||||
|         private LoginForward loginForward = null; | ||||
| 
 | ||||
|         OAuth2AuthorizationContext( | ||||
|                 final String guiClientId, | ||||
|  | @ -215,6 +218,11 @@ public class OAuth2AuthorizationContextHolder implements AuthorizationContextHol | |||
|             return null; | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public LoginForward getLoginForward() { | ||||
|             return loginForward; | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public boolean login(final String username, final CharSequence password) { | ||||
|             if (!this.valid || this.isLoggedIn()) { | ||||
|  | @ -282,6 +290,7 @@ public class OAuth2AuthorizationContextHolder implements AuthorizationContextHol | |||
|                 final TokenLoginInfo loginInfo = response.getBody(); | ||||
|                 this.restTemplate.getOAuth2ClientContext().setAccessToken(loginInfo.login); | ||||
| 
 | ||||
|                 loginForward = loginInfo.login_forward; | ||||
|                 return this.isLoggedIn(); | ||||
|             } catch (final Exception e) { | ||||
|                 log.warn("Autologin failed due to unexpected error: {}", e.getMessage()); | ||||
|  |  | |||
|  | @ -8,6 +8,8 @@ | |||
| 
 | ||||
| package ch.ethz.seb.sebserver.gui.service.remote.webservice.auth; | ||||
| 
 | ||||
| import ch.ethz.seb.sebserver.gbl.model.EntityKey; | ||||
| import ch.ethz.seb.sebserver.gbl.model.user.LoginForward; | ||||
| import org.springframework.web.client.RestTemplate; | ||||
| 
 | ||||
| import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; | ||||
|  | @ -67,4 +69,5 @@ public interface SEBServerAuthorizationContext { | |||
| 
 | ||||
|     CharSequence getUserPassword(); | ||||
| 
 | ||||
|     LoginForward getLoginForward(); | ||||
| } | ||||
|  |  | |||
|  | @ -15,10 +15,7 @@ import ch.ethz.seb.sebserver.gbl.api.APIMessage; | |||
| import ch.ethz.seb.sebserver.gbl.api.EntityType; | ||||
| import ch.ethz.seb.sebserver.gbl.model.EntityKey; | ||||
| import ch.ethz.seb.sebserver.gbl.model.exam.Exam; | ||||
| import ch.ethz.seb.sebserver.gbl.model.user.TokenLoginInfo; | ||||
| import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; | ||||
| import ch.ethz.seb.sebserver.gbl.model.user.UserMod; | ||||
| import ch.ethz.seb.sebserver.gbl.model.user.UserRole; | ||||
| import ch.ethz.seb.sebserver.gbl.model.user.*; | ||||
| import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; | ||||
| import ch.ethz.seb.sebserver.gbl.util.Cryptor; | ||||
| import ch.ethz.seb.sebserver.gbl.util.Result; | ||||
|  | @ -187,11 +184,14 @@ public class TeacherAccountServiceImpl implements TeacherAccountService { | |||
|             final OAuth2AccessToken token = accessToken.getBody(); | ||||
| 
 | ||||
|             final String examId = claims.get(EXAM_ID_CLAIM, String.class); | ||||
|             final EntityKey redirectTo = (StringUtils.isNotBlank(examId)) | ||||
|             final EntityKey key = (StringUtils.isNotBlank(examId)) | ||||
|                     ? new EntityKey(examId, EntityType.EXAM) | ||||
|                     : null; | ||||
|             final LoginForward loginForward = new LoginForward( | ||||
|                     key, | ||||
|                     "MONITOR_EXAM_FROM_LIST"); | ||||
| 
 | ||||
|             return new TokenLoginInfo(user.username, user.uuid, redirectTo, token); | ||||
|             return new TokenLoginInfo(user.username, user.uuid, loginForward, token); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -144,8 +144,6 @@ public interface FullLmsIntegrationService { | |||
|         public final String name; | ||||
|         @JsonProperty("url") | ||||
|         public final String url; | ||||
|         @JsonProperty("autologin_url") | ||||
|         public final String autoLoginURL; | ||||
|         @JsonProperty("access_token") | ||||
|         public final String access_token; | ||||
|         @JsonProperty("exam_templates") | ||||
|  | @ -156,14 +154,12 @@ public interface FullLmsIntegrationService { | |||
|                 @JsonProperty("id") final String id, | ||||
|                 @JsonProperty("name") final String name, | ||||
|                 @JsonProperty("url") final String url, | ||||
|                 @JsonProperty("autologin_url") final String autoLoginURL, | ||||
|                 @JsonProperty("access_token") final String access_token, | ||||
|                 @JsonProperty("exam_templates") final Collection<ExamTemplateSelection> exam_templates) { | ||||
| 
 | ||||
|             this.id = id; | ||||
|             this.name = name; | ||||
|             this.url = url; | ||||
|             this.autoLoginURL = autoLoginURL; | ||||
|             this.access_token = access_token; | ||||
|             this.exam_templates = Utils.immutableCollectionOf(exam_templates); | ||||
|         } | ||||
|  |  | |||
|  | @ -8,6 +8,7 @@ | |||
| 
 | ||||
| package ch.ethz.seb.sebserver.webservice.servicelayer.lms; | ||||
| 
 | ||||
| import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup; | ||||
| import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; | ||||
| import ch.ethz.seb.sebserver.gbl.util.Result; | ||||
| import org.springframework.context.annotation.Lazy; | ||||
|  | @ -30,7 +31,7 @@ public interface LmsAPITemplateCacheService { | |||
|      * @return LmsAPITemplate for specified LmsSetup configuration */ | ||||
|     Result<LmsAPITemplate> getLmsAPITemplate(String lmsSetupId); | ||||
| 
 | ||||
|     Result<LmsAPITemplate> getLmsAPITemplateForTesting(String lmsSetupId); | ||||
|     Result<LmsAPITemplate> createInMemoryLmsAPITemplate(LmsSetup lmsSetup); | ||||
| 
 | ||||
|     void clearCache(String lmsSetupId); | ||||
| 
 | ||||
|  |  | |||
|  | @ -49,7 +49,6 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplateCacheServ | |||
| import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleUtils; | ||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ConnectionConfigurationChangeEvent; | ||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ConnectionConfigurationService; | ||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamSessionService; | ||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.session.ScreenProctoringService; | ||||
| import org.apache.commons.io.IOUtils; | ||||
| import org.apache.commons.lang3.StringUtils; | ||||
|  | @ -241,7 +240,6 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService | |||
|                             connectionId, | ||||
|                             lmsSetup.name, | ||||
|                             getAPIRootURL(), | ||||
|                             getAutoLoginURL(), | ||||
|                             accessToken, | ||||
|                             this.getIntegrationTemplates(lmsSetup.institutionId) | ||||
|                     ); | ||||
|  | @ -317,8 +315,6 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService | |||
|                 .flatMap(this::findExam) | ||||
|                 .map(this::checkDeletion) | ||||
|                 .map(this::logExamDeleted) | ||||
|                 .flatMap(teacherAccountServiceImpl::deactivateTeacherAccountsForExam) | ||||
|                 .map(exam -> applyExamData(exam, true)) | ||||
|                 .flatMap(deleteExamAction::deleteExamInternal); | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -251,6 +251,16 @@ public class LmsAPITemplateAdapter implements LmsAPITemplate { | |||
|                 }).getOrThrow(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public String getCourseIdFromExam(final Exam exam) { | ||||
|         return this.courseAccessAPI.getCourseIdFromExam(exam); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public String getQuizIdFromExam(final Exam exam) { | ||||
|         return this.courseAccessAPI.getQuizIdFromExam(exam); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public LmsSetupTestResult testCourseAccessAPI() { | ||||
|         if (this.courseAccessAPI != null) { | ||||
|  |  | |||
|  | @ -8,6 +8,8 @@ | |||
| 
 | ||||
| package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl; | ||||
| 
 | ||||
| import static ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ExamRecordDynamicSqlSupport.lmsSetupId; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collection; | ||||
| import java.util.EnumMap; | ||||
|  | @ -94,12 +96,13 @@ public class LmsAPITemplateCacheServiceImpl implements LmsAPITemplateCacheServic | |||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public Result<LmsAPITemplate> getLmsAPITemplateForTesting(final String lmsSetupId) { | ||||
|         return lmsSetupDAO.byModelId(lmsSetupId) | ||||
|                 .map(lmsSetup -> new AdHocAPITemplateDataSupplier( | ||||
|                         lmsSetup, | ||||
|                         this.clientCredentialService)) | ||||
|                 .flatMap(this::createLmsSetupTemplate); | ||||
|     public Result<LmsAPITemplate> createInMemoryLmsAPITemplate(final LmsSetup lmsSetup) { | ||||
|         return Result.tryCatch(() -> { | ||||
|             final AdHocAPITemplateDataSupplier adHocAPITemplateDataSupplier = new AdHocAPITemplateDataSupplier( | ||||
|                     lmsSetup, | ||||
|                     this.clientCredentialService); | ||||
|             return this.createLmsSetupTemplate(adHocAPITemplateDataSupplier).getOrThrow(); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|  |  | |||
|  | @ -87,7 +87,7 @@ public class LmsTestServiceImpl implements LmsTestService { | |||
|     public LmsSetupTestResult testAdHoc(final LmsSetup lmsSetup) { | ||||
| 
 | ||||
|         final Result<LmsAPITemplate> createLmsSetupTemplate = lmsAPITemplateCacheService | ||||
|                 .getLmsAPITemplateForTesting(lmsSetup.getModelId()); | ||||
|                 .createInMemoryLmsAPITemplate(lmsSetup); | ||||
|         if (createLmsSetupTemplate.hasError()) { | ||||
|             return new LmsSetupTestResult( | ||||
|                     lmsSetup.lmsType, | ||||
|  |  | |||
|  | @ -379,9 +379,9 @@ public class MoodleRestTemplateFactoryImpl implements MoodleRestTemplateFactory | |||
|                 queryParam.queryParams(queryParams); | ||||
|             } | ||||
| 
 | ||||
|             final boolean usePOST = queryAttributes != null && !queryAttributes.isEmpty(); | ||||
|             //final boolean usePOST = queryAttributes != null && !queryAttributes.isEmpty(); | ||||
|             final HttpEntity<?> functionReqEntity; | ||||
|             if (usePOST) { | ||||
|             if ( queryAttributes != null && !queryAttributes.isEmpty()) { | ||||
|                 final HttpHeaders headers = new HttpHeaders(); | ||||
|                 headers.set( | ||||
|                         HttpHeaders.CONTENT_TYPE, | ||||
|  | @ -394,7 +394,7 @@ public class MoodleRestTemplateFactoryImpl implements MoodleRestTemplateFactory | |||
|                 functionReqEntity = new HttpEntity<>(new LinkedMultiValueMap<>()); | ||||
|             } | ||||
| 
 | ||||
|             return doRequest(functionName, queryParam, usePOST, functionReqEntity); | ||||
|             return doRequest(functionName, queryParam, true, functionReqEntity); | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|  | @ -465,7 +465,7 @@ public class MoodleRestTemplateFactoryImpl implements MoodleRestTemplateFactory | |||
| 
 | ||||
|                 final ResponseEntity<String> response = super.exchange( | ||||
|                         this.serverURL + this.tokenPath, | ||||
|                         HttpMethod.GET, | ||||
|                         HttpMethod.POST, | ||||
|                         this.tokenReqEntity, | ||||
|                         String.class, | ||||
|                         this.tokenReqURIVars); | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ | |||
| package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.plugin; | ||||
| 
 | ||||
| import java.util.HashMap; | ||||
| import java.util.LinkedHashMap; | ||||
| import java.util.Map; | ||||
| 
 | ||||
| import ch.ethz.seb.sebserver.gbl.api.APIMessage; | ||||
|  | @ -156,7 +157,7 @@ public class MoodlePluginFullIntegration implements FullLmsIntegrationAPI { | |||
|             final MoodleAPIRestTemplate rest = getRestTemplate().getOrThrow(); | ||||
| 
 | ||||
|             final Map<String, Map<String, String>> attributes = new HashMap<>(); | ||||
|             final Map<String, String> data_mapping = new HashMap<>(); | ||||
|             final Map<String, String> data_mapping = new LinkedHashMap<>(); | ||||
|             attributes.put(ATTRIBUTE_EXAM_DATA, data_mapping); | ||||
| 
 | ||||
|             // data[quizid]= int | ||||
|  | @ -168,7 +169,7 @@ public class MoodlePluginFullIntegration implements FullLmsIntegrationAPI { | |||
|             if (BooleanUtils.isTrue(examData.exam_created)) { | ||||
|                 data_mapping.put("addordelete", "1"); | ||||
|                 data_mapping.put("templateid", examData.template_id); | ||||
|                 data_mapping.put("showquitlink", BooleanUtils.isTrue(examData.show_quit_link) ? "1" : "2"); | ||||
|                 data_mapping.put("showquitlink", BooleanUtils.isTrue(examData.show_quit_link) ? "1" : "0"); | ||||
|                 data_mapping.put("quitsecret", examData.quit_password); | ||||
|             } else { | ||||
|                 data_mapping.put("addordelete", "0"); | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 anhefti
						anhefti