fix quit instruction, added default indicator, connection status filter
This commit is contained in:
parent
92663c18e8
commit
b94e445257
8 changed files with 305 additions and 80 deletions
|
@ -41,6 +41,7 @@ import org.springframework.util.LinkedMultiValueMap;
|
||||||
import org.springframework.util.MultiValueMap;
|
import org.springframework.util.MultiValueMap;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||||
|
@ -85,10 +86,13 @@ public final class ClientConnectionTable {
|
||||||
private final Table table;
|
private final Table table;
|
||||||
private final ColorData colorData;
|
private final ColorData colorData;
|
||||||
private final EnumSet<ConnectionStatus> statusFilter;
|
private final EnumSet<ConnectionStatus> statusFilter;
|
||||||
|
private String statusFilterParam = "";
|
||||||
|
private boolean statusFilterChanged = false;
|
||||||
|
|
||||||
private int tableWidth;
|
private int tableWidth;
|
||||||
private boolean needsSort = false;
|
private boolean needsSort = false;
|
||||||
private LinkedHashMap<Long, UpdatableTableItem> tableMapping;
|
private LinkedHashMap<Long, UpdatableTableItem> tableMapping;
|
||||||
|
private final Set<Long> toDelete = new HashSet<>();
|
||||||
private final MultiValueMap<String, Long> sessionIds;
|
private final MultiValueMap<String, Long> sessionIds;
|
||||||
|
|
||||||
private final Color darkFontColor;
|
private final Color darkFontColor;
|
||||||
|
@ -180,39 +184,6 @@ public final class ClientConnectionTable {
|
||||||
saveStatusFilter();
|
saveStatusFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveStatusFilter() {
|
|
||||||
try {
|
|
||||||
this.resourceService
|
|
||||||
.getCurrentUser()
|
|
||||||
.putAttribute(
|
|
||||||
USER_SESSION_STATUS_FILTER_ATTRIBUTE,
|
|
||||||
StringUtils.join(this.statusFilter, Constants.LIST_SEPARATOR));
|
|
||||||
} catch (final Exception e) {
|
|
||||||
log.warn("Failed to save status filter to user session");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadStatusFilter() {
|
|
||||||
try {
|
|
||||||
final String attribute = this.resourceService
|
|
||||||
.getCurrentUser()
|
|
||||||
.getAttribute(USER_SESSION_STATUS_FILTER_ATTRIBUTE);
|
|
||||||
if (attribute != null) {
|
|
||||||
this.statusFilter.clear();
|
|
||||||
Arrays.asList(StringUtils.split(attribute, Constants.LIST_SEPARATOR))
|
|
||||||
.forEach(name -> this.statusFilter.add(ConnectionStatus.valueOf(name)));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
this.statusFilter.clear();
|
|
||||||
this.statusFilter.add(ConnectionStatus.DISABLED);
|
|
||||||
}
|
|
||||||
} catch (final Exception e) {
|
|
||||||
log.warn("Failed to load status filter to user session");
|
|
||||||
this.statusFilter.clear();
|
|
||||||
this.statusFilter.add(ConnectionStatus.DISABLED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void withDefaultAction(final PageAction pageAction, final PageService pageService) {
|
public void withDefaultAction(final PageAction pageAction, final PageService pageService) {
|
||||||
this.table.addListener(SWT.MouseDoubleClick, event -> {
|
this.table.addListener(SWT.MouseDoubleClick, event -> {
|
||||||
final Tuple<String> selection = getSingleSelection();
|
final Tuple<String> selection = getSingleSelection();
|
||||||
|
@ -300,7 +271,12 @@ public final class ClientConnectionTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateValues() {
|
public void updateValues() {
|
||||||
|
if (this.statusFilterChanged) {
|
||||||
|
this.toDelete.clear();
|
||||||
|
this.toDelete.addAll(this.tableMapping.keySet());
|
||||||
|
}
|
||||||
this.restCallBuilder
|
this.restCallBuilder
|
||||||
|
.withHeader(API.EXAM_MONITORING_STATE_FILTER, this.statusFilterParam)
|
||||||
.call()
|
.call()
|
||||||
.get(error -> {
|
.get(error -> {
|
||||||
log.error("Error poll connection data: ", error);
|
log.error("Error poll connection data: ", error);
|
||||||
|
@ -312,7 +288,21 @@ public final class ClientConnectionTable {
|
||||||
data.getConnectionId(),
|
data.getConnectionId(),
|
||||||
connectionId -> new UpdatableTableItem(connectionId));
|
connectionId -> new UpdatableTableItem(connectionId));
|
||||||
tableItem.push(data);
|
tableItem.push(data);
|
||||||
|
if (this.statusFilterChanged) {
|
||||||
|
this.toDelete.remove(data.getConnectionId());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (this.statusFilterChanged && !this.toDelete.isEmpty()) {
|
||||||
|
this.toDelete.stream().forEach(id -> {
|
||||||
|
final UpdatableTableItem item = this.tableMapping.remove(id);
|
||||||
|
final List<Long> list = this.sessionIds.get(item.connectionData.clientConnection.userSessionId);
|
||||||
|
if (list != null) {
|
||||||
|
list.remove(id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.statusFilterChanged = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateGUI() {
|
public void updateGUI() {
|
||||||
|
@ -370,6 +360,45 @@ public final class ClientConnectionTable {
|
||||||
(e1, e2) -> e1, LinkedHashMap::new));
|
(e1, e2) -> e1, LinkedHashMap::new));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void saveStatusFilter() {
|
||||||
|
try {
|
||||||
|
this.resourceService
|
||||||
|
.getCurrentUser()
|
||||||
|
.putAttribute(
|
||||||
|
USER_SESSION_STATUS_FILTER_ATTRIBUTE,
|
||||||
|
StringUtils.join(this.statusFilter, Constants.LIST_SEPARATOR));
|
||||||
|
} catch (final Exception e) {
|
||||||
|
log.warn("Failed to save status filter to user session");
|
||||||
|
} finally {
|
||||||
|
this.statusFilterParam = StringUtils.join(this.statusFilter, Constants.LIST_SEPARATOR);
|
||||||
|
this.statusFilterChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadStatusFilter() {
|
||||||
|
try {
|
||||||
|
final String attribute = this.resourceService
|
||||||
|
.getCurrentUser()
|
||||||
|
.getAttribute(USER_SESSION_STATUS_FILTER_ATTRIBUTE);
|
||||||
|
if (attribute != null) {
|
||||||
|
this.statusFilter.clear();
|
||||||
|
Arrays.asList(StringUtils.split(attribute, Constants.LIST_SEPARATOR))
|
||||||
|
.forEach(name -> this.statusFilter.add(ConnectionStatus.valueOf(name)));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
this.statusFilter.clear();
|
||||||
|
this.statusFilter.add(ConnectionStatus.DISABLED);
|
||||||
|
}
|
||||||
|
} catch (final Exception e) {
|
||||||
|
log.warn("Failed to load status filter to user session");
|
||||||
|
this.statusFilter.clear();
|
||||||
|
this.statusFilter.add(ConnectionStatus.DISABLED);
|
||||||
|
} finally {
|
||||||
|
this.statusFilterParam = StringUtils.join(this.statusFilter, Constants.LIST_SEPARATOR);
|
||||||
|
this.statusFilterChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private final class UpdatableTableItem implements Comparable<UpdatableTableItem> {
|
private final class UpdatableTableItem implements Comparable<UpdatableTableItem> {
|
||||||
|
|
||||||
final Long connectionId;
|
final Long connectionId;
|
||||||
|
@ -567,8 +596,12 @@ public final class ClientConnectionTable {
|
||||||
|
|
||||||
this.connectionData = connectionData;
|
this.connectionData = connectionData;
|
||||||
|
|
||||||
if (!this.duplicateChecked && StringUtils.isNotBlank(connectionData.clientConnection.userSessionId)) {
|
if (!this.duplicateChecked &&
|
||||||
ClientConnectionTable.this.sessionIds.add(connectionData.clientConnection.userSessionId,
|
this.connectionData.clientConnection.status != ConnectionStatus.DISABLED &&
|
||||||
|
StringUtils.isNotBlank(connectionData.clientConnection.userSessionId)) {
|
||||||
|
|
||||||
|
ClientConnectionTable.this.sessionIds.add(
|
||||||
|
connectionData.clientConnection.userSessionId,
|
||||||
this.connectionId);
|
this.connectionId);
|
||||||
this.duplicateChecked = true;
|
this.duplicateChecked = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 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.webservice.servicelayer.exam;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||||
|
|
||||||
|
public interface ExamAdminService {
|
||||||
|
|
||||||
|
/** Adds a default indicator that is defined by configuration to a given exam.
|
||||||
|
*
|
||||||
|
* @param exam The Exam to add the default indicator
|
||||||
|
* @return the Exam with added default indicator */
|
||||||
|
Result<Exam> addDefaultIndicator(final Exam exam);
|
||||||
|
|
||||||
|
/** Applies all additional SEB restriction attributes that are defined by the
|
||||||
|
* type of the LMS of a given Exam to this given Exam.
|
||||||
|
*
|
||||||
|
* @param exam the Exam to apply all additional SEB restriction attributes
|
||||||
|
* @return the Exam */
|
||||||
|
Result<Exam> applyAdditionalSEBRestrictions(final Exam exam);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,130 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 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.webservice.servicelayer.exam;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.IndicatorType;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.exam.OpenEdxSebRestriction;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup.LmsType;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.AdditionalAttributesDAO;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamDAO;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.IndicatorDAO;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPIService;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.SebRestrictionService;
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
@Service
|
||||||
|
@WebServiceProfile
|
||||||
|
public class ExamAdminServiceImpl implements ExamAdminService {
|
||||||
|
|
||||||
|
private final ExamDAO examDAO;
|
||||||
|
private final IndicatorDAO indicatorDAO;
|
||||||
|
private final AdditionalAttributesDAO additionalAttributesDAO;
|
||||||
|
private final LmsAPIService lmsAPIService;
|
||||||
|
private final JSONMapper jsonMapper;
|
||||||
|
|
||||||
|
private final String defaultIndicatorName;
|
||||||
|
private final String defaultIndicatorType;
|
||||||
|
private final String defaultIndicatorColor;
|
||||||
|
private final String defaultIndicatorThresholds;
|
||||||
|
|
||||||
|
protected ExamAdminServiceImpl(
|
||||||
|
final ExamDAO examDAO,
|
||||||
|
final IndicatorDAO indicatorDAO,
|
||||||
|
final AdditionalAttributesDAO additionalAttributesDAO,
|
||||||
|
final LmsAPIService lmsAPIService,
|
||||||
|
final JSONMapper jsonMapper,
|
||||||
|
@Value("${sebserver.webservice.api.exam.indicator.name:Ping}") final String defaultIndicatorName,
|
||||||
|
@Value("${sebserver.webservice.api.exam.indicator.type:LAST_PING}") final String defaultIndicatorType,
|
||||||
|
@Value("${sebserver.webservice.api.exam.indicator.color:b4b4b4}") final String defaultIndicatorColor,
|
||||||
|
@Value("${sebserver.webservice.api.exam.indicator.thresholds:[{\"value\":2000.0,\"color\":\"22b14c\"},{\"value\":5000.0,\"color\":\"ff7e00\"},{\"value\":10000.0,\"color\":\"ed1c24\"}]}") final String defaultIndicatorThresholds) {
|
||||||
|
|
||||||
|
this.examDAO = examDAO;
|
||||||
|
this.indicatorDAO = indicatorDAO;
|
||||||
|
this.additionalAttributesDAO = additionalAttributesDAO;
|
||||||
|
this.lmsAPIService = lmsAPIService;
|
||||||
|
this.jsonMapper = jsonMapper;
|
||||||
|
|
||||||
|
this.defaultIndicatorName = defaultIndicatorName;
|
||||||
|
this.defaultIndicatorType = defaultIndicatorType;
|
||||||
|
this.defaultIndicatorColor = defaultIndicatorColor;
|
||||||
|
this.defaultIndicatorThresholds = defaultIndicatorThresholds;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<Exam> addDefaultIndicator(final Exam exam) {
|
||||||
|
return Result.tryCatch(() -> {
|
||||||
|
|
||||||
|
final Collection<Indicator.Threshold> thresholds = this.jsonMapper.readValue(
|
||||||
|
this.defaultIndicatorThresholds,
|
||||||
|
new TypeReference<Collection<Indicator.Threshold>>() {
|
||||||
|
});
|
||||||
|
|
||||||
|
final Indicator indicator = new Indicator(
|
||||||
|
null,
|
||||||
|
exam.id,
|
||||||
|
this.defaultIndicatorName,
|
||||||
|
IndicatorType.valueOf(this.defaultIndicatorType),
|
||||||
|
this.defaultIndicatorColor,
|
||||||
|
thresholds);
|
||||||
|
|
||||||
|
this.indicatorDAO.createNew(indicator)
|
||||||
|
.getOrThrow();
|
||||||
|
|
||||||
|
return this.examDAO
|
||||||
|
.byPK(exam.id)
|
||||||
|
.getOrThrow();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<Exam> applyAdditionalSEBRestrictions(final Exam exam) {
|
||||||
|
return Result.tryCatch(() -> {
|
||||||
|
final LmsSetup lmsSetup = this.lmsAPIService.getLmsSetup(exam.lmsSetupId)
|
||||||
|
.getOrThrow();
|
||||||
|
|
||||||
|
if (lmsSetup.lmsType == LmsType.OPEN_EDX) {
|
||||||
|
final List<String> permissions = Arrays.asList(
|
||||||
|
OpenEdxSebRestriction.PermissionComponent.ALWAYS_ALLOW_STUFF.key,
|
||||||
|
OpenEdxSebRestriction.PermissionComponent.CHECK_CONFIG_KEY.key);
|
||||||
|
|
||||||
|
this.additionalAttributesDAO.saveAdditionalAttribute(
|
||||||
|
EntityType.EXAM,
|
||||||
|
exam.id,
|
||||||
|
SebRestrictionService.SEB_RESTRICTION_ADDITIONAL_PROPERTY_NAME_PREFIX +
|
||||||
|
OpenEdxSebRestriction.ATTR_PERMISSION_COMPONENTS,
|
||||||
|
StringUtils.join(permissions, Constants.LIST_SEPARATOR_CHAR))
|
||||||
|
.getOrThrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.examDAO
|
||||||
|
.byPK(exam.id)
|
||||||
|
.getOrThrow();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -28,6 +28,7 @@ import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||||
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
import org.springframework.util.MultiValueMap;
|
import org.springframework.util.MultiValueMap;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
import org.springframework.web.util.UriComponentsBuilder;
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
|
@ -180,7 +181,7 @@ final class MoodleRestTemplateFactory {
|
||||||
private CharSequence accessToken = null;
|
private CharSequence accessToken = null;
|
||||||
|
|
||||||
private final Map<String, String> tokenReqURIVars;
|
private final Map<String, String> tokenReqURIVars;
|
||||||
private final HttpEntity<?> tokenReqEntity = new HttpEntity<>(null);
|
private final HttpEntity<?> tokenReqEntity = new HttpEntity<>(new LinkedMultiValueMap<>());
|
||||||
|
|
||||||
protected MoodleAPIRestTemplate(
|
protected MoodleAPIRestTemplate(
|
||||||
|
|
||||||
|
@ -272,7 +273,7 @@ final class MoodleRestTemplateFactory {
|
||||||
functionReqEntity = new HttpEntity<>(body, headers);
|
functionReqEntity = new HttpEntity<>(body, headers);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
functionReqEntity = new HttpEntity<>(null);
|
functionReqEntity = new HttpEntity<>(new LinkedMultiValueMap<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
final ResponseEntity<String> response = super.exchange(
|
final ResponseEntity<String> response = super.exchange(
|
||||||
|
|
|
@ -15,6 +15,7 @@ import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
@ -133,20 +134,19 @@ public class SebInstructionServiceImpl implements SebInstructionService {
|
||||||
.append(Constants.COLON)
|
.append(Constants.COLON)
|
||||||
.append(Constants.DOUBLE_QUOTE)
|
.append(Constants.DOUBLE_QUOTE)
|
||||||
.append(clientInstruction.getType())
|
.append(clientInstruction.getType())
|
||||||
.append(Constants.DOUBLE_QUOTE)
|
.append(Constants.DOUBLE_QUOTE);
|
||||||
.append(Constants.COMMA)
|
|
||||||
.append(Constants.DOUBLE_QUOTE)
|
|
||||||
.append(JSON_ATTR)
|
|
||||||
.append(Constants.DOUBLE_QUOTE)
|
|
||||||
.append(Constants.COLON);
|
|
||||||
if (attributes == null || attributes.isEmpty()) {
|
|
||||||
sBuilder.append(Constants.NULL);
|
|
||||||
|
|
||||||
} else {
|
if (StringUtils.isNotBlank(attributes)) {
|
||||||
sBuilder.append(Constants.CURLY_BRACE_OPEN)
|
sBuilder.append(Constants.COMMA)
|
||||||
|
.append(Constants.DOUBLE_QUOTE)
|
||||||
|
.append(JSON_ATTR)
|
||||||
|
.append(Constants.DOUBLE_QUOTE)
|
||||||
|
.append(Constants.COLON)
|
||||||
|
.append(Constants.CURLY_BRACE_OPEN)
|
||||||
.append(attributes)
|
.append(attributes)
|
||||||
.append(Constants.CURLY_BRACE_CLOSE);
|
.append(Constants.CURLY_BRACE_CLOSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return sBuilder
|
return sBuilder
|
||||||
.append(Constants.CURLY_BRACE_CLOSE)
|
.append(Constants.CURLY_BRACE_CLOSE)
|
||||||
.toString();
|
.toString();
|
||||||
|
|
|
@ -10,7 +10,6 @@ package ch.ethz.seb.sebserver.webservice.weblayer.api;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -37,7 +36,6 @@ import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
|
||||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage.APIMessageException;
|
import ch.ethz.seb.sebserver.gbl.api.APIMessage.APIMessageException;
|
||||||
|
@ -49,12 +47,10 @@ import ch.ethz.seb.sebserver.gbl.model.Domain.EXAM;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.Page;
|
import ch.ethz.seb.sebserver.gbl.model.Page;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.PageSortOrder;
|
import ch.ethz.seb.sebserver.gbl.model.PageSortOrder;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.OpenEdxSebRestriction;
|
|
||||||
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.exam.SebRestriction;
|
import ch.ethz.seb.sebserver.gbl.model.exam.SebRestriction;
|
||||||
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.LmsSetup.Features;
|
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup.Features;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup.LmsType;
|
|
||||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||||
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;
|
||||||
|
@ -64,11 +60,11 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.Authorization
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.UserService;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.UserService;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.impl.SEBServerUser;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.impl.SEBServerUser;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionService;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionService;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.AdditionalAttributesDAO;
|
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamDAO;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamDAO;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserDAO;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserDAO;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.exam.ExamAdminService;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPIService;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPIService;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.SebRestrictionService;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.SebRestrictionService;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ExamConfigService;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ExamConfigService;
|
||||||
|
@ -84,7 +80,7 @@ public class ExamAdministrationController extends EntityController<Exam, Exam> {
|
||||||
|
|
||||||
private final ExamDAO examDAO;
|
private final ExamDAO examDAO;
|
||||||
private final UserDAO userDAO;
|
private final UserDAO userDAO;
|
||||||
private final AdditionalAttributesDAO additionalAttributesDAO;
|
private final ExamAdminService examAdminService;
|
||||||
private final LmsAPIService lmsAPIService;
|
private final LmsAPIService lmsAPIService;
|
||||||
private final ExamConfigService sebExamConfigService;
|
private final ExamConfigService sebExamConfigService;
|
||||||
private final ExamSessionService examSessionService;
|
private final ExamSessionService examSessionService;
|
||||||
|
@ -99,10 +95,10 @@ public class ExamAdministrationController extends EntityController<Exam, Exam> {
|
||||||
final BeanValidationService beanValidationService,
|
final BeanValidationService beanValidationService,
|
||||||
final LmsAPIService lmsAPIService,
|
final LmsAPIService lmsAPIService,
|
||||||
final UserDAO userDAO,
|
final UserDAO userDAO,
|
||||||
|
final ExamAdminService examAdminService,
|
||||||
final ExamConfigService sebExamConfigService,
|
final ExamConfigService sebExamConfigService,
|
||||||
final ExamSessionService examSessionService,
|
final ExamSessionService examSessionService,
|
||||||
final SebRestrictionService sebRestrictionService,
|
final SebRestrictionService sebRestrictionService) {
|
||||||
final AdditionalAttributesDAO additionalAttributesDAO) {
|
|
||||||
|
|
||||||
super(authorization,
|
super(authorization,
|
||||||
bulkActionService,
|
bulkActionService,
|
||||||
|
@ -113,7 +109,7 @@ public class ExamAdministrationController extends EntityController<Exam, Exam> {
|
||||||
|
|
||||||
this.examDAO = examDAO;
|
this.examDAO = examDAO;
|
||||||
this.userDAO = userDAO;
|
this.userDAO = userDAO;
|
||||||
this.additionalAttributesDAO = additionalAttributesDAO;
|
this.examAdminService = examAdminService;
|
||||||
this.lmsAPIService = lmsAPIService;
|
this.lmsAPIService = lmsAPIService;
|
||||||
this.sebExamConfigService = sebExamConfigService;
|
this.sebExamConfigService = sebExamConfigService;
|
||||||
this.examSessionService = examSessionService;
|
this.examSessionService = examSessionService;
|
||||||
|
@ -337,29 +333,9 @@ public class ExamAdministrationController extends EntityController<Exam, Exam> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Result<Exam> notifyCreated(final Exam entity) {
|
protected Result<Exam> notifyCreated(final Exam entity) {
|
||||||
return Result.tryCatch(() -> {
|
return this.examAdminService
|
||||||
|
.addDefaultIndicator(entity)
|
||||||
final LmsSetup lmsSetup = this.lmsAPIService.getLmsSetup(entity.lmsSetupId)
|
.flatMap(this.examAdminService::applyAdditionalSEBRestrictions);
|
||||||
.getOrThrow();
|
|
||||||
|
|
||||||
// if we have an Open edX LMS involved, add additional initial SEB restriction attributes
|
|
||||||
if (lmsSetup.lmsType == LmsType.OPEN_EDX) {
|
|
||||||
final List<String> permissions = Arrays.asList(
|
|
||||||
OpenEdxSebRestriction.PermissionComponent.ALWAYS_ALLOW_STUFF.key,
|
|
||||||
OpenEdxSebRestriction.PermissionComponent.CHECK_CONFIG_KEY.key);
|
|
||||||
|
|
||||||
this.additionalAttributesDAO.saveAdditionalAttribute(
|
|
||||||
EntityType.EXAM,
|
|
||||||
entity.id,
|
|
||||||
SebRestrictionService.SEB_RESTRICTION_ADDITIONAL_PROPERTY_NAME_PREFIX +
|
|
||||||
OpenEdxSebRestriction.ATTR_PERMISSION_COMPONENTS,
|
|
||||||
StringUtils.join(permissions, Constants.LIST_SEPARATOR_CHAR))
|
|
||||||
.getOrThrow();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return entity;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -187,7 +187,7 @@ public class ExamMonitoringController {
|
||||||
examId,
|
examId,
|
||||||
filterStates.isEmpty()
|
filterStates.isEmpty()
|
||||||
? Objects::nonNull
|
? Objects::nonNull
|
||||||
: conn -> conn != null && filterStates.contains(conn.clientConnection.status))
|
: conn -> conn != null && !filterStates.contains(conn.clientConnection.status))
|
||||||
.getOrThrow();
|
.getOrThrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 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.gbl.model.exam;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.IndicatorType;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.Threshold;
|
||||||
|
|
||||||
|
public class IndicatorTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDefault() throws IOException {
|
||||||
|
final Indicator indicator = new Indicator(
|
||||||
|
null,
|
||||||
|
1L,
|
||||||
|
"Ping",
|
||||||
|
IndicatorType.LAST_PING,
|
||||||
|
"b4b4b4",
|
||||||
|
Arrays.asList(
|
||||||
|
new Indicator.Threshold(2000d, "22b14c"),
|
||||||
|
new Indicator.Threshold(5000d, "ff7e00"),
|
||||||
|
new Indicator.Threshold(10000d, "ed1c24")));
|
||||||
|
|
||||||
|
final JSONMapper mapper = new JSONMapper();
|
||||||
|
final String jsonString = mapper.writeValueAsString(indicator);
|
||||||
|
assertEquals(
|
||||||
|
"{\"examId\":1,\"name\":\"Ping\",\"type\":\"LAST_PING\",\"color\":\"b4b4b4\",\"thresholds\":[{\"value\":2000.0,\"color\":\"22b14c\"},{\"value\":5000.0,\"color\":\"ff7e00\"}",
|
||||||
|
jsonString);
|
||||||
|
|
||||||
|
final String threholds =
|
||||||
|
"[{\"value\":2000.0,\"color\":\"22b14c\"},{\"value\":5000.0,\"color\":\"ff7e00\"},{\"value\":10000.0,\"color\":\"ed1c24\"}]";
|
||||||
|
final Collection<Threshold> values = mapper.readValue(threholds, new TypeReference<Collection<Threshold>>() {
|
||||||
|
});
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"[Threshold [value=2000.0, color=22b14c], Threshold [value=5000.0, color=ff7e00], Threshold [value=10000.0, color=ed1c24]]",
|
||||||
|
values.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue