new seb restrcition strategy and minor fixes

This commit is contained in:
anhefti 2020-03-30 11:03:26 +02:00
parent 09eb17a630
commit b6466d8f1d
19 changed files with 207 additions and 85 deletions

View file

@ -117,6 +117,7 @@ public final class API {
public static final String EXAM_ADMINISTRATION_DOWNLOAD_CONFIG_PATH_SEGMENT = "/download-config";
public static final String EXAM_ADMINISTRATION_CONSISTENCY_CHECK_PATH_SEGMENT = "/check-consistency";
public static final String EXAM_ADMINISTRATION_SEB_RESTRICTION_PATH_SEGMENT = "/seb-restriction";
public static final String EXAM_ADMINISTRATION_CHECK_RESTRICTION_PATH_SEGMENT = "/check-seb-restriction";
public static final String EXAM_INDICATOR_ENDPOINT = "/indicator";

View file

@ -48,7 +48,7 @@ public final class Exam implements GrantEntity {
null,
null,
ExamStatus.FINISHED,
Boolean.FALSE,
// Boolean.FALSE,
null,
Boolean.FALSE,
null);
@ -117,8 +117,8 @@ public final class Exam implements GrantEntity {
@JsonProperty(EXAM.ATTR_STATUS)
public final ExamStatus status;
@JsonProperty(EXAM.ATTR_LMS_SEB_RESTRICTION)
public final Boolean lmsSebRestriction;
// @JsonProperty(EXAM.ATTR_LMS_SEB_RESTRICTION)
// public final Boolean lmsSebRestriction;
@JsonProperty(EXAM.ATTR_BROWSER_KEYS)
public final String browserExamKeys;
@ -145,7 +145,7 @@ public final class Exam implements GrantEntity {
@JsonProperty(EXAM.ATTR_OWNER) final String owner,
@JsonProperty(EXAM.ATTR_SUPPORTER) final Collection<String> supporter,
@JsonProperty(EXAM.ATTR_STATUS) final ExamStatus status,
@JsonProperty(EXAM.ATTR_LMS_SEB_RESTRICTION) final Boolean lmsSebRestriction,
// @JsonProperty(EXAM.ATTR_LMS_SEB_RESTRICTION) final Boolean lmsSebRestriction,
@JsonProperty(EXAM.ATTR_BROWSER_KEYS) final String browserExamKeys,
@JsonProperty(EXAM.ATTR_ACTIVE) final Boolean active,
@JsonProperty(EXAM.ATTR_LASTUPDATE) final String lastUpdate) {
@ -163,7 +163,7 @@ public final class Exam implements GrantEntity {
this.quitPassword = quitPassword;
this.owner = owner;
this.status = (status != null) ? status : getStatusFromDate(startTime, endTime);
this.lmsSebRestriction = (lmsSebRestriction != null) ? lmsSebRestriction : Boolean.FALSE;
// this.lmsSebRestriction = (lmsSebRestriction != null) ? lmsSebRestriction : Boolean.FALSE;
this.browserExamKeys = browserExamKeys;
this.active = (active != null) ? active : Boolean.TRUE;
this.lastUpdate = lastUpdate;
@ -191,7 +191,7 @@ public final class Exam implements GrantEntity {
EXAM.ATTR_STATUS,
ExamStatus.class,
getStatusFromDate(this.startTime, this.endTime));
this.lmsSebRestriction = mapper.getBoolean(EXAM.ATTR_LMS_SEB_RESTRICTION);
// this.lmsSebRestriction = mapper.getBoolean(EXAM.ATTR_LMS_SEB_RESTRICTION);
this.browserExamKeys = mapper.getString(EXAM.ATTR_BROWSER_KEYS);
this.active = mapper.getBoolean(EXAM.ATTR_ACTIVE);
this.supporter = mapper.getStringSet(EXAM.ATTR_SUPPORTER);
@ -216,7 +216,7 @@ public final class Exam implements GrantEntity {
this.quitPassword = null;
this.owner = null;
this.status = (status != null) ? status : getStatusFromDate(this.startTime, this.endTime);
this.lmsSebRestriction = null;
// this.lmsSebRestriction = null;
this.browserExamKeys = null;
this.active = null;
this.supporter = null;
@ -314,9 +314,9 @@ public final class Exam implements GrantEntity {
return this.status;
}
public Boolean getLmsSebRestriction() {
return this.lmsSebRestriction;
}
// public Boolean getLmsSebRestriction() {
// return this.lmsSebRestriction;
// }
public String getBrowserExamKeys() {
return this.browserExamKeys;
@ -357,8 +357,8 @@ public final class Exam implements GrantEntity {
builder.append(this.supporter);
builder.append(", status=");
builder.append(this.status);
builder.append(", lmsSebRestriction=");
builder.append(this.lmsSebRestriction);
// builder.append(", lmsSebRestriction=");
// builder.append(this.lmsSebRestriction);
builder.append(", browserExamKeys=");
builder.append(this.browserExamKeys);
builder.append(", active=");

View file

@ -39,13 +39,13 @@ public final class LmsSetup implements GrantEntity, Activatable {
public enum Features {
COURSE_API,
SEA_RESTRICTION,
SEB_RESTRICTION,
COURSE_STRUCTURE_API,
}
public enum LmsType {
MOCKUP(Features.COURSE_API),
OPEN_EDX(Features.COURSE_API, Features.SEA_RESTRICTION),
OPEN_EDX(Features.COURSE_API, Features.SEB_RESTRICTION),
MOODLE(Features.COURSE_API);
public final EnumSet<Features> features;

View file

@ -636,4 +636,16 @@ public final class Utils {
.toString();
}
public static String truncateText(final String text, final int toChars) {
if (text == null || toChars < 3) {
return text;
}
if (text.length() <= toChars) {
return text;
}
return StringUtils.truncate(text, toChars - 3) + "...";
}
}

View file

@ -65,6 +65,7 @@ import ch.ethz.seb.sebserver.gui.service.remote.download.DownloadService;
import ch.ethz.seb.sebserver.gui.service.remote.download.SebExamConfigDownload;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.CheckExamConsistency;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.CheckSebRestriction;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.DeleteExamConfigMapping;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.DeleteIndicator;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExam;
@ -222,7 +223,7 @@ public class ExamForm implements TemplateComposer {
.call()
.getOr(Collections.emptyList());
if (warnings != null && !warnings.isEmpty()) {
showConsistencyChecks(warnings, formContext.getParent());
showConsistencyChecks(warnings, formContext.getParent());
}
}
@ -234,7 +235,7 @@ public class ExamForm implements TemplateComposer {
formContext.getParent(),
titleKey);
if (warnings != null && !warnings.isEmpty()) {
GridData gridData = (GridData) content.getLayoutData();
final GridData gridData = (GridData) content.getLayoutData();
gridData.verticalIndent = 10;
}
@ -248,6 +249,12 @@ public class ExamForm implements TemplateComposer {
|| examStatus == ExamStatus.RUNNING
&& currentUser.get().hasRole(UserRole.EXAM_ADMIN);
final boolean sebRestrictionAvailable = testSebRestrictionAPI(exam);
final boolean isRestricted = readonly && sebRestrictionAvailable && this.restService
.getBuilder(CheckSebRestriction.class)
.withURIVariable(API.PARAM_MODEL_ID, exam.getModelId())
.call()
.onError(e -> log.error("Unexpected error while trying to verify seb restriction settings: ", e))
.getOr(false);
// The Exam form
final FormHandle<Exam> formHandle = this.pageService.formBuilder(
@ -399,12 +406,14 @@ public class ExamForm implements TemplateComposer {
.newAction(ActionDefinition.EXAM_ENABLE_SEB_RESTRICTION)
.withEntityKey(entityKey)
.withExec(action -> ExamSebRestrictionSettings.setSebRestriction(action, true, this.restService))
.publishIf(() -> sebRestrictionAvailable && readonly && BooleanUtils.isFalse(exam.lmsSebRestriction))
.publishIf(() -> sebRestrictionAvailable && readonly && modifyGrant && !importFromQuizData
&& BooleanUtils.isFalse(isRestricted))
.newAction(ActionDefinition.EXAM_DISABLE_SEB_RESTRICTION)
.withEntityKey(entityKey)
.withExec(action -> ExamSebRestrictionSettings.setSebRestriction(action, false, this.restService))
.publishIf(() -> sebRestrictionAvailable && readonly && BooleanUtils.isTrue(exam.lmsSebRestriction));
.publishIf(() -> sebRestrictionAvailable && readonly && modifyGrant && !importFromQuizData
&& BooleanUtils.isTrue(isRestricted));
// additional data in read-only view
if (readonly && !importFromQuizData) {
@ -413,8 +422,7 @@ public class ExamForm implements TemplateComposer {
this.widgetFactory.addFormSubContextHeader(
content,
CONFIG_LIST_TITLE_KEY,
CONFIG_LIST_TITLE_TOOLTIP_KEY
);
CONFIG_LIST_TITLE_TOOLTIP_KEY);
final EntityTable<ExamConfigurationMap> configurationTable =
this.pageService.entityTableBuilder(this.restService.getRestCall(GetExamConfigMappingsPage.class))
@ -506,8 +514,7 @@ public class ExamForm implements TemplateComposer {
this.widgetFactory.addFormSubContextHeader(
content,
INDICATOR_LIST_TITLE_KEY,
INDICATOR_LIST_TITLE_TOOLTIP_KEY
);
INDICATOR_LIST_TITLE_TOOLTIP_KEY);
final EntityTable<Indicator> indicatorTable =
this.pageService.entityTableBuilder(this.restService.getRestCall(GetIndicatorPage.class))
@ -597,7 +604,7 @@ public class ExamForm implements TemplateComposer {
.withURIVariable(API.PARAM_MODEL_ID, String.valueOf(exam.lmsSetupId))
.call()
.onError(t -> log.error("Failed to check SEB restriction API: ", t))
.map(lmsSetup -> lmsSetup.lmsType.features.contains(Features.SEA_RESTRICTION))
.map(lmsSetup -> lmsSetup.lmsType.features.contains(Features.SEB_RESTRICTION))
.getOr(false);
}

View file

@ -114,11 +114,18 @@ public class RegisterPage implements TemplateComposer {
@Override
public void compose(final PageContext pageContext) {
final Composite outer = new Composite(pageContext.getParent(), SWT.NONE);
final GridLayout outerLayout = new GridLayout();
outerLayout.marginLeft = 50;
outerLayout.marginRight = 50;
outer.setLayout(outerLayout);
outer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
final Composite parent = PageService.createManagedVScrolledComposite(
pageContext.getParent(),
outer,
scrolledComposite -> {
final Composite result = new Composite(scrolledComposite, SWT.NONE);
result.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
result.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, true, true));
final GridLayout contentOutlaying = new GridLayout();
contentOutlaying.marginHeight = 0;
contentOutlaying.marginWidth = 0;
@ -147,7 +154,6 @@ public class RegisterPage implements TemplateComposer {
.sorted(ResourceService.RESOURCE_COMPARATOR)
.collect(Collectors.toList());
this.widgetFactory.labelLocalizedTitle(parent, TITLE_TEXT_KEY);
// The UserAccount form

View file

@ -198,6 +198,9 @@ public final class PageAction {
PageAction.this.getName(),
e.getMessage(),
Utils.getErrorCauseMessage(e));
PageAction.this.pageContext.notifyError(
PageContext.UNEXPECTED_ERROR_KEY,
e);
return Result.ofError(e);
} catch (final Exception e) {
log.error("Failed to execute action: {} | error: {} | cause: {}",

View file

@ -0,0 +1,41 @@
/*
* 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.gui.service.remote.webservice.api.exam;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.core.type.TypeReference;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
@Lazy
@Component
@GuiProfile
public class CheckSebRestriction extends RestCall<Boolean> {
public CheckSebRestriction() {
super(new TypeKey<>(
CallType.UNDEFINED,
EntityType.EXAM_SEB_RESTRICTION,
new TypeReference<Boolean>() {
}),
HttpMethod.GET,
MediaType.APPLICATION_JSON_UTF8,
API.EXAM_ADMINISTRATION_ENDPOINT
+ API.MODEL_ID_VAR_PATH_SEGMENT
+ API.EXAM_ADMINISTRATION_CHECK_RESTRICTION_PATH_SEGMENT);
}
}

View file

@ -19,6 +19,7 @@ import org.eclipse.swt.widgets.Listener;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.util.Tuple;
import ch.ethz.seb.sebserver.gbl.util.Utils;
public final class SingleSelection extends Combo implements Selection {
@ -41,7 +42,7 @@ public final class SingleSelection extends Combo implements Selection {
this.valueMapping.clear();
this.keyMapping.clear();
this.valueMapping.addAll(mapping.stream()
.map(t -> t._2)
.map(t -> Utils.truncateText(t._2, 100))
.collect(Collectors.toList()));
this.keyMapping.addAll(mapping.stream()
.map(t -> t._1)

View file

@ -8,6 +8,44 @@
package ch.ethz.seb.sebserver.gui.widget;
import static ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService.POLYGLOT_WIDGET_FUNCTION_KEY;
import java.io.InputStream;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.rap.rwt.client.service.JavaScriptExecutor;
import org.eclipse.rap.rwt.widgets.WidgetUtil;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Device;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.ColorDialog;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.DateTime;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.swt.widgets.Widget;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.IndicatorType;
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.Threshold;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
@ -19,29 +57,6 @@ import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
import ch.ethz.seb.sebserver.gui.service.page.PageService;
import ch.ethz.seb.sebserver.gui.service.page.impl.DefaultPageLayout;
import ch.ethz.seb.sebserver.gui.service.push.ServerPushService;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.rap.rwt.client.service.JavaScriptExecutor;
import org.eclipse.rap.rwt.widgets.WidgetUtil;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Device;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import java.io.InputStream;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.function.Consumer;
import java.util.function.Supplier;
import static ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService.POLYGLOT_WIDGET_FUNCTION_KEY;
@Lazy
@Service
@ -151,7 +166,7 @@ public class WidgetFactory {
TEXT_H1("h1"),
TEXT_H2("h2"),
TEXT_H3("h3"),
SUBTITLE( "subtitle"),
SUBTITLE("subtitle"),
IMAGE_BUTTON("imageButton"),
TEXT_ACTION("action"),
TEXT_READONLY("readonlyText"),
@ -179,7 +194,9 @@ public class WidgetFactory {
LIST_NAVIGATION("list-nav"),
PLAIN_PWD("pwdplain"),
COLOR_BOX("colorbox")
COLOR_BOX("colorbox"),
REGISTER_FORM("register")
;
@ -228,8 +245,8 @@ public class WidgetFactory {
labelLocalizedTitle.setLayoutData(gridData);
// sub title if defined in language properties
LocTextKey subTitleTextKey = new LocTextKey(title.name + SUB_TITLE_TExT_SUFFIX);
if (i18nSupport.hasText(subTitleTextKey)) {
final LocTextKey subTitleTextKey = new LocTextKey(title.name + SUB_TITLE_TExT_SUFFIX);
if (this.i18nSupport.hasText(subTitleTextKey)) {
final GridData gridDataSub = new GridData(SWT.FILL, SWT.FILL, true, false);
final Label labelLocalizedSubTitle = labelLocalized(
defaultPageLayout,
@ -241,20 +258,21 @@ public class WidgetFactory {
return defaultPageLayout;
}
public void addFormSubContextHeader(final Composite parent, final LocTextKey titleTextKey, final LocTextKey tooltipTextKey) {
GridData gridData = new GridData(SWT.FILL, SWT.BOTTOM, true, false);
public void addFormSubContextHeader(final Composite parent, final LocTextKey titleTextKey,
final LocTextKey tooltipTextKey) {
final GridData gridData = new GridData(SWT.FILL, SWT.BOTTOM, true, false);
gridData.horizontalIndent = 8;
gridData.verticalIndent = 10;
Label subContextLabel = labelLocalized(
final Label subContextLabel = labelLocalized(
parent,
CustomVariant.TEXT_H3,
titleTextKey,
tooltipTextKey);
subContextLabel.setLayoutData(gridData);
GridData gridData1 = new GridData(SWT.FILL, SWT.BOTTOM, true, false);
final GridData gridData1 = new GridData(SWT.FILL, SWT.BOTTOM, true, false);
gridData1.heightHint = 5;
gridData1.horizontalIndent = 8;
Label subContextSeparator = labelSeparator(parent);
final Label subContextSeparator = labelSeparator(parent);
subContextSeparator.setLayoutData(gridData1);
}
@ -289,7 +307,7 @@ public class WidgetFactory {
public Composite createWarningPanel(final Composite parent) {
final Composite composite = new Composite(parent, SWT.NONE);
GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false);
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false);
composite.setLayoutData(gridData);
final GridLayout gridLayout = new GridLayout(1, true);
gridLayout.marginWidth = 20;
@ -379,7 +397,7 @@ public class WidgetFactory {
public Label labelLocalizedTitle(final Composite content, final LocTextKey locTextKey) {
final Label labelLocalized = labelLocalized(content, CustomVariant.TEXT_H1, locTextKey);
GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false);
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false);
labelLocalized.setLayoutData(gridData);
return labelLocalized;
}

View file

@ -107,7 +107,8 @@ public class ExamDAOImpl implements ExamDAO {
.execute()
: this.examRecordMapper.selectByExample()
.build()
.execute()).flatMap(this::toDomainModel);
.execute())
.flatMap(this::toDomainModel);
}
@Override
@ -210,9 +211,7 @@ public class ExamDAOImpl implements ExamDAO {
(exam.status != null)
? exam.status.name()
: null,
(exam.lmsSebRestriction != null)
? BooleanUtils.toIntegerObject(exam.lmsSebRestriction)
: null,
1, // seb restriction (deprecated)
null, // updating
null, // lastUpdate
null // active
@ -259,6 +258,10 @@ public class ExamDAOImpl implements ExamDAO {
// used to save instead of create a new one
if (records != null && records.size() > 0) {
final ExamRecord examRecord = records.get(0);
// if another institution tries to import an exam that already exists
if (!exam.institutionId.equals(examRecord.getInstitutionId())) {
throw new IllegalStateException("Exam cannot be imported twice from different institutions");
}
final ExamRecord newRecord = new ExamRecord(
examRecord.getId(),
null, null, null, null, null,
@ -266,7 +269,7 @@ public class ExamDAOImpl implements ExamDAO {
null, // quitPassword
null, // browser keys
null, // status
null, // lmsSebRestriction
null, // lmsSebRestriction (deprecated)
null, // updating
null, // lastUpdate
BooleanUtils.toIntegerObject(exam.active));
@ -288,7 +291,7 @@ public class ExamDAOImpl implements ExamDAO {
null, // quitPassword
null, // browser keys
(exam.status != null) ? exam.status.name() : ExamStatus.UP_COMING.name(),
BooleanUtils.toInteger(exam.lmsSebRestriction),
1, // seb restriction (deprecated)
BooleanUtils.toInteger(false),
null, // lastUpdate
BooleanUtils.toInteger(true));
@ -752,7 +755,7 @@ public class ExamDAOImpl implements ExamDAO {
record.getOwner(),
supporter,
status,
BooleanUtils.toBooleanObject((quizData != null) ? record.getLmsSebRestriction() : null),
// BooleanUtils.toBooleanObject((quizData != null) ? record.getLmsSebRestriction() : null),
record.getBrowserKeys(),
BooleanUtils.toBooleanObject((quizData != null) ? record.getActive() : null),
record.getLastupdate());

View file

@ -17,13 +17,15 @@ public interface ExamAdminService {
*
* @param exam The Exam to add the default indicator
* @return the Exam with added default indicator */
Result<Exam> addDefaultIndicator(final Exam exam);
Result<Exam> addDefaultIndicator(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);
Result<Exam> applyAdditionalSEBRestrictions(Exam exam);
Result<Boolean> isRestricted(Exam exam);
}

View file

@ -127,4 +127,15 @@ public class ExamAdminServiceImpl implements ExamAdminService {
});
}
@Override
public Result<Boolean> isRestricted(final Exam exam) {
if (exam == null) {
return Result.of(false);
}
return this.lmsAPIService
.getLmsAPITemplate(exam.lmsSetupId)
.map(lmsAPI -> !lmsAPI.getSebClientRestriction(exam).hasError());
}
}

View file

@ -121,7 +121,6 @@ public class SebRestrictionServiceImpl implements SebRestrictionService {
null, null, null, null, null, null, null, null, null, null, null,
exam.supporter,
exam.status,
exam.lmsSebRestriction,
(browserExamKeys != null && !browserExamKeys.isEmpty())
? StringUtils.join(browserExamKeys, Constants.LIST_SEPARATOR_CHAR)
: StringUtils.EMPTY,
@ -157,7 +156,7 @@ public class SebRestrictionServiceImpl implements SebRestrictionService {
public Result<Exam> applySebClientRestriction(final Exam exam) {
if (!this.lmsAPIService
.getLmsSetup(exam.lmsSetupId)
.getOrThrow().lmsType.features.contains(Features.SEA_RESTRICTION)) {
.getOrThrow().lmsType.features.contains(Features.SEB_RESTRICTION)) {
return Result.of(exam);
}

View file

@ -14,7 +14,6 @@ import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.apache.commons.lang3.BooleanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
@ -31,6 +30,7 @@ import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ConfigurationDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamConfigurationMapDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.exam.ExamAdminService;
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamConfigUpdateService;
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamSessionService;
@ -46,19 +46,22 @@ public class ExamConfigUpdateServiceImpl implements ExamConfigUpdateService {
private final ExamConfigurationMapDAO examConfigurationMapDAO;
private final ExamSessionService examSessionService;
private final ExamUpdateHandler examUpdateHandler;
private final ExamAdminService examAdminService;
protected ExamConfigUpdateServiceImpl(
final ExamDAO examDAO,
final ConfigurationDAO configurationDAO,
final ExamConfigurationMapDAO examConfigurationMapDAO,
final ExamSessionService examSessionService,
final ExamUpdateHandler examUpdateHandler) {
final ExamUpdateHandler examUpdateHandler,
final ExamAdminService examAdminService) {
this.examDAO = examDAO;
this.configurationDAO = configurationDAO;
this.examConfigurationMapDAO = examConfigurationMapDAO;
this.examSessionService = examSessionService;
this.examUpdateHandler = examUpdateHandler;
this.examAdminService = examAdminService;
}
// processing:
@ -127,7 +130,8 @@ public class ExamConfigUpdateServiceImpl implements ExamConfigUpdateService {
// generate the new Config Key and update the Config Key within the LMSSetup API for each exam (delete old Key and add new Key)
for (final Exam exam : exams) {
if (exam.getStatus() == ExamStatus.RUNNING && BooleanUtils.isTrue(exam.lmsSebRestriction)) {
if (exam.getStatus() == ExamStatus.RUNNING || this.examAdminService.isRestricted(exam).getOr(false)) {
this.examUpdateHandler
.getSebRestrictionService()
.applySebClientRestriction(exam)
@ -197,7 +201,7 @@ public class ExamConfigUpdateServiceImpl implements ExamConfigUpdateService {
.getOrThrow();
// update seb client restriction if the feature is activated for the exam
if (exam.lmsSebRestriction) {
if (this.examAdminService.isRestricted(exam).getOr(false)) {
this.examUpdateHandler
.getSebRestrictionService()
.applySebClientRestriction(exam)

View file

@ -125,7 +125,7 @@ public class ExamSessionServiceImpl implements ExamSessionService {
// if SEB restriction is not available no consistency violation message is added
final LmsSetup lmsSetup = this.lmsAPIService.getLmsSetup(exam.lmsSetupId)
.getOr(null);
if (lmsSetup != null && lmsSetup.lmsType.features.contains(Features.SEA_RESTRICTION)) {
if (lmsSetup != null && lmsSetup.lmsType.features.contains(Features.SEB_RESTRICTION)) {
this.lmsAPIService.getLmsAPITemplate(exam.lmsSetupId)
.map(t -> {
if (t.testCourseRestrictionAPI().isOk()) {

View file

@ -22,7 +22,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.mybatis.dynamic.sql.SqlTable;
import org.slf4j.Logger;
@ -227,6 +226,24 @@ public class ExamAdministrationController extends EntityController<Exam, Exam> {
.getOrThrow();
}
@RequestMapping(
path = API.MODEL_ID_VAR_PATH_SEGMENT
+ API.EXAM_ADMINISTRATION_CHECK_RESTRICTION_PATH_SEGMENT,
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public Boolean checkSebRestriction(
@PathVariable final Long modelId,
@RequestParam(
name = API.PARAM_INSTITUTION_ID,
required = true,
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId) {
checkReadPrivilege(institutionId);
return this.examDAO.byPK(modelId)
.flatMap(this.examAdminService::isRestricted)
.getOrThrow();
}
// ****************************************************************************
// **** SEB Restriction
@ -266,7 +283,7 @@ public class ExamAdministrationController extends EntityController<Exam, Exam> {
return this.entityDAO.byPK(examId)
.flatMap(this.authorization::checkModify)
.flatMap(exam -> this.sebRestrictionService.saveSebRestrictionToExam(exam, sebRestriction))
.flatMap(exam -> BooleanUtils.isTrue(exam.lmsSebRestriction)
.flatMap(exam -> this.examAdminService.isRestricted(exam).getOrThrow()
? this.applySebRestriction(exam, true)
: Result.of(exam))
.getOrThrow();
@ -397,7 +414,7 @@ public class ExamAdministrationController extends EntityController<Exam, Exam> {
final LmsSetup lmsSetup = this.lmsAPIService.getLmsSetup(exam.lmsSetupId)
.getOrThrow();
if (!lmsSetup.lmsType.features.contains(Features.SEA_RESTRICTION)) {
if (!lmsSetup.lmsType.features.contains(Features.SEB_RESTRICTION)) {
return Result.ofError(new UnsupportedOperationException(
"SEB Restriction feature not available for LMS type: " + lmsSetup.lmsType));
}
@ -405,7 +422,7 @@ public class ExamAdministrationController extends EntityController<Exam, Exam> {
if (restrict) {
if (!this.lmsAPIService
.getLmsSetup(exam.lmsSetupId)
.getOrThrow().lmsType.features.contains(Features.SEA_RESTRICTION)) {
.getOrThrow().lmsType.features.contains(Features.SEB_RESTRICTION)) {
return Result.ofError(new APIMessageException(
APIMessage.ErrorMessage.ILLEGAL_API_ARGUMENT

View file

@ -809,7 +809,6 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
null, null,
Utils.immutableCollectionOf(userId),
ExamStatus.RUNNING,
true,
null,
true,
null);

View file

@ -65,7 +65,6 @@ public class ExamAPITest extends AdministrationAPIIntegrationTester {
exam.owner,
Arrays.asList("user5"),
null,
true,
null,
true,
null))
@ -97,7 +96,6 @@ public class ExamAPITest extends AdministrationAPIIntegrationTester {
exam.owner,
Arrays.asList("user2"),
null,
true,
null,
true,
null))