add warning if course imported twice and seb restriction readonly view
This commit is contained in:
parent
b6466d8f1d
commit
be7a7cef77
14 changed files with 174 additions and 42 deletions
|
@ -118,6 +118,7 @@ public final class API {
|
||||||
public static final String EXAM_ADMINISTRATION_CONSISTENCY_CHECK_PATH_SEGMENT = "/check-consistency";
|
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_SEB_RESTRICTION_PATH_SEGMENT = "/seb-restriction";
|
||||||
public static final String EXAM_ADMINISTRATION_CHECK_RESTRICTION_PATH_SEGMENT = "/check-seb-restriction";
|
public static final String EXAM_ADMINISTRATION_CHECK_RESTRICTION_PATH_SEGMENT = "/check-seb-restriction";
|
||||||
|
public static final String EXAM_ADMINISTRATION_CHECK_IMPORTED_PATH_SEGMENT = "/check-imported";
|
||||||
|
|
||||||
public static final String EXAM_INDICATOR_ENDPOINT = "/indicator";
|
public static final String EXAM_INDICATOR_ENDPOINT = "/indicator";
|
||||||
|
|
||||||
|
|
|
@ -400,6 +400,7 @@ public class ExamForm implements TemplateComposer {
|
||||||
.withURIVariable(API.PARAM_MODEL_ID, String.valueOf(exam.lmsSetupId))
|
.withURIVariable(API.PARAM_MODEL_ID, String.valueOf(exam.lmsSetupId))
|
||||||
.call()
|
.call()
|
||||||
.getOrThrow().lmsType.name())
|
.getOrThrow().lmsType.name())
|
||||||
|
.withAttribute(PageContext.AttributeKeys.FORCE_READ_ONLY, String.valueOf(!modifyGrant))
|
||||||
.noEventPropagation()
|
.noEventPropagation()
|
||||||
.publishIf(() -> sebRestrictionAvailable && readonly)
|
.publishIf(() -> sebRestrictionAvailable && readonly)
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.eclipse.swt.widgets.Composite;
|
import org.eclipse.swt.widgets.Composite;
|
||||||
|
|
||||||
|
@ -104,6 +105,12 @@ public class ExamSebRestrictionSettings {
|
||||||
final PageContext pageContext,
|
final PageContext pageContext,
|
||||||
final FormHandle<?> formHandle) {
|
final FormHandle<?> formHandle) {
|
||||||
|
|
||||||
|
final boolean isReadonly = BooleanUtils.toBoolean(
|
||||||
|
pageContext.getAttribute(PageContext.AttributeKeys.FORCE_READ_ONLY));
|
||||||
|
if (isReadonly) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
final EntityKey entityKey = pageContext.getEntityKey();
|
final EntityKey entityKey = pageContext.getEntityKey();
|
||||||
final LmsType lmsType = getLmsType(pageContext);
|
final LmsType lmsType = getLmsType(pageContext);
|
||||||
SebRestriction bodyValue = null;
|
SebRestriction bodyValue = null;
|
||||||
|
@ -170,6 +177,8 @@ public class ExamSebRestrictionSettings {
|
||||||
final ResourceService resourceService = this.pageService.getResourceService();
|
final ResourceService resourceService = this.pageService.getResourceService();
|
||||||
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 boolean isReadonly = BooleanUtils.toBoolean(
|
||||||
|
this.pageContext.getAttribute(PageContext.AttributeKeys.FORCE_READ_ONLY));
|
||||||
|
|
||||||
final Composite content = this.pageService
|
final Composite content = this.pageService
|
||||||
.getWidgetFactory()
|
.getWidgetFactory()
|
||||||
|
@ -189,12 +198,12 @@ public class ExamSebRestrictionSettings {
|
||||||
formContext)
|
formContext)
|
||||||
.withDefaultSpanInput(6)
|
.withDefaultSpanInput(6)
|
||||||
.withEmptyCellSeparation(false)
|
.withEmptyCellSeparation(false)
|
||||||
.readonly(false)
|
.readonly(isReadonly)
|
||||||
|
|
||||||
.addField(FormBuilder.text(
|
.addField(FormBuilder.text(
|
||||||
"Info",
|
"Info",
|
||||||
SEB_RESTRICTION_FORM_INFO,
|
SEB_RESTRICTION_FORM_INFO,
|
||||||
pageService.getI18nSupport().getText(SEB_RESTRICTION_FORM_INFO_TEXT))
|
this.pageService.getI18nSupport().getText(SEB_RESTRICTION_FORM_INFO_TEXT))
|
||||||
.asArea(50)
|
.asArea(50)
|
||||||
.asHTML()
|
.asHTML()
|
||||||
.readonly(true))
|
.readonly(true))
|
||||||
|
@ -254,6 +263,7 @@ public class ExamSebRestrictionSettings {
|
||||||
|
|
||||||
return () -> formHandle;
|
return () -> formHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static LmsType getLmsType(final PageContext pageContext) {
|
private static LmsType getLmsType(final PageContext pageContext) {
|
||||||
|
|
|
@ -13,7 +13,6 @@ import java.util.Collection;
|
||||||
import java.util.function.BooleanSupplier;
|
import java.util.function.BooleanSupplier;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
|
||||||
import org.eclipse.swt.widgets.Composite;
|
import org.eclipse.swt.widgets.Composite;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.joda.time.DateTimeZone;
|
import org.joda.time.DateTimeZone;
|
||||||
|
@ -21,6 +20,8 @@ import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
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.Entity;
|
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||||
|
@ -43,6 +44,7 @@ import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.impl.ModalInputDialog;
|
import ch.ethz.seb.sebserver.gui.service.page.impl.ModalInputDialog;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
|
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
|
||||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||||
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.CheckExamImported;
|
||||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.quiz.GetQuizPage;
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.quiz.GetQuizPage;
|
||||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
|
||||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck;
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck;
|
||||||
|
@ -55,7 +57,7 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||||
@Lazy
|
@Lazy
|
||||||
@Component
|
@Component
|
||||||
@GuiProfile
|
@GuiProfile
|
||||||
public class QuizDiscoveryList implements TemplateComposer {
|
public class QuizLookupList implements TemplateComposer {
|
||||||
|
|
||||||
// localized text keys
|
// localized text keys
|
||||||
|
|
||||||
|
@ -93,6 +95,8 @@ public class QuizDiscoveryList implements TemplateComposer {
|
||||||
new LocTextKey("sebserver.quizdiscovery.quiz.details.endtime");
|
new LocTextKey("sebserver.quizdiscovery.quiz.details.endtime");
|
||||||
private final static LocTextKey NO_IMPORT_OF_OUT_DATED_QUIZ =
|
private final static LocTextKey NO_IMPORT_OF_OUT_DATED_QUIZ =
|
||||||
new LocTextKey("sebserver.quizdiscovery.quiz.import.out.dated");
|
new LocTextKey("sebserver.quizdiscovery.quiz.import.out.dated");
|
||||||
|
private final static LocTextKey TEXT_KEY_CONFIRM_EXISTING =
|
||||||
|
new LocTextKey("sebserver.quizdiscovery.quiz.import.existing.confirm");
|
||||||
|
|
||||||
private final static String TEXT_KEY_ADDITIONAL_ATTR_PREFIX =
|
private final static String TEXT_KEY_ADDITIONAL_ATTR_PREFIX =
|
||||||
"sebserver.quizdiscovery.quiz.details.additional.";
|
"sebserver.quizdiscovery.quiz.details.additional.";
|
||||||
|
@ -109,7 +113,7 @@ public class QuizDiscoveryList implements TemplateComposer {
|
||||||
private final PageService pageService;
|
private final PageService pageService;
|
||||||
private final int pageSize;
|
private final int pageSize;
|
||||||
|
|
||||||
protected QuizDiscoveryList(
|
protected QuizLookupList(
|
||||||
final PageService pageService,
|
final PageService pageService,
|
||||||
final ResourceService resourceService,
|
final ResourceService resourceService,
|
||||||
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
|
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
|
||||||
|
@ -232,6 +236,7 @@ public class QuizDiscoveryList implements TemplateComposer {
|
||||||
.publishIf(table::hasAnyContent, false)
|
.publishIf(table::hasAnyContent, false)
|
||||||
|
|
||||||
.newAction(ActionDefinition.QUIZ_DISCOVERY_EXAM_IMPORT)
|
.newAction(ActionDefinition.QUIZ_DISCOVERY_EXAM_IMPORT)
|
||||||
|
.withConfirm(importQuizConfirm(table, restService))
|
||||||
.withSelect(
|
.withSelect(
|
||||||
table::getSelection,
|
table::getSelection,
|
||||||
action -> this.importQuizData(action, table),
|
action -> this.importQuizData(action, table),
|
||||||
|
@ -244,7 +249,31 @@ public class QuizDiscoveryList implements TemplateComposer {
|
||||||
.apply(String.valueOf(quizData.lmsSetupId));
|
.apply(String.valueOf(quizData.lmsSetupId));
|
||||||
}
|
}
|
||||||
|
|
||||||
private PageAction importQuizData(final PageAction action, final EntityTable<QuizData> table) {
|
private Function<PageAction, LocTextKey> importQuizConfirm(
|
||||||
|
final EntityTable<QuizData> table,
|
||||||
|
final RestService restService) {
|
||||||
|
|
||||||
|
return action -> {
|
||||||
|
action.getSingleSelection();
|
||||||
|
final QuizData selectedROWData = table.getSingleSelectedROWData();
|
||||||
|
|
||||||
|
final Collection<EntityKey> existingImports = restService.getBuilder(CheckExamImported.class)
|
||||||
|
.withURIVariable(API.PARAM_MODEL_ID, selectedROWData.id)
|
||||||
|
.call()
|
||||||
|
.getOrThrow();
|
||||||
|
|
||||||
|
if (existingImports != null && !existingImports.isEmpty()) {
|
||||||
|
return TEXT_KEY_CONFIRM_EXISTING;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private PageAction importQuizData(
|
||||||
|
final PageAction action,
|
||||||
|
final EntityTable<QuizData> table) {
|
||||||
|
|
||||||
action.getSingleSelection();
|
action.getSingleSelection();
|
||||||
final QuizData selectedROWData = table.getSingleSelectedROWData();
|
final QuizData selectedROWData = table.getSingleSelectedROWData();
|
||||||
|
|
|
@ -21,7 +21,7 @@ import ch.ethz.seb.sebserver.gui.content.LmsSetupList;
|
||||||
import ch.ethz.seb.sebserver.gui.content.MonitoringClientConnection;
|
import ch.ethz.seb.sebserver.gui.content.MonitoringClientConnection;
|
||||||
import ch.ethz.seb.sebserver.gui.content.MonitoringRunningExam;
|
import ch.ethz.seb.sebserver.gui.content.MonitoringRunningExam;
|
||||||
import ch.ethz.seb.sebserver.gui.content.MonitoringRunningExamList;
|
import ch.ethz.seb.sebserver.gui.content.MonitoringRunningExamList;
|
||||||
import ch.ethz.seb.sebserver.gui.content.QuizDiscoveryList;
|
import ch.ethz.seb.sebserver.gui.content.QuizLookupList;
|
||||||
import ch.ethz.seb.sebserver.gui.content.SebClientConfigForm;
|
import ch.ethz.seb.sebserver.gui.content.SebClientConfigForm;
|
||||||
import ch.ethz.seb.sebserver.gui.content.SebClientConfigList;
|
import ch.ethz.seb.sebserver.gui.content.SebClientConfigList;
|
||||||
import ch.ethz.seb.sebserver.gui.content.SebClientLogs;
|
import ch.ethz.seb.sebserver.gui.content.SebClientLogs;
|
||||||
|
@ -52,7 +52,7 @@ public enum PageStateDefinitionImpl implements PageStateDefinition {
|
||||||
LMS_SETUP_VIEW(Type.FORM_VIEW, LmsSetupForm.class, ActivityDefinition.LMS_SETUP),
|
LMS_SETUP_VIEW(Type.FORM_VIEW, LmsSetupForm.class, ActivityDefinition.LMS_SETUP),
|
||||||
LMS_SETUP_EDIT(Type.FORM_EDIT, LmsSetupForm.class, ActivityDefinition.LMS_SETUP),
|
LMS_SETUP_EDIT(Type.FORM_EDIT, LmsSetupForm.class, ActivityDefinition.LMS_SETUP),
|
||||||
|
|
||||||
QUIZ_LIST(Type.LIST_VIEW, QuizDiscoveryList.class, ActivityDefinition.QUIZ_DISCOVERY),
|
QUIZ_LIST(Type.LIST_VIEW, QuizLookupList.class, ActivityDefinition.QUIZ_DISCOVERY),
|
||||||
|
|
||||||
EXAM_LIST(Type.LIST_VIEW, ExamList.class, ActivityDefinition.EXAM),
|
EXAM_LIST(Type.LIST_VIEW, ExamList.class, ActivityDefinition.EXAM),
|
||||||
EXAM_VIEW(Type.FORM_VIEW, ExamForm.class, ActivityDefinition.EXAM),
|
EXAM_VIEW(Type.FORM_VIEW, ExamForm.class, ActivityDefinition.EXAM),
|
||||||
|
|
|
@ -14,7 +14,6 @@ import java.util.List;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.eclipse.swt.SWT;
|
import org.eclipse.swt.SWT;
|
||||||
import org.eclipse.swt.layout.GridData;
|
import org.eclipse.swt.layout.GridData;
|
||||||
|
@ -28,6 +27,7 @@ import ch.ethz.seb.sebserver.gbl.Constants;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
||||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||||
import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
|
import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
|
||||||
|
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||||
import ch.ethz.seb.sebserver.gui.widget.Selection;
|
import ch.ethz.seb.sebserver.gui.widget.Selection;
|
||||||
import ch.ethz.seb.sebserver.gui.widget.Selection.Type;
|
import ch.ethz.seb.sebserver.gui.widget.Selection.Type;
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ public final class SelectionFieldBuilder extends FieldBuilder<String> {
|
||||||
this.type,
|
this.type,
|
||||||
fieldGrid,
|
fieldGrid,
|
||||||
this.itemsSupplier,
|
this.itemsSupplier,
|
||||||
(builder.pageService.getFormTooltipMode() == PageService.FormTooltipMode.INPUT) ? tooltip : null,
|
(builder.pageService.getFormTooltipMode() == PageService.FormTooltipMode.INPUT) ? this.tooltip : null,
|
||||||
null,
|
null,
|
||||||
actionKey);
|
actionKey);
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ public final class SelectionFieldBuilder extends FieldBuilder<String> {
|
||||||
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, true);
|
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, true);
|
||||||
|
|
||||||
label.setLayoutData(gridData);
|
label.setLayoutData(gridData);
|
||||||
label.setText(this.value);
|
label.setText((this.value != null) ? this.value : Constants.EMPTY_NOTE);
|
||||||
} else {
|
} else {
|
||||||
final Collection<String> keys = Arrays.asList(StringUtils.split(this.value, Constants.LIST_SEPARATOR));
|
final Collection<String> keys = Arrays.asList(StringUtils.split(this.value, Constants.LIST_SEPARATOR));
|
||||||
this.itemsSupplier.get()
|
this.itemsSupplier.get()
|
||||||
|
|
|
@ -32,6 +32,7 @@ public interface PageContext {
|
||||||
String PAGE_TEMPLATE_COMPOSER_NAME = "ATTR_PAGE_TEMPLATE_COMPOSER_NAME";
|
String PAGE_TEMPLATE_COMPOSER_NAME = "ATTR_PAGE_TEMPLATE_COMPOSER_NAME";
|
||||||
|
|
||||||
String READ_ONLY = "READ_ONLY";
|
String READ_ONLY = "READ_ONLY";
|
||||||
|
String FORCE_READ_ONLY = "FORCE_READ_ONLY";
|
||||||
String READ_ONLY_FROM = "READ_ONLY_FROM";
|
String READ_ONLY_FROM = "READ_ONLY_FROM";
|
||||||
|
|
||||||
String ENTITY_ID = "ENTITY_ID";
|
String ENTITY_ID = "ENTITY_ID";
|
||||||
|
|
|
@ -129,8 +129,9 @@ public interface PageService {
|
||||||
*
|
*
|
||||||
* @param table the entity table
|
* @param table the entity table
|
||||||
* @param noSelectionText LocTextKey for missing selection message
|
* @param noSelectionText LocTextKey for missing selection message
|
||||||
* @param testBeforeActivation a function to test before activation. This function shall throw an error if test fails.
|
* @param testBeforeActivation a function to test before activation. This function shall throw an error if test
|
||||||
* My be null if no specific test is needed before activation
|
* fails.
|
||||||
|
* My be null if no specific test is needed before activation
|
||||||
* @return page action execution function for switching the activity */
|
* @return page action execution function for switching the activity */
|
||||||
<T extends Entity & Activatable> Function<PageAction, PageAction> activationToggleActionFunction(
|
<T extends Entity & Activatable> Function<PageAction, PageAction> activationToggleActionFunction(
|
||||||
EntityTable<T> table,
|
EntityTable<T> table,
|
||||||
|
@ -144,8 +145,8 @@ public interface PageService {
|
||||||
* @param noSelectionText LocTextKey for missing selection message
|
* @param noSelectionText LocTextKey for missing selection message
|
||||||
* @return page action execution function for switching the activity */
|
* @return page action execution function for switching the activity */
|
||||||
default <T extends Entity & Activatable> Function<PageAction, PageAction> activationToggleActionFunction(
|
default <T extends Entity & Activatable> Function<PageAction, PageAction> activationToggleActionFunction(
|
||||||
EntityTable<T> table,
|
final EntityTable<T> table,
|
||||||
LocTextKey noSelectionText) {
|
final LocTextKey noSelectionText) {
|
||||||
return this.activationToggleActionFunction(table, noSelectionText, null);
|
return this.activationToggleActionFunction(table, noSelectionText, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -399,7 +400,7 @@ public interface PageService {
|
||||||
|
|
||||||
private PageContext pageContext;
|
private PageContext pageContext;
|
||||||
private ActionDefinition definition;
|
private ActionDefinition definition;
|
||||||
private Supplier<LocTextKey> confirm;
|
private Function<PageAction, LocTextKey> confirm;
|
||||||
private LocTextKey successMessage;
|
private LocTextKey successMessage;
|
||||||
private Supplier<Set<EntityKey>> selectionSupplier;
|
private Supplier<Set<EntityKey>> selectionSupplier;
|
||||||
private LocTextKey noSelectionMessage;
|
private LocTextKey noSelectionMessage;
|
||||||
|
@ -508,6 +509,11 @@ public interface PageService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public PageActionBuilder withConfirm(final Supplier<LocTextKey> confirm) {
|
public PageActionBuilder withConfirm(final Supplier<LocTextKey> confirm) {
|
||||||
|
this.confirm = action -> confirm.get();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PageActionBuilder withConfirm(final Function<PageAction, LocTextKey> confirm) {
|
||||||
this.confirm = confirm;
|
this.confirm = confirm;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ public final class PageAction {
|
||||||
private static final Logger log = LoggerFactory.getLogger(PageAction.class);
|
private static final Logger log = LoggerFactory.getLogger(PageAction.class);
|
||||||
|
|
||||||
public final ActionDefinition definition;
|
public final ActionDefinition definition;
|
||||||
private final Supplier<LocTextKey> confirm;
|
private final Function<PageAction, LocTextKey> confirm;
|
||||||
private final Supplier<Set<EntityKey>> selectionSupplier;
|
private final Supplier<Set<EntityKey>> selectionSupplier;
|
||||||
private final LocTextKey noSelectionMessage;
|
private final LocTextKey noSelectionMessage;
|
||||||
private PageContext pageContext;
|
private PageContext pageContext;
|
||||||
|
@ -48,7 +48,7 @@ public final class PageAction {
|
||||||
|
|
||||||
public PageAction(
|
public PageAction(
|
||||||
final ActionDefinition definition,
|
final ActionDefinition definition,
|
||||||
final Supplier<LocTextKey> confirm,
|
final Function<PageAction, LocTextKey> confirm,
|
||||||
final LocTextKey successMessage,
|
final LocTextKey successMessage,
|
||||||
final Supplier<Set<EntityKey>> selectionSupplier,
|
final Supplier<Set<EntityKey>> selectionSupplier,
|
||||||
final LocTextKey noSelectionMessage,
|
final LocTextKey noSelectionMessage,
|
||||||
|
@ -154,7 +154,7 @@ public final class PageAction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final LocTextKey confirmMessage = this.confirm.get();
|
final LocTextKey confirmMessage = this.confirm.apply(this);
|
||||||
if (confirmMessage != null) {
|
if (confirmMessage != null) {
|
||||||
this.pageContext.applyConfirmDialog(confirmMessage,
|
this.pageContext.applyConfirmDialog(confirmMessage,
|
||||||
confirm -> callback.accept((confirm)
|
confirm -> callback.accept((confirm)
|
||||||
|
@ -198,9 +198,6 @@ public final class PageAction {
|
||||||
PageAction.this.getName(),
|
PageAction.this.getName(),
|
||||||
e.getMessage(),
|
e.getMessage(),
|
||||||
Utils.getErrorCauseMessage(e));
|
Utils.getErrorCauseMessage(e));
|
||||||
PageAction.this.pageContext.notifyError(
|
|
||||||
PageContext.UNEXPECTED_ERROR_KEY,
|
|
||||||
e);
|
|
||||||
return Result.ofError(e);
|
return Result.ofError(e);
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
log.error("Failed to execute action: {} | error: {} | cause: {}",
|
log.error("Failed to execute action: {} | error: {} | cause: {}",
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* 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 java.util.Collection;
|
||||||
|
|
||||||
|
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.model.EntityKey;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||||
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
@Component
|
||||||
|
@GuiProfile
|
||||||
|
public class CheckExamImported extends RestCall<Collection<EntityKey>> {
|
||||||
|
|
||||||
|
public CheckExamImported() {
|
||||||
|
super(new TypeKey<>(
|
||||||
|
CallType.UNDEFINED,
|
||||||
|
EntityType.EXAM,
|
||||||
|
new TypeReference<Collection<EntityKey>>() {
|
||||||
|
}),
|
||||||
|
HttpMethod.GET,
|
||||||
|
MediaType.APPLICATION_FORM_URLENCODED,
|
||||||
|
API.EXAM_ADMINISTRATION_ENDPOINT
|
||||||
|
+ API.MODEL_ID_VAR_PATH_SEGMENT
|
||||||
|
+ API.EXAM_ADMINISTRATION_CHECK_IMPORTED_PATH_SEGMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -28,6 +28,8 @@ public interface ExamDAO extends ActivatableEntityDAO<Exam, Exam>, BulkActionSup
|
||||||
* happened */
|
* happened */
|
||||||
Result<Collection<Long>> allIdsOfInstitution(Long institutionId);
|
Result<Collection<Long>> allIdsOfInstitution(Long institutionId);
|
||||||
|
|
||||||
|
Result<Collection<Long>> allByQuizId(String quizId);
|
||||||
|
|
||||||
/** Updates the exam status for specified exam
|
/** Updates the exam status for specified exam
|
||||||
*
|
*
|
||||||
* @param examId The exam identifier
|
* @param examId The exam identifier
|
||||||
|
|
|
@ -111,6 +111,24 @@ public class ExamDAOImpl implements ExamDAO {
|
||||||
.flatMap(this::toDomainModel);
|
.flatMap(this::toDomainModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<Collection<Long>> allByQuizId(final String quizId) {
|
||||||
|
return Result.tryCatch(() -> {
|
||||||
|
return this.examRecordMapper.selectByExample()
|
||||||
|
.where(
|
||||||
|
ExamRecordDynamicSqlSupport.externalId,
|
||||||
|
isEqualToWhenPresent(quizId))
|
||||||
|
.and(
|
||||||
|
ExamRecordDynamicSqlSupport.active,
|
||||||
|
isEqualToWhenPresent(BooleanUtils.toIntegerObject(true)))
|
||||||
|
.build()
|
||||||
|
.execute()
|
||||||
|
.stream()
|
||||||
|
.map(rec -> rec.getId())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public Result<Collection<Exam>> allMatching(final FilterMap filterMap, final Predicate<Exam> predicate) {
|
public Result<Collection<Exam>> allMatching(final FilterMap filterMap, final Predicate<Exam> predicate) {
|
||||||
|
@ -258,24 +276,24 @@ public class ExamDAOImpl implements ExamDAO {
|
||||||
// used to save instead of create a new one
|
// used to save instead of create a new one
|
||||||
if (records != null && records.size() > 0) {
|
if (records != null && records.size() > 0) {
|
||||||
final ExamRecord examRecord = records.get(0);
|
final ExamRecord examRecord = records.get(0);
|
||||||
// if another institution tries to import an exam that already exists
|
// if the same institution tries to import an exam that already exists
|
||||||
if (!exam.institutionId.equals(examRecord.getInstitutionId())) {
|
// open the existing. otherwise create new one if requested
|
||||||
throw new IllegalStateException("Exam cannot be imported twice from different institutions");
|
if (exam.institutionId.equals(examRecord.getInstitutionId())) {
|
||||||
}
|
final ExamRecord newRecord = new ExamRecord(
|
||||||
final ExamRecord newRecord = new ExamRecord(
|
examRecord.getId(),
|
||||||
examRecord.getId(),
|
null, null, null, null, null,
|
||||||
null, null, null, null, null,
|
(exam.type != null) ? exam.type.name() : ExamType.UNDEFINED.name(),
|
||||||
(exam.type != null) ? exam.type.name() : ExamType.UNDEFINED.name(),
|
null, // quitPassword
|
||||||
null, // quitPassword
|
null, // browser keys
|
||||||
null, // browser keys
|
null, // status
|
||||||
null, // status
|
null, // lmsSebRestriction (deprecated)
|
||||||
null, // lmsSebRestriction (deprecated)
|
null, // updating
|
||||||
null, // updating
|
null, // lastUpdate
|
||||||
null, // lastUpdate
|
BooleanUtils.toIntegerObject(exam.active));
|
||||||
BooleanUtils.toIntegerObject(exam.active));
|
|
||||||
|
|
||||||
this.examRecordMapper.updateByPrimaryKeySelective(newRecord);
|
this.examRecordMapper.updateByPrimaryKeySelective(newRecord);
|
||||||
return this.examRecordMapper.selectByPrimaryKey(examRecord.getId());
|
return this.examRecordMapper.selectByPrimaryKey(examRecord.getId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final ExamRecord examRecord = new ExamRecord(
|
final ExamRecord examRecord = new ExamRecord(
|
||||||
|
|
|
@ -45,6 +45,7 @@ import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType;
|
import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.Domain.EXAM;
|
import ch.ethz.seb.sebserver.gbl.model.Domain.EXAM;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||||
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;
|
||||||
|
@ -208,6 +209,27 @@ public class ExamAdministrationController extends EntityController<Exam, Exam> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequestMapping(
|
||||||
|
path = API.MODEL_ID_VAR_PATH_SEGMENT
|
||||||
|
+ API.EXAM_ADMINISTRATION_CHECK_IMPORTED_PATH_SEGMENT,
|
||||||
|
method = RequestMethod.GET,
|
||||||
|
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||||
|
public Collection<EntityKey> checkImported(
|
||||||
|
@PathVariable final String modelId,
|
||||||
|
@RequestParam(
|
||||||
|
name = API.PARAM_INSTITUTION_ID,
|
||||||
|
required = true,
|
||||||
|
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId) {
|
||||||
|
|
||||||
|
checkReadPrivilege(institutionId);
|
||||||
|
return this.examDAO.allByQuizId(modelId)
|
||||||
|
.map(ids -> ids
|
||||||
|
.stream()
|
||||||
|
.map(id -> new EntityKey(id, EntityType.EXAM))
|
||||||
|
.collect(Collectors.toList()))
|
||||||
|
.getOrThrow();
|
||||||
|
}
|
||||||
|
|
||||||
@RequestMapping(
|
@RequestMapping(
|
||||||
path = API.MODEL_ID_VAR_PATH_SEGMENT
|
path = API.MODEL_ID_VAR_PATH_SEGMENT
|
||||||
+ API.EXAM_ADMINISTRATION_CONSISTENCY_CHECK_PATH_SEGMENT,
|
+ API.EXAM_ADMINISTRATION_CONSISTENCY_CHECK_PATH_SEGMENT,
|
||||||
|
@ -226,6 +248,9 @@ public class ExamAdministrationController extends EntityController<Exam, Exam> {
|
||||||
.getOrThrow();
|
.getOrThrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ****************************************************************************
|
||||||
|
// **** SEB Restriction
|
||||||
|
|
||||||
@RequestMapping(
|
@RequestMapping(
|
||||||
path = API.MODEL_ID_VAR_PATH_SEGMENT
|
path = API.MODEL_ID_VAR_PATH_SEGMENT
|
||||||
+ API.EXAM_ADMINISTRATION_CHECK_RESTRICTION_PATH_SEGMENT,
|
+ API.EXAM_ADMINISTRATION_CHECK_RESTRICTION_PATH_SEGMENT,
|
||||||
|
@ -244,9 +269,6 @@ public class ExamAdministrationController extends EntityController<Exam, Exam> {
|
||||||
.getOrThrow();
|
.getOrThrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ****************************************************************************
|
|
||||||
// **** SEB Restriction
|
|
||||||
|
|
||||||
@RequestMapping(
|
@RequestMapping(
|
||||||
path = API.MODEL_ID_VAR_PATH_SEGMENT
|
path = API.MODEL_ID_VAR_PATH_SEGMENT
|
||||||
+ API.EXAM_ADMINISTRATION_SEB_RESTRICTION_PATH_SEGMENT,
|
+ API.EXAM_ADMINISTRATION_SEB_RESTRICTION_PATH_SEGMENT,
|
||||||
|
|
|
@ -350,6 +350,7 @@ sebserver.quizdiscovery.action.list=LMS Exam Lookup
|
||||||
sebserver.quizdiscovery.action.import=Import as Exam
|
sebserver.quizdiscovery.action.import=Import as Exam
|
||||||
sebserver.quizdiscovery.quiz.import.out.dated=The Selected LMS exam is is already finished and can't be imported
|
sebserver.quizdiscovery.quiz.import.out.dated=The Selected LMS exam is is already finished and can't be imported
|
||||||
sebserver.quizdiscovery.action.details=Show LMS Exam Details
|
sebserver.quizdiscovery.action.details=Show LMS Exam Details
|
||||||
|
sebserver.quizdiscovery.quiz.import.existing.confirm=This course was already imported and import it twice may lead to<br/> unexpected behavior within automated SEB restriction on LMS.<br/><br/> Do you want to import this course as exam anyways?
|
||||||
|
|
||||||
sebserver.quizdiscovery.quiz.details.title=LMS Exam Details
|
sebserver.quizdiscovery.quiz.details.title=LMS Exam Details
|
||||||
sebserver.quizdiscovery.quiz.details.institution=Institution
|
sebserver.quizdiscovery.quiz.details.institution=Institution
|
||||||
|
|
Loading…
Add table
Reference in a new issue