SEBSERV-417 finished first part
This commit is contained in:
parent
4b675bc717
commit
3501c5de05
14 changed files with 204 additions and 40 deletions
|
@ -175,7 +175,7 @@ public final class API {
|
|||
public static final String LMS_FULL_INTEGRATION_EXAM_TEMPLATE_ID = "exam_template_id";
|
||||
public static final String LMS_FULL_INTEGRATION_QUIT_PASSWORD = "quit_password";
|
||||
public static final String LMS_FULL_INTEGRATION_QUIT_LINK = "quit_link";
|
||||
|
||||
public static final String LMS_FULL_INTEGRATION_TIME_ZONE = "account_time_zone";
|
||||
|
||||
public static final String USER_ACCOUNT_ENDPOINT = "/useraccount";
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ import javax.validation.constraints.NotEmpty;
|
|||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
|
@ -95,6 +96,12 @@ public final class UserMod implements UserAccount {
|
|||
@JsonProperty(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD)
|
||||
private final CharSequence confirmNewPassword;
|
||||
|
||||
@JsonProperty(USER.ATTR_LOCAL_ACCOUNT)
|
||||
private final Boolean isLocalAccount;
|
||||
|
||||
@JsonProperty(USER.ATTR_DIRECT_LOGIN)
|
||||
private final Boolean hasDirectLogin;
|
||||
|
||||
@JsonCreator
|
||||
public UserMod(
|
||||
@JsonProperty(USER.ATTR_UUID) final String uuid,
|
||||
|
@ -107,6 +114,8 @@ public final class UserMod implements UserAccount {
|
|||
@JsonProperty(USER.ATTR_EMAIL) final String email,
|
||||
@JsonProperty(USER.ATTR_LANGUAGE) final Locale language,
|
||||
@JsonProperty(USER.ATTR_TIMEZONE) final DateTimeZone timeZone,
|
||||
@JsonProperty(USER.ATTR_LOCAL_ACCOUNT) final Boolean isLocalAccount,
|
||||
@JsonProperty(USER.ATTR_DIRECT_LOGIN) final Boolean hasDirectLogin,
|
||||
@JsonProperty(USER_ROLE.REFERENCE_NAME) final Set<String> roles) {
|
||||
|
||||
this.uuid = uuid;
|
||||
|
@ -119,6 +128,8 @@ public final class UserMod implements UserAccount {
|
|||
this.email = email;
|
||||
this.language = (language != null) ? language : Locale.ENGLISH;
|
||||
this.timeZone = (timeZone != null) ? timeZone : DateTimeZone.UTC;
|
||||
this.isLocalAccount = BooleanUtils.isNotFalse(isLocalAccount);
|
||||
this.hasDirectLogin = BooleanUtils.isNotFalse(hasDirectLogin);
|
||||
this.roles = (roles != null)
|
||||
? Collections.unmodifiableSet(roles)
|
||||
: Collections.emptySet();
|
||||
|
@ -136,6 +147,8 @@ public final class UserMod implements UserAccount {
|
|||
this.language = postAttrMapper.getLocale(USER.ATTR_LANGUAGE);
|
||||
this.timeZone = postAttrMapper.getDateTimeZone(USER.ATTR_TIMEZONE);
|
||||
this.roles = postAttrMapper.getStringSet(USER_ROLE.REFERENCE_NAME);
|
||||
this.isLocalAccount = BooleanUtils.isNotFalse(postAttrMapper.getBoolean(USER.ATTR_LOCAL_ACCOUNT));
|
||||
this.hasDirectLogin = BooleanUtils.isNotFalse(postAttrMapper.getBoolean(USER.ATTR_DIRECT_LOGIN));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -237,6 +250,15 @@ public final class UserMod implements UserAccount {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
public Boolean isLocalAccount() {
|
||||
return isLocalAccount;
|
||||
}
|
||||
|
||||
public Boolean hasDirectLogin() {
|
||||
return hasDirectLogin;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public EntityKey getEntityKey() {
|
||||
|
@ -279,7 +301,7 @@ public final class UserMod implements UserAccount {
|
|||
return new UserMod(
|
||||
UUID.randomUUID().toString(),
|
||||
institutionId,
|
||||
null, null, null, null, null, null, null, null, null);
|
||||
null, null, null, null, null, null, null, null, true, true, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -145,6 +145,8 @@ class AdminUserInitializer {
|
|||
null,
|
||||
null,
|
||||
null,
|
||||
true,
|
||||
true,
|
||||
new HashSet<>(this.webserviceInfo.isLightSetup() ?
|
||||
UserRole.getLightSetupRoles() :
|
||||
List.of(UserRole.SEB_SERVER_ADMIN.name())
|
||||
|
|
|
@ -50,6 +50,7 @@ public class WebserviceInfo {
|
|||
"sebserver.webservice.api.exam.endpoint.discovery";
|
||||
private static final String WEB_SERVICE_EXTERNAL_ADDRESS_ALIAS = "sebserver.webservice.lms.address.alias";
|
||||
private static final String WEB_SERVICE_CONTEXT_PATH = "server.servlet.context-path";
|
||||
public static final String SEBSERVER_WEBSERVICE_AUTOLOGIN_ENDPOINT = "sebserver.webservice.autologin.endpoint";
|
||||
|
||||
private final String sebServerVersion;
|
||||
private final String testProperty;
|
||||
|
@ -61,6 +62,8 @@ public class WebserviceInfo {
|
|||
private final String discoveryEndpoint;
|
||||
private final String contextPath;
|
||||
|
||||
private final String autoLoginEndpoint;
|
||||
|
||||
private final boolean isLightSetup;
|
||||
private final String serverURLPrefix;
|
||||
private final boolean isDistributed;
|
||||
|
@ -104,6 +107,9 @@ public class WebserviceInfo {
|
|||
this.webserviceUUID = UUID.randomUUID().toString()
|
||||
+ Constants.UNDERLINE
|
||||
+ this.sebServerVersion;
|
||||
this.autoLoginEndpoint = environment.getProperty(
|
||||
SEBSERVER_WEBSERVICE_AUTOLOGIN_ENDPOINT,
|
||||
"/auto_login");
|
||||
|
||||
this.distributedUpdateInterval = environment.getProperty(
|
||||
"sebserver.webservice.distributed.updateInterval",
|
||||
|
@ -237,6 +243,10 @@ public class WebserviceInfo {
|
|||
return this.discoveryEndpoint;
|
||||
}
|
||||
|
||||
public String getAutoLoginEndpoint() {
|
||||
return autoLoginEndpoint;
|
||||
}
|
||||
|
||||
public String getDiscoveryEndpointAddress() {
|
||||
return this.serverURLPrefix + this.discoveryEndpoint;
|
||||
}
|
||||
|
|
|
@ -113,16 +113,6 @@ public interface EntityDAO<T extends Entity, M extends ModelIdAware> {
|
|||
* happened */
|
||||
Result<Collection<EntityKey>> delete(Set<EntityKey> all);
|
||||
|
||||
@Transactional
|
||||
default Result<EntityKey> deleteOne(final Long examId) {
|
||||
if (examId == null) {
|
||||
return Result.ofRuntimeError("exam Id has null reference");
|
||||
}
|
||||
return delete( new HashSet<>(Arrays.asList(new EntityKey(examId, EntityType.EXAM))))
|
||||
.map(set -> set.iterator().next())
|
||||
.onError(TransactionHandler::rollback);
|
||||
}
|
||||
|
||||
/** Get a (unordered) collection of all Entities that matches the given filter criteria.
|
||||
* The possible filter criteria for a specific Entity type is defined by the entity type.
|
||||
* <p>
|
||||
|
|
|
@ -252,8 +252,8 @@ public class UserDAOImpl implements UserDAO {
|
|||
userMod.language.toLanguageTag(),
|
||||
userMod.timeZone.getID(),
|
||||
BooleanUtils.toInteger(false),
|
||||
BooleanUtils.toInteger(true),
|
||||
BooleanUtils.toInteger(true));
|
||||
BooleanUtils.toInteger(userMod.hasDirectLogin()),
|
||||
BooleanUtils.toInteger(userMod.isLocalAccount()));
|
||||
|
||||
this.userRecordMapper.insert(recordToSave);
|
||||
final Long newUserPK = recordToSave.getId();
|
||||
|
|
|
@ -42,7 +42,8 @@ public interface FullLmsIntegrationService {
|
|||
String quizId,
|
||||
String examTemplateId,
|
||||
String quitPassword,
|
||||
String quitLink);
|
||||
String quitLink,
|
||||
String timezone);
|
||||
|
||||
Result<EntityKey> deleteExam(
|
||||
String lmsUUID,
|
||||
|
@ -66,6 +67,9 @@ 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")
|
||||
|
@ -76,12 +80,14 @@ 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);
|
||||
}
|
||||
|
|
|
@ -12,12 +12,15 @@ import java.io.OutputStream;
|
|||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import ch.ethz.seb.sebserver.ClientHttpRequestFactoryService;
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
|
@ -26,8 +29,12 @@ import ch.ethz.seb.sebserver.gbl.model.exam.ExamTemplate;
|
|||
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.sebconfig.SEBClientConfig;
|
||||
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.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
import ch.ethz.seb.sebserver.webservice.WebserviceInfo;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.UserService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.impl.SEBServerUser;
|
||||
|
@ -44,6 +51,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ClientConfigServi
|
|||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamSessionService;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
@ -62,6 +70,7 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
|||
|
||||
private final LmsSetupDAO lmsSetupDAO;
|
||||
private final UserActivityLogDAO userActivityLogDAO;
|
||||
private final UserDAO userDAO;
|
||||
private final SEBClientConfigDAO sebClientConfigDAO;
|
||||
private final ClientConfigService clientConfigService;
|
||||
private final DeleteExamAction deleteExamAction;
|
||||
|
@ -79,6 +88,7 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
|||
public FullLmsIntegrationServiceImpl(
|
||||
final LmsSetupDAO lmsSetupDAO,
|
||||
final UserActivityLogDAO userActivityLogDAO,
|
||||
final UserDAO userDAO,
|
||||
final SEBClientConfigDAO sebClientConfigDAO,
|
||||
final ClientConfigService clientConfigService,
|
||||
final DeleteExamAction deleteExamAction,
|
||||
|
@ -96,6 +106,7 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
|||
|
||||
this.lmsSetupDAO = lmsSetupDAO;
|
||||
this.userActivityLogDAO = userActivityLogDAO;
|
||||
this.userDAO = userDAO;
|
||||
this.sebClientConfigDAO = sebClientConfigDAO;
|
||||
this.clientConfigService = clientConfigService;
|
||||
this.deleteExamAction = deleteExamAction;
|
||||
|
@ -126,6 +137,11 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
|||
.add(0, new StringHttpMessageConverter(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyExamDeletion(final ExamDeletionEvent event) {
|
||||
event.ids.forEach(this::deleteAdHocAccount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyLmsSetupChange(final LmsSetupChangeEvent event) {
|
||||
final LmsSetup lmsSetup = event.getLmsSetup();
|
||||
|
@ -187,6 +203,7 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
|||
connectionId,
|
||||
lmsSetup.name,
|
||||
getAPIRootURL(),
|
||||
getAutoLoginURL(),
|
||||
accessToken,
|
||||
this.getIntegrationTemplates(lmsSetup.institutionId)
|
||||
);
|
||||
|
@ -238,13 +255,14 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
|||
final String quizId,
|
||||
final String examTemplateId,
|
||||
final String quitPassword,
|
||||
final String quitLink) {
|
||||
final String quitLink,
|
||||
final String timezone) {
|
||||
|
||||
return lmsSetupDAO
|
||||
.getLmsSetupIdByConnectionId(lmsUUID)
|
||||
.flatMap(lmsAPIService::getLmsAPITemplate)
|
||||
.map(findQuizData(courseId, quizId))
|
||||
.map(createAccountAndExam(examTemplateId, quitPassword));
|
||||
.map(createAccountAndExam(examTemplateId, quitPassword, timezone));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -260,6 +278,7 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
|||
.flatMap(this::findExam)
|
||||
.map(this::checkDeletion)
|
||||
.map(this::logExamDeleted)
|
||||
.map(this::deleteAdHocAccount)
|
||||
.flatMap(deleteExamAction::deleteExamFromLMSIntegration);
|
||||
}
|
||||
|
||||
|
@ -276,10 +295,7 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
|||
return exam;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyExamDeletion(final ExamDeletionEvent event) {
|
||||
event.ids.forEach(this::deleteAdHocAccount);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Result<Void> streamConnectionConfiguration(
|
||||
|
@ -306,12 +322,15 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
|||
if (StringUtils.isBlank(connectionConfigId)) {
|
||||
connectionConfigId = this.sebClientConfigDAO
|
||||
.all(exam.institutionId, true)
|
||||
.map(all -> all.iterator().next())
|
||||
.map(all -> all.stream().filter(config -> config.configPurpose == SEBClientConfig.ConfigPurpose.START_EXAM)
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new APIMessage.APIMessageException(
|
||||
APIMessage.ErrorMessage.ILLEGAL_API_ARGUMENT.of("No active Connection Configuration found"))))
|
||||
.map(SEBClientConfig::getModelId)
|
||||
.getOr(null);
|
||||
}
|
||||
if (StringUtils.isBlank(connectionConfigId)) {
|
||||
return Result.ofRuntimeError("No active Connection Configuration found");
|
||||
throw new APIMessage.APIMessageException(APIMessage.ErrorMessage.ILLEGAL_API_ARGUMENT.of("No active Connection Configuration found"));
|
||||
}
|
||||
|
||||
this.clientConfigService.exportSEBClientConfiguration(out, connectionConfigId, exam.id);
|
||||
|
@ -358,7 +377,8 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
|||
|
||||
private Function<QuizData, Exam> createAccountAndExam(
|
||||
final String examTemplateId,
|
||||
final String quitPassword) {
|
||||
final String quitPassword,
|
||||
final String timezone) {
|
||||
|
||||
return quizData -> {
|
||||
|
||||
|
@ -378,8 +398,13 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
|||
post.putIfAbsent(Domain.EXAM.ATTR_QUIT_PASSWORD, quitPassword);
|
||||
}
|
||||
|
||||
final String accountUUID = createAdHocSupporterAccount(quizData);
|
||||
post.putIfAbsent(Domain.EXAM.ATTR_OWNER, accountUUID);
|
||||
final String accountUUID = createAdHocSupporterAccount(quizData, timezone);
|
||||
if (accountUUID != null) {
|
||||
post.putIfAbsent(Domain.EXAM.ATTR_OWNER, accountUUID);
|
||||
// TODO do we need to apply the ad-hoc teacher account also as supporter?
|
||||
} else {
|
||||
post.putIfAbsent(Domain.EXAM.ATTR_OWNER, userService.getCurrentUser().uuid());
|
||||
}
|
||||
|
||||
final Exam exam = new Exam(null, quizData, post);
|
||||
return examDAO
|
||||
|
@ -390,16 +415,81 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
|||
};
|
||||
}
|
||||
|
||||
private String createAdHocSupporterAccount(final QuizData data) {
|
||||
// TODO create an ad hoc supporter account for this exam and apply it to the exam
|
||||
return "mockAccountUUID";
|
||||
private String createAdHocSupporterAccount(final QuizData data, final String timezone) {
|
||||
try {
|
||||
|
||||
final String uuid = UUID.randomUUID().toString();
|
||||
final String name = "teacher-" + uuid;
|
||||
DateTimeZone dtz = DateTimeZone.UTC;
|
||||
if (StringUtils.isNotBlank(timezone)) {
|
||||
try {
|
||||
dtz = DateTimeZone.forID(timezone);
|
||||
} catch (final Exception e) {
|
||||
log.warn("Failed to set requested time zone for ad-hoc teacher account: {}", timezone);
|
||||
}
|
||||
}
|
||||
|
||||
final UserMod adHocTeacherUser = new UserMod(
|
||||
uuid,
|
||||
data.institutionId,
|
||||
name,
|
||||
data.id,
|
||||
name,
|
||||
uuid,
|
||||
uuid,
|
||||
null,
|
||||
Locale.ENGLISH,
|
||||
dtz,
|
||||
true,
|
||||
false,
|
||||
Utils.immutableSetOf(UserRole.TEACHER.name()));
|
||||
|
||||
userDAO.createNew(adHocTeacherUser)
|
||||
.flatMap(account -> userDAO.setActive(account, true))
|
||||
.getOrThrow();
|
||||
|
||||
return uuid;
|
||||
} catch (final Exception e) {
|
||||
log.error("Failed to create ad-hoc teacher account for importing exam: {}", data, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Exam deleteAdHocAccount(final Exam exam) {
|
||||
deleteAdHocAccount(exam.id);
|
||||
return exam;
|
||||
}
|
||||
|
||||
private void deleteAdHocAccount(final Long examId) {
|
||||
try {
|
||||
// TODO check if exam has an ad-hoc account and if true, delete it
|
||||
|
||||
final Result<Exam> examResult = examDAO.byPK(examId);
|
||||
if (examResult.hasError()) {
|
||||
log.warn("Failed to get exam for id: {}", examId);
|
||||
return;
|
||||
}
|
||||
|
||||
final String externalId = examResult.get().externalId;
|
||||
final FilterMap filter = new FilterMap();
|
||||
filter.putIfAbsent(Domain.USER.ATTR_SURNAME, externalId);
|
||||
final Collection<UserInfo> accounts = userDAO.allMatching(filter).getOrThrow();
|
||||
|
||||
if (accounts.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (accounts.size() > 1) {
|
||||
log.error("Too many accounts found!?... ad-hoc teacher account mapping: {}", externalId);
|
||||
return;
|
||||
}
|
||||
|
||||
userDAO.delete(Utils.immutableSetOf(new EntityKey(
|
||||
accounts.iterator().next().uuid,
|
||||
EntityType.USER)))
|
||||
.getOrThrow();
|
||||
|
||||
} catch (final Exception e) {
|
||||
log.error("Failed to delete ad hoc account for exam: {}", examId, e);
|
||||
log.error("Failed to delete ad-hoc account for exam: {}", examId, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -420,6 +510,10 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
|||
return webserviceInfo.getExternalServerURL() + lmsAPIEndpoint;
|
||||
}
|
||||
|
||||
private String getAutoLoginURL() {
|
||||
return webserviceInfo.getExternalServerURL() + webserviceInfo.getAutoLoginEndpoint();
|
||||
}
|
||||
|
||||
private Exam logExamCreated(final Exam exam) {
|
||||
this.userActivityLogDAO
|
||||
.logCreate(exam)
|
||||
|
|
|
@ -637,8 +637,8 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic
|
|||
public void streamLightExamConfig(final String modelId, final HttpServletResponse response) throws IOException{
|
||||
|
||||
final ServletOutputStream outputStream = response.getOutputStream();
|
||||
PipedOutputStream pout;
|
||||
PipedInputStream pin;
|
||||
PipedOutputStream pout = null;
|
||||
PipedInputStream pin= null;
|
||||
|
||||
try {
|
||||
pout = new PipedOutputStream();
|
||||
|
|
|
@ -670,6 +670,8 @@ class ScreenProctoringAPIBinding {
|
|||
userInfo.email,
|
||||
userInfo.language,
|
||||
userInfo.timeZone,
|
||||
true,
|
||||
true,
|
||||
spsUserRoles);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,18 +8,23 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.webservice.weblayer.api;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.FullLmsIntegrationService;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
@ -53,9 +58,17 @@ public class LmsIntegrationController {
|
|||
@RequestParam(name = API.LMS_FULL_INTEGRATION_EXAM_TEMPLATE_ID, required = true) final String templateId,
|
||||
@RequestParam(name = API.LMS_FULL_INTEGRATION_QUIT_PASSWORD, required = false) final String quitPassword,
|
||||
@RequestParam(name = API.LMS_FULL_INTEGRATION_QUIT_LINK, required = false) final String quitLink,
|
||||
@RequestParam(name = API.LMS_FULL_INTEGRATION_TIME_ZONE, required = false) final String timezone,
|
||||
final HttpServletResponse response) {
|
||||
|
||||
final Exam exam = fullLmsIntegrationService.importExam(lmsUUId, courseId, quizId, templateId, quitPassword, quitLink)
|
||||
final Exam exam = fullLmsIntegrationService.importExam(
|
||||
lmsUUId,
|
||||
courseId,
|
||||
quizId,
|
||||
templateId,
|
||||
quitPassword,
|
||||
quitLink,
|
||||
timezone)
|
||||
.onError(e -> log.error(
|
||||
"Failed to create/import exam: lmsId:{}, courseId: {}, quizId: {}, templateId: {}",
|
||||
lmsUUId, courseId, quizId, templateId, e))
|
||||
|
@ -94,11 +107,33 @@ public class LmsIntegrationController {
|
|||
@RequestParam(name = API.LMS_FULL_INTEGRATION_QUIZ_ID, required = true) final String quizId,
|
||||
final HttpServletResponse response) throws IOException {
|
||||
|
||||
fullLmsIntegrationService.streamConnectionConfiguration(lmsUUId, courseId, quizId, response.getOutputStream())
|
||||
.onError(e -> log.error(
|
||||
"Failed to stream connection configuration for exam: lmsId:{}, courseId: {}, quizId: {}",
|
||||
lmsUUId, courseId, quizId, e))
|
||||
.getOrThrow();
|
||||
final ServletOutputStream outputStream = response.getOutputStream();
|
||||
final PipedOutputStream pout;
|
||||
final PipedInputStream pin;
|
||||
try {
|
||||
pout = new PipedOutputStream();
|
||||
pin = new PipedInputStream(pout);
|
||||
|
||||
}
|
||||
fullLmsIntegrationService
|
||||
.streamConnectionConfiguration(lmsUUId, courseId, quizId, pout)
|
||||
.getOrThrow();
|
||||
|
||||
IOUtils.copyLarge(pin, outputStream);
|
||||
|
||||
response.setStatus(HttpStatus.OK.value());
|
||||
outputStream.flush();
|
||||
|
||||
} catch (final APIMessage.APIMessageException me) {
|
||||
response.setStatus(HttpStatus.BAD_REQUEST.value());
|
||||
throw me;
|
||||
} catch (final Exception e) {
|
||||
log.error(
|
||||
"Failed to stream connection configuration for exam: lmsId:{}, courseId: {}, quizId: {}",
|
||||
lmsUUId, courseId, quizId, e);
|
||||
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
|
||||
} finally {
|
||||
outputStream.flush();
|
||||
outputStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ sebserver.gui.date.displayformat=de
|
|||
sebserver.gui.http.external.scheme=${sebserver.webservice.http.external.scheme}
|
||||
sebserver.gui.http.external.servername=${sebserver.webservice.http.external.servername}
|
||||
sebserver.gui.http.external.port=${sebserver.webservice.http.external.port}
|
||||
sebserver.gui.http.external.autologin.endpoint=/auto_login
|
||||
|
||||
sebserver.gui.http.webservice.scheme=http
|
||||
sebserver.gui.http.webservice.servername=localhost
|
||||
|
|
|
@ -47,6 +47,7 @@ sebserver.webservice.http.external.servername=
|
|||
sebserver.webservice.http.external.port=
|
||||
sebserver.webservice.http.redirect.gui=/gui
|
||||
sebserver.webservice.ping.service.strategy=BLOCKING
|
||||
sebserver.webservice.autologin.endpoint=/auto_login
|
||||
|
||||
|
||||
### webservice API
|
||||
|
|
|
@ -96,6 +96,7 @@ public class ModelObjectJSONGenerator {
|
|||
domainObject = new UserMod(
|
||||
"UUID", 1L, "NAME", "SURNAME", "USERNAME", "newPassword", "confirmNewPassword", "EMAIL",
|
||||
Locale.ENGLISH, DateTimeZone.UTC,
|
||||
true, true,
|
||||
new HashSet<>(Arrays.asList(UserRole.EXAM_ADMIN.name(), UserRole.EXAM_SUPPORTER.name())));
|
||||
System.out.println(domainObject.getClass().getSimpleName() + ":");
|
||||
System.out.println(writerWithDefaultPrettyPrinter.writeValueAsString(domainObject));
|
||||
|
|
Loading…
Reference in a new issue