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…
Reference in a new issue