SEBSERV-105 GUI implementation and bug-fix

This commit is contained in:
anhefti 2020-01-13 15:08:08 +01:00
parent 151b6b734a
commit 45fb04955b
16 changed files with 236 additions and 91 deletions

View file

@ -35,6 +35,7 @@ public final class Constants {
public static final long HOUR_IN_MILLIS = 60 * MINUTE_IN_MILLIS; public static final long HOUR_IN_MILLIS = 60 * MINUTE_IN_MILLIS;
public static final long DAY_IN_MILLIS = 24 * HOUR_IN_MILLIS; public static final long DAY_IN_MILLIS = 24 * HOUR_IN_MILLIS;
public static final Character CARRIAGE_RETURN = '\n';
public static final Character CURLY_BRACE_OPEN = '{'; public static final Character CURLY_BRACE_OPEN = '{';
public static final Character CURLY_BRACE_CLOSE = '}'; public static final Character CURLY_BRACE_CLOSE = '}';
public static final Character COLON = ':'; public static final Character COLON = ':';

View file

@ -93,7 +93,7 @@ public class OpenEdxSebRestriction {
public final Collection<String> permissionComponents; public final Collection<String> permissionComponents;
@JsonProperty(ATTR_USER_BANNING_ENABLED) @JsonProperty(ATTR_USER_BANNING_ENABLED)
public final boolean banningEnabled; public final Boolean banningEnabled;
@JsonCreator @JsonCreator
OpenEdxSebRestriction( OpenEdxSebRestriction(

View file

@ -175,6 +175,56 @@ public final class Utils {
.collect(Collectors.toList())); .collect(Collectors.toList()));
} }
public static Collection<String> getListOfLines(final String list) {
if (list == null) {
return Collections.emptyList();
}
return Arrays.asList(StringUtils.split(
streamlineCarriageReturn(list),
Constants.CARRIAGE_RETURN));
}
public static String convertCarriageReturnToListSeparator(final String value) {
if (value == null) {
return null;
}
return streamlineCarriageReturn(value.trim())
.replace(Constants.CARRIAGE_RETURN, Constants.LIST_SEPARATOR_CHAR);
}
public static String convertListSeparatorToCarriageReturn(final String value) {
if (value == null) {
return null;
}
return value
.trim()
.replace(Constants.LIST_SEPARATOR_CHAR, Constants.CARRIAGE_RETURN);
}
public static String streamlineCarriageReturn(final String value) {
if (value == null) {
return null;
}
return value.replace('\r', '\n')
.replace("\r\n", "\n");
}
public static Collection<String> getListFromString(final String list) {
return getListFromString(list, Constants.LIST_SEPARATOR);
}
public static Collection<String> getListFromString(final String list, final String separator) {
if (list == null) {
return Collections.emptyList();
}
return Arrays.asList(StringUtils.split(list, separator));
}
public static Result<Long> dateTimeStringToTimestamp(final String startTime) { public static Result<Long> dateTimeStringToTimestamp(final String startTime) {
return Result.tryCatch(() -> { return Result.tryCatch(() -> {
return DateTime.parse(startTime, Constants.STANDARD_DATE_TIME_FORMATTER).getMillis(); return DateTime.parse(startTime, Constants.STANDARD_DATE_TIME_FORMATTER).getMillis();

View file

@ -394,6 +394,8 @@ public class ExamForm implements TemplateComposer {
// additional data in read-only view // additional data in read-only view
if (readonly && !importFromQuizData) { if (readonly && !importFromQuizData) {
this.widgetFactory.labelSeparator(content);
// List of SEB Configuration // List of SEB Configuration
this.widgetFactory.labelLocalized( this.widgetFactory.labelLocalized(
content, content,
@ -479,6 +481,8 @@ public class ExamForm implements TemplateComposer {
.noEventPropagation() .noEventPropagation()
.publishIf(() -> userGrantCheck.r() && configurationTable.hasAnyContent()); .publishIf(() -> userGrantCheck.r() && configurationTable.hasAnyContent());
this.widgetFactory.labelSeparator(content);
// List of Indicators // List of Indicators
this.widgetFactory.labelLocalized( this.widgetFactory.labelLocalized(
content, content,

View file

@ -8,6 +8,9 @@
package ch.ethz.seb.sebserver.gui.content; package ch.ethz.seb.sebserver.gui.content;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
@ -16,14 +19,14 @@ import java.util.function.Supplier;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
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.JSONMapper;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.exam.OpenEdxSebRestriction; import ch.ethz.seb.sebserver.gbl.model.exam.OpenEdxSebRestriction;
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.LmsType; import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup.LmsType;
import ch.ethz.seb.sebserver.gbl.util.Utils; import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; import ch.ethz.seb.sebserver.gui.form.Form;
import ch.ethz.seb.sebserver.gui.form.FormBuilder; import ch.ethz.seb.sebserver.gui.form.FormBuilder;
import ch.ethz.seb.sebserver.gui.form.FormHandle; import ch.ethz.seb.sebserver.gui.form.FormHandle;
import ch.ethz.seb.sebserver.gui.service.ResourceService; import ch.ethz.seb.sebserver.gui.service.ResourceService;
@ -54,6 +57,10 @@ public class ExamSebRestrictionSettings {
new LocTextKey("sebserver.exam.form.sebrestriction.WHITELIST_PATHS"); new LocTextKey("sebserver.exam.form.sebrestriction.WHITELIST_PATHS");
private final static LocTextKey SEB_RESTRICTION_FORM_EDX_PERMISSIONS = private final static LocTextKey SEB_RESTRICTION_FORM_EDX_PERMISSIONS =
new LocTextKey("sebserver.exam.form.sebrestriction.PERMISSION_COMPONENTS"); new LocTextKey("sebserver.exam.form.sebrestriction.PERMISSION_COMPONENTS");
private final static LocTextKey SEB_RESTRICTION_FORM_EDX_BLACKLIST_CHAPTERS =
new LocTextKey("sebserver.exam.form.sebrestriction.BLACKLIST_CHAPTERS");
private final static LocTextKey SEB_RESTRICTION_FORM_EDX_USER_BANNING_ENABLED =
new LocTextKey("sebserver.exam.form.sebrestriction.USER_BANNING_ENABLED");
static final String PAGE_CONTEXT_ATTR_LMS_TYPE = "ATTR_LMS_TYPE"; static final String PAGE_CONTEXT_ATTR_LMS_TYPE = "ATTR_LMS_TYPE";
@ -66,7 +73,8 @@ public class ExamSebRestrictionSettings {
new ModalInputDialog<FormHandle<?>>( new ModalInputDialog<FormHandle<?>>(
action.pageContext().getParent().getShell(), action.pageContext().getParent().getShell(),
pageService.getWidgetFactory()) pageService.getWidgetFactory())
.setVeryLargeDialogWidth(); .setDialogWidth(740)
.setDialogHeight(400);
final SebRestrictionPropertiesForm bindFormContext = new SebRestrictionPropertiesForm( final SebRestrictionPropertiesForm bindFormContext = new SebRestrictionPropertiesForm(
pageService, pageService,
@ -96,19 +104,35 @@ public class ExamSebRestrictionSettings {
final LmsType lmsType = getLmsType(pageContext); final LmsType lmsType = getLmsType(pageContext);
SebRestriction bodyValue = null; SebRestriction bodyValue = null;
try { try {
final JSONMapper jsonMapper = pageService.getJSONMapper(); final Form form = formHandle.getForm();
if (lmsType == LmsType.OPEN_EDX) { final Collection<String> browserKeys = Utils.getListOfLines(
final OpenEdxSebRestriction edxProperties = jsonMapper.readValue( form.getFieldValue(SebRestriction.ATTR_BROWSER_KEYS));
formHandle.getFormBinding().getFormAsJson(),
OpenEdxSebRestriction.class);
bodyValue = SebRestriction.from(Long.parseLong(entityKey.modelId), edxProperties);
} else {
bodyValue = jsonMapper.readValue(
formHandle.getFormBinding().getFormAsJson(),
SebRestriction.class);
}
} catch (final Exception e) {
final Map<String, String> additionalAttributes = new HashMap<>();
if (lmsType == LmsType.OPEN_EDX) {
additionalAttributes.put(
OpenEdxSebRestriction.ATTR_PERMISSION_COMPONENTS,
form.getFieldValue(OpenEdxSebRestriction.ATTR_PERMISSION_COMPONENTS));
additionalAttributes.put(
OpenEdxSebRestriction.ATTR_WHITELIST_PATHS,
form.getFieldValue(OpenEdxSebRestriction.ATTR_WHITELIST_PATHS));
additionalAttributes.put(
OpenEdxSebRestriction.ATTR_USER_BANNING_ENABLED,
form.getFieldValue(OpenEdxSebRestriction.ATTR_USER_BANNING_ENABLED));
additionalAttributes.put(
OpenEdxSebRestriction.ATTR_BLACKLIST_CHAPTERS,
Utils.convertCarriageReturnToListSeparator(
form.getFieldValue(OpenEdxSebRestriction.ATTR_BLACKLIST_CHAPTERS)));
}
bodyValue = new SebRestriction(
Long.parseLong(entityKey.modelId),
null,
browserKeys,
additionalAttributes);
} catch (final Exception e) {
e.printStackTrace();
} }
return !pageService return !pageService
@ -116,17 +140,8 @@ public class ExamSebRestrictionSettings {
.getBuilder(SaveSebRestriction.class) .getBuilder(SaveSebRestriction.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId) .withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.withBody(bodyValue) .withBody(bodyValue)
//.withFormBinding(formHandle.getFormBinding())
.call() .call()
.onError(formHandle::handleError) .onError(formHandle::handleError)
.map(mapping -> {
pageService.executePageAction(
pageService.pageActionBuilder(pageContext.clearEntityKeys())
.newAction(ActionDefinition.EXAM_VIEW_FROM_LIST)
.withEntityKey(pageContext.getParentEntityKey())
.create());
return mapping;
})
.hasError(); .hasError();
} }
@ -152,15 +167,22 @@ public class ExamSebRestrictionSettings {
final EntityKey entityKey = this.pageContext.getEntityKey(); final EntityKey entityKey = this.pageContext.getEntityKey();
final LmsType lmsType = getLmsType(this.pageContext); final LmsType lmsType = getLmsType(this.pageContext);
final Composite content = this.pageService
.getWidgetFactory()
.createPopupScrollComposite(parent);
final SebRestriction sebRestriction = restService final SebRestriction sebRestriction = restService
.getBuilder(GetSebRestriction.class) .getBuilder(GetSebRestriction.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId) .withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call() .call()
.getOrThrow(); .getOrThrow();
final PageContext formContext = this.pageContext.clearEntityKeys(); final PageContext formContext = this.pageContext
.copyOf(content)
.clearEntityKeys();
final FormHandle<SebRestriction> formHandle = this.pageService.formBuilder( final FormHandle<SebRestriction> formHandle = this.pageService.formBuilder(
formContext.copyOf(parent), 3) formContext, 3)
.withDefaultSpanEmptyCell(0) .withDefaultSpanEmptyCell(0)
.withEmptyCellSeparation(false) .withEmptyCellSeparation(false)
.readonly(false) .readonly(false)
@ -168,14 +190,14 @@ public class ExamSebRestrictionSettings {
.addField(FormBuilder.text( .addField(FormBuilder.text(
SebRestriction.ATTR_CONFIG_KEYS, SebRestriction.ATTR_CONFIG_KEYS,
SEB_RESTRICTION_FORM_CONFIG_KEYS, SEB_RESTRICTION_FORM_CONFIG_KEYS,
StringUtils.join(sebRestriction.getConfigKeys(), '\n')) StringUtils.join(sebRestriction.getConfigKeys(), Constants.CARRIAGE_RETURN))
.asArea(25) .asArea(50)
.readonly(true)) .readonly(true))
.addField(FormBuilder.text( .addField(FormBuilder.text(
SebRestriction.ATTR_BROWSER_KEYS, SebRestriction.ATTR_BROWSER_KEYS,
SEB_RESTRICTION_FORM_BROWSER_KEYS, SEB_RESTRICTION_FORM_BROWSER_KEYS,
StringUtils.join(sebRestriction.getBrowserExamKeys(), '\n')) StringUtils.join(sebRestriction.getBrowserExamKeys(), Constants.CARRIAGE_RETURN))
.asArea()) .asArea())
.addFieldIf( .addFieldIf(
@ -196,6 +218,26 @@ public class ExamSebRestrictionSettings {
.get(OpenEdxSebRestriction.ATTR_PERMISSION_COMPONENTS), .get(OpenEdxSebRestriction.ATTR_PERMISSION_COMPONENTS),
() -> resourceService.sebRestrictionPermissionResources())) () -> resourceService.sebRestrictionPermissionResources()))
.addFieldIf(
() -> lmsType == LmsType.OPEN_EDX,
() -> FormBuilder.text(
OpenEdxSebRestriction.ATTR_BLACKLIST_CHAPTERS,
SEB_RESTRICTION_FORM_EDX_BLACKLIST_CHAPTERS,
Utils.convertListSeparatorToCarriageReturn(
sebRestriction
.getAdditionalProperties()
.get(OpenEdxSebRestriction.ATTR_BLACKLIST_CHAPTERS)))
.asArea())
.addFieldIf(
() -> lmsType == LmsType.OPEN_EDX,
() -> FormBuilder.checkbox(
OpenEdxSebRestriction.ATTR_USER_BANNING_ENABLED,
SEB_RESTRICTION_FORM_EDX_USER_BANNING_ENABLED,
sebRestriction
.getAdditionalProperties()
.get(OpenEdxSebRestriction.ATTR_USER_BANNING_ENABLED)))
.build(); .build();
return () -> formHandle; return () -> formHandle;

View file

@ -149,6 +149,7 @@ public class SebExamConfigList implements TemplateComposer {
// configuration template table // configuration template table
widgetFactory.label(content, ""); widgetFactory.label(content, "");
widgetFactory.labelSeparator(content);
widgetFactory.labelLocalizedTitle( widgetFactory.labelLocalizedTitle(
content, content,
TITLE_TEMPLATE_TEXT_KEY); TITLE_TEMPLATE_TEXT_KEY);
@ -192,7 +193,8 @@ public class SebExamConfigList implements TemplateComposer {
.publishIf(examConfigGrant::iw) .publishIf(examConfigGrant::iw)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_PROP_FROM_LIST) .newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_PROP_FROM_LIST)
.withSelect(configTable::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) .withSelect(configTable::getSelection, PageAction::applySingleSelectionAsEntityKey,
EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> configTable.hasAnyContent()) .publishIf(() -> configTable.hasAnyContent())
.newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY_PROP_FROM_LIST) .newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY_PROP_FROM_LIST)

View file

@ -289,6 +289,7 @@ public class SebExamConfigPropForm implements TemplateComposer {
if (isAttachedToExam) { if (isAttachedToExam) {
widgetFactory.labelSeparator(content);
widgetFactory.labelLocalized( widgetFactory.labelLocalized(
content, content,
CustomVariant.TEXT_H3, CustomVariant.TEXT_H3,

View file

@ -250,12 +250,12 @@ public enum ActionDefinition {
ActionCategory.FORM), ActionCategory.FORM),
EXAM_ENABLE_SEB_RESTRICTION( EXAM_ENABLE_SEB_RESTRICTION(
new LocTextKey("sebserver.exam.action.sebrestriction.enable"), new LocTextKey("sebserver.exam.action.sebrestriction.enable"),
ImageIcon.LOCK, ImageIcon.UNLOCK,
PageStateDefinitionImpl.EXAM_VIEW, PageStateDefinitionImpl.EXAM_VIEW,
ActionCategory.FORM), ActionCategory.FORM),
EXAM_DISABLE_SEB_RESTRICTION( EXAM_DISABLE_SEB_RESTRICTION(
new LocTextKey("sebserver.exam.action.sebrestriction.disable"), new LocTextKey("sebserver.exam.action.sebrestriction.disable"),
ImageIcon.UNLOCK, ImageIcon.LOCK,
PageStateDefinitionImpl.EXAM_VIEW, PageStateDefinitionImpl.EXAM_VIEW,
ActionCategory.FORM), ActionCategory.FORM),

View file

@ -611,7 +611,7 @@ public class ResourceService {
return Arrays.asList(WhiteListPath.values()) return Arrays.asList(WhiteListPath.values())
.stream() .stream()
.map(type -> new Tuple<>( .map(type -> new Tuple<>(
type.name(), type.key,
this.i18nSupport.getText(SEB_RESTRICTION_WHITE_LIST_PREFIX + type.name(), type.key))) this.i18nSupport.getText(SEB_RESTRICTION_WHITE_LIST_PREFIX + type.name(), type.key)))
.sorted(RESOURCE_COMPARATOR) .sorted(RESOURCE_COMPARATOR)
.collect(Collectors.toList()); .collect(Collectors.toList());
@ -621,7 +621,7 @@ public class ResourceService {
return Arrays.asList(PermissionComponent.values()) return Arrays.asList(PermissionComponent.values())
.stream() .stream()
.map(type -> new Tuple<>( .map(type -> new Tuple<>(
type.name(), type.key,
this.i18nSupport.getText(SEB_RESTRICTION_PERMISSIONS_PREFIX + type.name(), type.key))) this.i18nSupport.getText(SEB_RESTRICTION_PERMISSIONS_PREFIX + type.name(), type.key)))
.sorted(RESOURCE_COMPARATOR) .sorted(RESOURCE_COMPARATOR)
.collect(Collectors.toList()); .collect(Collectors.toList());

View file

@ -501,7 +501,7 @@ public class WidgetFactory {
public Label labelSeparator(final Composite parent) { public Label labelSeparator(final Composite parent) {
final Label label = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL); final Label label = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL);
final GridData data = new GridData(SWT.FILL, SWT.TOP, true, true); final GridData data = new GridData(SWT.FILL, SWT.TOP, true, false);
label.setLayoutData(data); label.setLayoutData(data);
return label; return label;
} }

View file

@ -38,7 +38,7 @@ public interface AdditionalAttributesDAO {
* @param entityId the entity identifier (primary key) * @param entityId the entity identifier (primary key)
* @param name the name of the attribute * @param name the name of the attribute
* @param value the value of the attribute */ * @param value the value of the attribute */
void saveAdditionalAttribute( Result<AdditionalAttributeRecord> saveAdditionalAttribute(
EntityType type, EntityType type,
Long entityId, Long entityId,
String name, String name,

View file

@ -59,53 +59,60 @@ public class AdditionalAttributesDAOImpl implements AdditionalAttributesDAO {
@Override @Override
@Transactional @Transactional
public void saveAdditionalAttribute( public Result<AdditionalAttributeRecord> saveAdditionalAttribute(
final EntityType type, final EntityType type,
final Long entityId, final Long entityId,
final String name, final String name,
final String value) { final String value) {
if (value == null) { return Result.tryCatch(() -> {
this.delete(entityId, name); if (value == null) {
return; Result.ofError(new IllegalArgumentException(
} "value cannot be null. Use delete to delete an additional attribute"));
}
final Optional<Long> id = this.additionalAttributeRecordMapperer final Optional<Long> id = this.additionalAttributeRecordMapperer
.selectIdsByExample() .selectIdsByExample()
.where( .where(
AdditionalAttributeRecordDynamicSqlSupport.entityType, AdditionalAttributeRecordDynamicSqlSupport.entityType,
SqlBuilder.isEqualTo(type.name())) SqlBuilder.isEqualTo(type.name()))
.and( .and(
AdditionalAttributeRecordDynamicSqlSupport.entityId, AdditionalAttributeRecordDynamicSqlSupport.entityId,
SqlBuilder.isEqualTo(entityId)) SqlBuilder.isEqualTo(entityId))
.and( .and(
AdditionalAttributeRecordDynamicSqlSupport.name, AdditionalAttributeRecordDynamicSqlSupport.name,
SqlBuilder.isEqualTo(name)) SqlBuilder.isEqualTo(name))
.build() .build()
.execute() .execute()
.stream() .stream()
.findFirst(); .findFirst();
if (id.isPresent()) { if (id.isPresent()) {
final AdditionalAttributeRecord rec = new AdditionalAttributeRecord( final AdditionalAttributeRecord rec = new AdditionalAttributeRecord(
id.get(), id.get(),
type.name(), type.name(),
entityId, entityId,
name, name,
value); value);
this.additionalAttributeRecordMapperer this.additionalAttributeRecordMapperer
.updateByPrimaryKeySelective(rec); .updateByPrimaryKeySelective(rec);
} else {
final AdditionalAttributeRecord rec = new AdditionalAttributeRecord(
null,
type.name(),
entityId,
name,
value);
this.additionalAttributeRecordMapperer
.insert(rec);
}
return this.additionalAttributeRecordMapperer
.selectByPrimaryKey(rec.getId());
} else {
final AdditionalAttributeRecord rec = new AdditionalAttributeRecord(
null,
type.name(),
entityId,
name,
value);
this.additionalAttributeRecordMapperer
.insert(rec);
return this.additionalAttributeRecordMapperer
.selectByPrimaryKey(rec.getId());
}
});
} }
@Override @Override

View file

@ -206,11 +206,17 @@ public class ExamDAOImpl implements ExamDAO {
(exam.supporter != null) (exam.supporter != null)
? StringUtils.join(exam.supporter, Constants.LIST_SEPARATOR_CHAR) ? StringUtils.join(exam.supporter, Constants.LIST_SEPARATOR_CHAR)
: null, : null,
(exam.type != null) ? exam.type.name() : null, (exam.type != null)
? exam.type.name()
: null,
exam.quitPassword, exam.quitPassword,
null, // browser keys exam.browserExamKeys,
(exam.status != null) ? exam.status.name() : null, (exam.status != null)
BooleanUtils.toIntegerObject(exam.lmsSebRestriction), ? exam.status.name()
: null,
(exam.lmsSebRestriction != null)
? BooleanUtils.toIntegerObject(exam.lmsSebRestriction)
: null,
null, // updating null, // updating
null, // lastUpdate null, // lastUpdate
null // active null // active

View file

@ -29,10 +29,9 @@ public interface SebRestrictionService {
* and given additional restriction properties within the AdditionalAttrtibutes linked * and given additional restriction properties within the AdditionalAttrtibutes linked
* to the given Exam. * to the given Exam.
* *
* * @param exam the Exam instance to save the SEB restrictions for
* @param exam * @param sebRestriction SebRestriction data containing generic and LMS specific restriction attributes
* @param sebRestriction * @return Result refer to the given Exam instance or to an error if happened */
* @return */
Result<Exam> saveSebRestrictionToExam(Exam exam, SebRestriction sebRestriction); Result<Exam> saveSebRestrictionToExam(Exam exam, SebRestriction sebRestriction);
/** Used to apply SEB Client restriction within the LMS API for a specified Exam. /** Used to apply SEB Client restriction within the LMS API for a specified Exam.

View file

@ -118,7 +118,10 @@ public class SebRestrictionServiceImpl implements SebRestrictionService {
final Collection<String> browserExamKeys = sebRestriction.getBrowserExamKeys(); final Collection<String> browserExamKeys = sebRestriction.getBrowserExamKeys();
final Exam newExam = new Exam( final Exam newExam = new Exam(
exam.id, exam.id,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
exam.supporter,
exam.status,
exam.lmsSebRestriction,
(browserExamKeys != null && !browserExamKeys.isEmpty()) (browserExamKeys != null && !browserExamKeys.isEmpty())
? StringUtils.join(browserExamKeys, Constants.LIST_SEPARATOR_CHAR) ? StringUtils.join(browserExamKeys, Constants.LIST_SEPARATOR_CHAR)
: StringUtils.EMPTY, : StringUtils.EMPTY,

View file

@ -10,6 +10,7 @@ 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;
@ -36,6 +37,7 @@ 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;
@ -47,10 +49,12 @@ 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;
@ -60,6 +64,7 @@ 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;
@ -79,6 +84,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 LmsAPIService lmsAPIService; private final LmsAPIService lmsAPIService;
private final ExamConfigService sebExamConfigService; private final ExamConfigService sebExamConfigService;
private final ExamSessionService examSessionService; private final ExamSessionService examSessionService;
@ -95,7 +101,8 @@ public class ExamAdministrationController extends EntityController<Exam, Exam> {
final UserDAO userDAO, final UserDAO userDAO,
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,
@ -106,6 +113,7 @@ public class ExamAdministrationController extends EntityController<Exam, Exam> {
this.examDAO = examDAO; this.examDAO = examDAO;
this.userDAO = userDAO; this.userDAO = userDAO;
this.additionalAttributesDAO = additionalAttributesDAO;
this.lmsAPIService = lmsAPIService; this.lmsAPIService = lmsAPIService;
this.sebExamConfigService = sebExamConfigService; this.sebExamConfigService = sebExamConfigService;
this.examSessionService = examSessionService; this.examSessionService = examSessionService;
@ -278,7 +286,6 @@ public class ExamAdministrationController extends EntityController<Exam, Exam> {
@PathVariable(API.PARAM_MODEL_ID) final Long examlId) { @PathVariable(API.PARAM_MODEL_ID) final Long examlId) {
checkModifyPrivilege(institutionId); checkModifyPrivilege(institutionId);
return this.entityDAO.byPK(examlId) return this.entityDAO.byPK(examlId)
.flatMap(this.authorization::checkModify) .flatMap(this.authorization::checkModify)
.flatMap(exam -> this.applySebRestriction(exam, true)) .flatMap(exam -> this.applySebRestriction(exam, true))
@ -328,6 +335,33 @@ public class ExamAdministrationController extends EntityController<Exam, Exam> {
.getOrThrow(); .getOrThrow();
} }
@Override
protected Result<Exam> notifyCreated(final Exam entity) {
return Result.tryCatch(() -> {
final LmsSetup lmsSetup = this.lmsAPIService.getLmsSetup(entity.lmsSetupId)
.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
protected Result<Exam> validForCreate(final Exam entity) { protected Result<Exam> validForCreate(final Exam entity) {
return super.validForCreate(entity) return super.validForCreate(entity)
@ -381,10 +415,6 @@ public class ExamAdministrationController extends EntityController<Exam, Exam> {
"SEB Restriction feature not available for LMS type: " + lmsSetup.lmsType)); "SEB Restriction feature not available for LMS type: " + lmsSetup.lmsType));
} }
if (BooleanUtils.toBoolean(exam.lmsSebRestriction) == restrict) {
return Result.of(exam);
}
if (restrict) { if (restrict) {
if (!this.lmsAPIService if (!this.lmsAPIService
.getLmsSetup(exam.lmsSetupId) .getLmsSetup(exam.lmsSetupId)