fixed exception handling, bugfix and code cleanup

This commit is contained in:
anhefti 2019-11-26 15:30:41 +01:00
parent 4811d88940
commit e3b0d2251e
54 changed files with 625 additions and 338 deletions

View file

@ -197,6 +197,26 @@ public class APIMessage implements Serializable {
return ErrorMessage.FIELD_VALIDATION.of(fieldName, args);
}
public static String toHTML(final String errorMessage, final List<APIMessage> messages) {
final StringBuilder builder = new StringBuilder();
builder.append("<b>Failure: </b>").append(errorMessage).append("<br/><br/>");
builder.append("<b>Detail Messages:</b><br/><br/>");
messages.stream()
.forEach(message -> {
builder
.append("&nbsp;&nbsp;code&nbsp;:&nbsp;")
.append(message.messageCode)
.append("<br/>")
.append("&nbsp;&nbsp;system message&nbsp;:&nbsp;")
.append(HtmlUtils.htmlEscape(message.systemMessage))
.append("<br/>")
.append("&nbsp;&nbsp;details&nbsp;:&nbsp;")
.append(HtmlUtils.htmlEscape(StringUtils.abbreviate(message.details, 100)))
.append("<br/><br/>");
});
return builder.toString();
}
public static String toHTML(final Collection<APIMessage> messages) {
final StringBuilder builder = new StringBuilder();
builder.append("<b>Messages:</b><br/><br/>");

View file

@ -407,4 +407,11 @@ public final class Utils {
org.springframework.http.MediaType.APPLICATION_JSON_UTF8_VALUE);
return headers;
}
public static final String getErrorCauseMessage(final Exception e) {
if (e == null || e.getCause() == null) {
return Constants.EMPTY_NOTE;
}
return e.getCause().getClass().getName() + " : " + e.getCause().getMessage();
}
}

View file

@ -19,6 +19,7 @@ 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.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration;
@ -96,131 +97,138 @@ public class ConfigTemplateAttributeForm implements TemplateComposer {
final EntityKey templateKey = pageContext.getParentEntityKey();
final Long templateId = Long.valueOf(templateKey.modelId);
final ConfigurationNode template = this.restService
.getBuilder(GetExamConfigNode.class)
.withURIVariable(API.PARAM_MODEL_ID, templateKey.modelId)
.call()
.get(pageContext::notifyError);
try {
final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(template);
final boolean modifyGrant = entityGrant.m();
final ConfigurationNode template = this.restService
.getBuilder(GetExamConfigNode.class)
.withURIVariable(API.PARAM_MODEL_ID, templateKey.modelId)
.call()
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_NODE, error))
.getOrThrow();
// the attribute
final TemplateAttribute attribute = this.restService.getBuilder(GetTemplateAttribute.class)
.withURIVariable(API.PARAM_PARENT_MODEL_ID, templateKey.modelId)
.withURIVariable(API.PARAM_MODEL_ID, attributeKey.modelId)
.call()
.getOrThrow();
final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(template);
final boolean modifyGrant = entityGrant.m();
// the follow-up configuration
final Configuration configuration = this.restService.getBuilder(GetConfigurations.class)
.withQueryParam(Configuration.FILTER_ATTR_CONFIGURATION_NODE_ID, templateKey.getModelId())
.withQueryParam(Configuration.FILTER_ATTR_FOLLOWUP, Constants.TRUE_STRING)
.call()
.map(Utils::toSingleton)
.onError(pageContext::notifyError)
.getOrThrow();
// the attribute
final TemplateAttribute attribute = this.restService.getBuilder(GetTemplateAttribute.class)
.withURIVariable(API.PARAM_PARENT_MODEL_ID, templateKey.modelId)
.withURIVariable(API.PARAM_MODEL_ID, attributeKey.modelId)
.call()
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_NODE, error))
.getOrThrow();
// the default page layout with title
final Composite content = widgetFactory.defaultPageLayout(
pageContext.getParent(),
FORM_TITLE);
// the follow-up configuration
final Configuration configuration = this.restService.getBuilder(GetConfigurations.class)
.withQueryParam(Configuration.FILTER_ATTR_CONFIGURATION_NODE_ID, templateKey.getModelId())
.withQueryParam(Configuration.FILTER_ATTR_FOLLOWUP, Constants.TRUE_STRING)
.call()
.map(Utils::toSingleton)
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION, error))
.getOrThrow();
final PageContext formContext = pageContext.copyOf(content);
// the default page layout with title
final Composite content = widgetFactory.defaultPageLayout(
pageContext.getParent(),
FORM_TITLE);
final boolean hasView = attribute.getOrientation() != null;
final PageContext formContext = pageContext.copyOf(content);
this.pageService.formBuilder(
formContext, 4)
.readonly(true) // TODO change this for next version
.addField(FormBuilder.text(
Domain.CONFIGURATION_ATTRIBUTE.ATTR_NAME,
FORM_NAME_TEXT_KEY,
attribute::getName))
.addField(FormBuilder.text(
Domain.CONFIGURATION_ATTRIBUTE.ATTR_TYPE,
FORM_TYPE_TEXT_KEY,
() -> this.resourceService.getAttributeTypeName(attribute)))
.addFieldIf(
() -> hasView,
() -> FormBuilder.singleSelection(
Domain.ORIENTATION.ATTR_VIEW_ID,
FORM_VIEW_TEXT_KEY,
attribute.getViewModelId(),
() -> this.resourceService.getViewResources(templateKey.modelId)))
.addFieldIf(
() -> hasView,
() -> FormBuilder.text(
Domain.ORIENTATION.ATTR_GROUP_ID,
FORM_GROUP_TEXT_KEY,
attribute.getGroupId()))
.build();
final boolean hasView = attribute.getOrientation() != null;
widgetFactory.labelLocalized(
content,
CustomVariant.TEXT_H2,
FORM_VALUE_TEXT_KEY);
this.pageService.formBuilder(
formContext, 4)
.readonly(true) // TODO change this for next version
.addField(FormBuilder.text(
Domain.CONFIGURATION_ATTRIBUTE.ATTR_NAME,
FORM_NAME_TEXT_KEY,
attribute::getName))
.addField(FormBuilder.text(
Domain.CONFIGURATION_ATTRIBUTE.ATTR_TYPE,
FORM_TYPE_TEXT_KEY,
() -> this.resourceService.getAttributeTypeName(attribute)))
.addFieldIf(
() -> hasView,
() -> FormBuilder.singleSelection(
Domain.ORIENTATION.ATTR_VIEW_ID,
FORM_VIEW_TEXT_KEY,
attribute.getViewModelId(),
() -> this.resourceService.getViewResources(templateKey.modelId)))
.addFieldIf(
() -> hasView,
() -> FormBuilder.text(
Domain.ORIENTATION.ATTR_GROUP_ID,
FORM_GROUP_TEXT_KEY,
attribute.getGroupId()))
.build();
final Composite grid = new Composite(content, SWT.NONE);
grid.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
grid.setLayout(new GridLayout(6, true));
widgetFactory.labelLocalized(
content,
CustomVariant.TEXT_H2,
FORM_VALUE_TEXT_KEY);
final PageContext valueContext = formContext.copyOf(grid);
final Composite grid = new Composite(content, SWT.NONE);
grid.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
grid.setLayout(new GridLayout(6, true));
final Orientation defaultOrientation = getDefaultOrientation(attribute);
final AttributeMapping attributeMapping = this.examConfigurationService
.getAttributes(attribute, defaultOrientation)
.getOrThrow();
final ViewContext viewContext = this.examConfigurationService.createViewContext(
valueContext,
configuration,
new View(-1L, "template", 10, 0, templateId),
attributeMapping,
1, false);
final PageContext valueContext = formContext.copyOf(grid);
final InputFieldBuilder inputFieldBuilder = this.examConfigurationService.getInputFieldBuilder(
attribute.getConfigAttribute(),
defaultOrientation);
final Orientation defaultOrientation = getDefaultOrientation(attribute);
final AttributeMapping attributeMapping = this.examConfigurationService
.getAttributes(attribute, defaultOrientation)
.getOrThrow();
final ViewContext viewContext = this.examConfigurationService.createViewContext(
valueContext,
configuration,
new View(-1L, "template", 10, 0, templateId),
attributeMapping,
1, false);
final InputField createInputField = inputFieldBuilder.createInputField(
content,
attribute.getConfigAttribute(),
viewContext);
final InputFieldBuilder inputFieldBuilder = this.examConfigurationService.getInputFieldBuilder(
attribute.getConfigAttribute(),
defaultOrientation);
viewContext.registerInputField(createInputField);
final InputField createInputField = inputFieldBuilder.createInputField(
content,
attribute.getConfigAttribute(),
viewContext);
this.examConfigurationService.initInputFieldValues(
configuration.id,
Arrays.asList(viewContext));
viewContext.registerInputField(createInputField);
this.pageService.pageActionBuilder(formContext.clearEntityKeys())
this.examConfigurationService.initInputFieldValues(
configuration.id,
Arrays.asList(viewContext));
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_FORM_SET_DEFAULT)
.withEntityKey(attributeKey)
.withParentEntityKey(templateKey)
.withExec(this.examConfigurationService::resetToDefaults)
.ignoreMoveAwayFromEdit()
.publishIf(() -> modifyGrant)
this.pageService.pageActionBuilder(formContext.clearEntityKeys())
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_REMOVE_VIEW)
.withEntityKey(attributeKey)
.withParentEntityKey(templateKey)
.withExec(this.examConfigurationService::removeFromView)
.ignoreMoveAwayFromEdit()
.publishIf(() -> modifyGrant && hasView)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_FORM_SET_DEFAULT)
.withEntityKey(attributeKey)
.withParentEntityKey(templateKey)
.withExec(this.examConfigurationService::resetToDefaults)
.ignoreMoveAwayFromEdit()
.publishIf(() -> modifyGrant)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_ATTACH_DEFAULT_VIEW)
.withEntityKey(attributeKey)
.withParentEntityKey(templateKey)
.withExec(this.examConfigurationService::attachToDefaultView)
.ignoreMoveAwayFromEdit()
.publishIf(() -> modifyGrant && !hasView)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_REMOVE_VIEW)
.withEntityKey(attributeKey)
.withParentEntityKey(templateKey)
.withExec(this.examConfigurationService::removeFromView)
.ignoreMoveAwayFromEdit()
.publishIf(() -> modifyGrant && hasView)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_FORM_EDIT_TEMPLATE)
.withEntityKey(templateKey)
.ignoreMoveAwayFromEdit()
.publish();
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_ATTACH_DEFAULT_VIEW)
.withEntityKey(attributeKey)
.withParentEntityKey(templateKey)
.withExec(this.examConfigurationService::attachToDefaultView)
.ignoreMoveAwayFromEdit()
.publishIf(() -> modifyGrant && !hasView)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_FORM_EDIT_TEMPLATE)
.withEntityKey(templateKey)
.ignoreMoveAwayFromEdit()
.publish();
} catch (final Exception e) {
pageContext.notifyUnexpectedError(e);
}
}
private Orientation getDefaultOrientation(final TemplateAttribute attribute) {

View file

@ -9,13 +9,12 @@
package ch.ethz.seb.sebserver.gui.content;
import org.eclipse.swt.widgets.Composite;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
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.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode;
@ -53,8 +52,6 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@GuiProfile
public class ConfigTemplateForm implements TemplateComposer {
private static final Logger log = LoggerFactory.getLogger(ConfigTemplateForm.class);
private static final LocTextKey FORM_TITLE_NEW =
new LocTextKey("sebserver.configtemplate.form.title.new");
private static final LocTextKey FORM_TITLE =
@ -118,14 +115,8 @@ public class ConfigTemplateForm implements TemplateComposer {
.getBuilder(GetExamConfigNode.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call()
.get(pageContext::notifyError);
if (examConfig == null) {
log.error("Failed to get ConfigurationNode for Template. "
+ "Error was notified to the User. "
+ "See previous logs for more infomation");
return;
}
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_NODE, error))
.getOrThrow();
final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(examConfig);
final boolean writeGrant = entityGrant.w();

View file

@ -87,6 +87,10 @@ public class ExamForm implements TemplateComposer {
private static final Logger log = LoggerFactory.getLogger(ExamForm.class);
public static final LocTextKey EXAM_FORM_TITLE_KEY =
new LocTextKey("sebserver.exam.form.title");
public static final LocTextKey EXAM_FORM_TITLE_IMPORT_KEY =
new LocTextKey("sebserver.exam.form.title.import");
private static final LocTextKey CONFIG_EMPTY_LIST_MESSAGE =
new LocTextKey("sebserver.exam.configuration.list.empty");
private static final LocTextKey INDICATOR_EMPTY_LIST_MESSAGE =
@ -145,6 +149,9 @@ public class ExamForm implements TemplateComposer {
private final static LocTextKey CONSISTENCY_MESSAGE_MISSING_SEB_RESTRICTION =
new LocTextKey("sebserver.exam.consistency.missing-seb-restriction");
private final static LocTextKey SEB_RESTRICTION_ERROR =
new LocTextKey("sebserver.error.exam.seb.restriction");
private final Map<String, LocTextKey> consistencyMessageMapping;
private final static LocTextKey CONFIRM_MESSAGE_REMOVE_CONFIG =
@ -199,15 +206,8 @@ public class ExamForm implements TemplateComposer {
final Exam exam = (importFromQuizData
? createExamFromQuizData(pageContext)
: getExistingExam(pageContext))
.get(pageContext::notifyError);
if (exam == null) {
log.error(
"Failed to get Exam. "
+ "Error was notified to the User. "
+ "See previous logs for more infomation");
return;
}
.onError(error -> pageContext.notifyLoadError(EntityType.EXAM, error))
.getOrThrow();
// new PageContext with actual EntityKey
final PageContext formContext = pageContext.withEntityKey(exam.getEntityKey());
@ -221,10 +221,9 @@ public class ExamForm implements TemplateComposer {
}
// the default page layout with title
final LocTextKey titleKey = new LocTextKey(
importFromQuizData
? "sebserver.exam.form.title.import"
: "sebserver.exam.form.title");
final LocTextKey titleKey = importFromQuizData
? EXAM_FORM_TITLE_IMPORT_KEY
: EXAM_FORM_TITLE_KEY;
final Composite content = this.widgetFactory.defaultPageLayout(
formContext.getParent(),
titleKey);
@ -579,7 +578,10 @@ public class ExamForm implements TemplateComposer {
}
private PageAction setSebRestriction(final PageAction action, final boolean sebRestriction) {
return setSebRestriction(action, sebRestriction, t -> action.pageContext().notifyError(t));
return setSebRestriction(
action,
sebRestriction,
error -> action.pageContext().notifyError(SEB_RESTRICTION_ERROR, error));
}
private PageAction setSebRestriction(
@ -685,7 +687,7 @@ public class ExamForm implements TemplateComposer {
.getBuilder(DeleteExamConfigMapping.class)
.withURIVariable(API.PARAM_MODEL_ID, examConfigMappingKey.modelId)
.call()
.onError(error -> action.pageContext().notifyError(error));
.onError(error -> action.pageContext().notifyRemoveError(EntityType.EXAM_CONFIGURATION_MAP, error));
return action;
}
@ -693,8 +695,7 @@ public class ExamForm implements TemplateComposer {
final EntityKey entityKey = pageContext.getEntityKey();
return this.restService.getBuilder(GetExam.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call()
.onError(error -> pageContext.notifyError(error));
.call();
}
private Result<Exam> createExamFromQuizData(final PageContext pageContext) {
@ -705,7 +706,7 @@ public class ExamForm implements TemplateComposer {
.withQueryParam(QuizData.QUIZ_ATTR_LMS_SETUP_ID, parentEntityKey.modelId)
.call()
.map(quizzData -> new Exam(quizzData))
.onError(error -> pageContext.notifyError(error));
.onError(error -> pageContext.notifyLoadError(EntityType.EXAM, error));
}
private String indicatorTypeName(final Indicator indicator) {

View file

@ -18,6 +18,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
@ -170,7 +171,8 @@ final class ExamToConfigBindPopup {
.getBuilder(GetExam.class)
.withURIVariable(API.PARAM_MODEL_ID, parentEntityKey.modelId)
.call()
.get(this.pageContext::notifyError)
.onError(error -> this.pageContext.notifyLoadError(EntityType.EXAM, error))
.getOrThrow()
: null;
// get data or create new. Handle error if happen
@ -180,7 +182,10 @@ final class ExamToConfigBindPopup {
.getBuilder(GetExamConfigMapping.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call()
.get(this.pageContext::notifyError);
.onError(error -> this.pageContext.notifyLoadError(
EntityType.EXAM_CONFIGURATION_MAP,
error))
.getOrThrow();
// new PageContext with actual EntityKey
final PageContext formContext = this.pageContext.withEntityKey(examConfigurationMap.getEntityKey());

View file

@ -9,12 +9,11 @@
package ch.ethz.seb.sebserver.gui.content;
import org.eclipse.swt.widgets.Composite;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
@ -41,8 +40,6 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@GuiProfile
public class IndicatorForm implements TemplateComposer {
private static final Logger log = LoggerFactory.getLogger(IndicatorForm.class);
private static final LocTextKey NEW_INDICATOR_TILE_TEXT_KEY =
new LocTextKey("sebserver.exam.indicator.form.title.new");
private static final LocTextKey INDICATOR_TILE_TEXT_KEY =
@ -82,7 +79,8 @@ public class IndicatorForm implements TemplateComposer {
.getBuilder(GetExam.class)
.withURIVariable(API.PARAM_MODEL_ID, parentEntityKey.modelId)
.call()
.get(pageContext::notifyError);
.onError(error -> pageContext.notifyLoadError(EntityType.EXAM, error))
.getOrThrow();
// get data or create new. Handle error if happen
final Indicator indicator = (isNew)
@ -91,14 +89,8 @@ public class IndicatorForm implements TemplateComposer {
.getBuilder(GetIndicator.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call()
.get(pageContext::notifyError);
if (indicator == null) {
log.error("Failed to get Indicator. "
+ "Error was notified to the User. "
+ "See previous logs for more infomation");
return;
}
.onError(error -> pageContext.notifyLoadError(EntityType.INDICATOR, error))
.getOrThrow();
// new PageContext with actual EntityKey
final PageContext formContext = pageContext.withEntityKey(indicator.getEntityKey());

View file

@ -9,8 +9,6 @@
package ch.ethz.seb.sebserver.gui.content;
import org.eclipse.swt.widgets.Composite;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
@ -44,6 +42,11 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@GuiProfile
public class InstitutionForm implements TemplateComposer {
private static final LocTextKey TITLE_TEXT_KEY =
new LocTextKey("sebserver.institution.form.title");
private static final LocTextKey NEW_TITLE_TEXT_KEY =
new LocTextKey("sebserver.institution.form.title.new");
private static final LocTextKey FORM_LOGO_IMAGE_TEXT_KEY =
new LocTextKey("sebserver.institution.form.logoImage");
private static final LocTextKey FORM_URL_SUFFIX_TEXT_KEY =
@ -51,8 +54,6 @@ public class InstitutionForm implements TemplateComposer {
private static final LocTextKey FORM_NAME_TEXT_KEY =
new LocTextKey("sebserver.institution.form.name");
private static final Logger log = LoggerFactory.getLogger(InstitutionForm.class);
private final PageService pageService;
private final RestService restService;
private final CurrentUser currentUser;
@ -80,14 +81,8 @@ public class InstitutionForm implements TemplateComposer {
.getBuilder(GetInstitution.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call()
.get(pageContext::notifyError);
if (institution == null) {
log.error("Failed to get Institution. "
+ "Error was notified to the User. "
+ "See previous logs for more infomation");
return;
}
.onError(error -> pageContext.notifyLoadError(EntityType.INSTITUTION, error))
.getOrThrow();
final EntityGrantCheck instGrant = this.currentUser.entityGrantCheck(institution);
final boolean writeGrant = instGrant.w();
@ -98,16 +93,10 @@ public class InstitutionForm implements TemplateComposer {
// new PageContext with actual EntityKey
final PageContext formContext = pageContext.withEntityKey(institution.getEntityKey());
if (log.isDebugEnabled()) {
log.debug("Institution Form for Institution {}", institution.name);
}
// the default page layout with interactive title
final LocTextKey titleKey = new LocTextKey(
(isNew)
? "sebserver.institution.form.title.new"
: "sebserver.institution.form.title",
institution.name);
final LocTextKey titleKey = isNew
? NEW_TITLE_TEXT_KEY
: TITLE_TEXT_KEY;
final Composite content = widgetFactory.defaultPageLayout(
formContext.getParent(),
titleKey);

View file

@ -13,13 +13,12 @@ import java.util.function.Function;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.swt.widgets.Composite;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
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.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
@ -61,7 +60,10 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@GuiProfile
public class LmsSetupForm implements TemplateComposer {
private static final Logger log = LoggerFactory.getLogger(LmsSetupForm.class);
private static final LocTextKey TITLE_TEXT_KEY =
new LocTextKey("sebserver.lmssetup.form.title");
private static final LocTextKey NEW_TITLE_TEXT_KEY =
new LocTextKey("sebserver.lmssetup.form.title.new");
private static final LocTextKey FORM_SECRET_LMS_TEXT_KEY =
new LocTextKey("sebserver.lmssetup.form.secret.lms");
@ -120,23 +122,15 @@ public class LmsSetupForm implements TemplateComposer {
.getBuilder(GetLmsSetup.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call()
.get(pageContext::notifyError);
if (lmsSetup == null) {
log.error(
"Failed to get LmsSetup. "
+ "Error was notified to the User. "
+ "See previous logs for more infomation");
return;
}
.onError(error -> pageContext.notifyLoadError(EntityType.LMS_SETUP, error))
.getOrThrow();
// new PageContext with actual EntityKey
final PageContext formContext = pageContext.withEntityKey(lmsSetup.getEntityKey());
// the default page layout with title
final LocTextKey titleKey = new LocTextKey(
isNotNew.getAsBoolean()
? "sebserver.lmssetup.form.title"
: "sebserver.lmssetup.form.title.new");
final LocTextKey titleKey = isNotNew.getAsBoolean()
? TITLE_TEXT_KEY
: NEW_TITLE_TEXT_KEY;
final Composite content = widgetFactory.defaultPageLayout(
formContext.getParent(),
titleKey);
@ -302,7 +296,7 @@ public class LmsSetupForm implements TemplateComposer {
API.PARAM_MODEL_ID,
action.pageContext().getAttribute(AttributeKeys.ENTITY_ID))
.call()
.onError(t -> action.pageContext().notifyError(t));
.onError(error -> action.pageContext().notifyActivationError(EntityType.LMS_SETUP, error));
return testLmsSetup;
}

View file

@ -11,13 +11,12 @@ package ch.ethz.seb.sebserver.gui.content;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.rap.rwt.client.service.UrlLauncher;
import org.eclipse.swt.widgets.Composite;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SebClientConfig;
@ -49,8 +48,6 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@GuiProfile
public class SebClientConfigForm implements TemplateComposer {
private static final Logger log = LoggerFactory.getLogger(LmsSetupForm.class);
private static final LocTextKey FORM_TITLE_NEW =
new LocTextKey("sebserver.clientconfig.form.title.new");
private static final LocTextKey FORM_TITLE =
@ -106,14 +103,8 @@ public class SebClientConfigForm implements TemplateComposer {
.getBuilder(GetClientConfig.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call()
.get(pageContext::notifyError);
if (clientConfig == null) {
log.error("Failed to get SebClientConfig. "
+ "Error was notified to the User. "
+ "See previous logs for more infomation");
return;
}
.onError(error -> pageContext.notifyLoadError(EntityType.SEB_CLIENT_CONFIGURATION, error))
.getOrThrow();
final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(clientConfig);
final boolean writeGrant = entityGrant.w();

View file

@ -20,6 +20,7 @@ import org.eclipse.swt.widgets.Control;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration;
@ -177,13 +178,16 @@ final class SebExamConfigImportPopup {
} else {
formHandle
.getContext()
.notifyError(error);
.notifyImportError(EntityType.CONFIGURATION_NODE, error);
}
});
return true;
}
formHandle.getContext().notifyError(configuration.getError());
formHandle.getContext().notifyError(
SebExamConfigPropForm.FORM_TITLE,
configuration.getError());
return true;
}
} else {
@ -195,7 +199,7 @@ final class SebExamConfigImportPopup {
return false;
} catch (final Exception e) {
formHandle.getContext().notifyError(e);
formHandle.getContext().notifyError(SebExamConfigPropForm.FORM_TITLE, e);
return true;
}
}

View file

@ -18,8 +18,6 @@ import org.eclipse.rap.rwt.client.service.UrlLauncher;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Text;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
@ -71,8 +69,6 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
@GuiProfile
public class SebExamConfigPropForm implements TemplateComposer {
private static final Logger log = LoggerFactory.getLogger(SebExamConfigPropForm.class);
static final LocTextKey FORM_TITLE_NEW =
new LocTextKey("sebserver.examconfig.form.title.new");
static final LocTextKey FORM_TITLE =
@ -139,13 +135,8 @@ public class SebExamConfigPropForm implements TemplateComposer {
.getBuilder(GetExamConfigNode.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call()
.get(pageContext::notifyError);
if (examConfig == null) {
log.error("Failed to get ConfigurationNode. "
+ "Error was notified to the User. "
+ "See previous logs for more infomation");
return;
}
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_NODE, error))
.getOrThrow();
final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(examConfig);
final boolean writeGrant = entityGrant.w();

View file

@ -102,7 +102,7 @@ public class SebExamConfigSettingsForm implements TemplateComposer {
final ConfigurationNode configNode = this.restService.getBuilder(GetExamConfigNode.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call()
.onError(pageContext::notifyError)
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_NODE, error))
.getOrThrow();
final Configuration configuration = this.restService.getBuilder(GetConfigurations.class)
@ -110,12 +110,12 @@ public class SebExamConfigSettingsForm implements TemplateComposer {
.withQueryParam(Configuration.FILTER_ATTR_FOLLOWUP, Constants.TRUE_STRING)
.call()
.map(Utils::toSingleton)
.onError(pageContext::notifyError)
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION, error))
.getOrThrow();
final AttributeMapping attributes = this.examConfigurationService
.getAttributes(configNode.templateId)
.onError(pageContext::notifyError)
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_ATTRIBUTE, error))
.getOrThrow();
final boolean readonly = pageContext.isReadonly() || configNode.status == ConfigurationStatus.IN_USE;
@ -195,11 +195,11 @@ public class SebExamConfigSettingsForm implements TemplateComposer {
.publish();
} catch (final RuntimeException e) {
log.error("Unexpected error while trying to fetch exam configuration data and create views", e);
pageContext.notifyUnexpectedError(e);
throw e;
} catch (final Exception e) {
log.error("Unexpected error while trying to fetch exam configuration data and create views", e);
pageContext.notifyError(e);
pageContext.notifyError(SebExamConfigPropForm.FORM_TITLE, e);
}
}

View file

@ -15,6 +15,7 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.user.PasswordChange;
@ -46,6 +47,7 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
* password that is also required must match the administrators current password. */
public class UserAccountChangePasswordForm implements TemplateComposer {
private static final String FORM_TITLE_KEY = "sebserver.useraccount.form.pwchange.title";
private static final LocTextKey FORM_PASSWORD_NEW_TEXT_KEY =
new LocTextKey("sebserver.useraccount.form.password.new");
private static final LocTextKey FORM_PASSWORD_NEW_CONFIRM_TEXT_KEY =
@ -79,11 +81,12 @@ public class UserAccountChangePasswordForm implements TemplateComposer {
.getBuilder(GetUserAccount.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call()
.get(pageContext::notifyError);
.onError(error -> pageContext.notifyLoadError(EntityType.USER, error))
.getOrThrow();
final Composite content = widgetFactory.defaultPageLayout(
pageContext.getParent(),
new LocTextKey("sebserver.useraccount.form.pwchange.title", userInfo.username));
new LocTextKey(FORM_TITLE_KEY, userInfo.username));
final boolean ownAccount = this.currentUser.get().uuid.equals(entityKey.getModelId());

View file

@ -12,8 +12,6 @@ import java.util.function.BooleanSupplier;
import org.apache.tomcat.util.buf.StringUtils;
import org.eclipse.swt.widgets.Composite;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
@ -56,23 +54,26 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@GuiProfile
public class UserAccountForm implements TemplateComposer {
private static final Logger log = LoggerFactory.getLogger(UserAccountForm.class);
static final LocTextKey TITLE_TEXT_KEY =
new LocTextKey("sebserver.useraccount.form.title");
static final LocTextKey NEW_TITLE_TEXT_KEY =
new LocTextKey("sebserver.useraccount.form.title.new");
private static final LocTextKey FORM_PASSWORD_CONFIRM_TEXT_KEY =
static final LocTextKey FORM_PASSWORD_CONFIRM_TEXT_KEY =
new LocTextKey("sebserver.useraccount.form.password.confirm");
private static final LocTextKey FORM_PASSWORD_TEXT_KEY =
static final LocTextKey FORM_PASSWORD_TEXT_KEY =
new LocTextKey("sebserver.useraccount.form.password");
private static final LocTextKey FORM_ROLES_TEXT_KEY =
static final LocTextKey FORM_ROLES_TEXT_KEY =
new LocTextKey("sebserver.useraccount.form.roles");
private static final LocTextKey FORM_TIMEZONE_TEXT_KEY =
static final LocTextKey FORM_TIMEZONE_TEXT_KEY =
new LocTextKey("sebserver.useraccount.form.timezone");
private static final LocTextKey FORM_MAIL_TEXT_KEY =
static final LocTextKey FORM_MAIL_TEXT_KEY =
new LocTextKey("sebserver.useraccount.form.mail");
private static final LocTextKey FORM_USERNAME_TEXT_KEY =
static final LocTextKey FORM_USERNAME_TEXT_KEY =
new LocTextKey("sebserver.useraccount.form.username");
private static final LocTextKey FORM_NAME_TEXT_KEY =
static final LocTextKey FORM_NAME_TEXT_KEY =
new LocTextKey("sebserver.useraccount.form.name");
private static final LocTextKey FORM_INSTITUTION_TEXT_KEY =
static final LocTextKey FORM_INSTITUTION_TEXT_KEY =
new LocTextKey("sebserver.useraccount.form.institution");
private final PageService pageService;
@ -110,15 +111,8 @@ public class UserAccountForm implements TemplateComposer {
.getBuilder(GetUserAccount.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call()
.get(pageContext::notifyError);
if (userAccount == null) {
log.error(
"Failed to get UserAccount. "
+ "Error was notified to the User. "
+ "See previous logs for more infomation");
return;
}
.onError(error -> pageContext.notifyLoadError(EntityType.USER, error))
.getOrThrow();
final boolean roleBasedEditGrant = Privilege.hasRoleBasedUserAccountEditGrant(userAccount, currentUser.get());
// new PageContext with actual EntityKey
@ -138,16 +132,10 @@ public class UserAccountForm implements TemplateComposer {
.map(inst -> inst.active)
.getOr(false);
if (log.isDebugEnabled()) {
log.debug("UserAccount Form for user {}", userAccount.getName());
}
// the default page layout with title
final LocTextKey titleKey = new LocTextKey(
isNotNew.getAsBoolean()
? "sebserver.useraccount.form.title"
: "sebserver.useraccount.form.title.new",
userAccount.getUsername());
final LocTextKey titleKey = isNotNew.getAsBoolean()
? TITLE_TEXT_KEY
: NEW_TITLE_TEXT_KEY;
final Composite content = widgetFactory.defaultPageLayout(
formContext.getParent(),
titleKey);

View file

@ -14,7 +14,9 @@ import java.util.function.Predicate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.gbl.util.Utils;
@ -133,8 +135,16 @@ public class FormHandle<T extends Entity> {
fieldAccessor -> showValidationError(fieldAccessor, fve)));
return true;
} else {
log.error("Unexpected error while trying to post form: ", error);
this.pageContext.notifyError(error);
log.error("Unexpected error while trying to post form: {}", error.getMessage());
final EntityType resultType = this.post.getResultType();
if (resultType != null) {
this.pageContext.notifySaveError(resultType, error);
} else {
this.pageContext.notifyError(
new LocTextKey(PageContext.GENERIC_SAVE_ERROR_TEXT_KEY, Constants.EMPTY_NOTE),
error);
}
return false;
}
}

View file

@ -286,6 +286,10 @@ public class ResourceService {
.collect(Collectors.toList());
}
public static LocTextKey getEntityTypeNameKey(final EntityType type) {
return new LocTextKey(ENTITY_TYPE_PREFIX + type.name());
}
public String getEntityTypeName(final EntityType type) {
if (type == null) {
return Constants.EMPTY_NOTE;

View file

@ -233,6 +233,9 @@ public abstract class AbstractTableFieldBuilder implements InputFieldBuilder {
}
ConfigurationAttribute attr = tableContext.getAttribute(value.attributeId);
if (attr == null) {
return false;
}
while (attr.parentId != null) {
if (attribute.id.equals(attr.parentId)) {
return true;

View file

@ -28,6 +28,7 @@ import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
import ch.ethz.seb.sebserver.gbl.api.APIMessage.ErrorMessage;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration;
@ -373,7 +374,7 @@ public class ExamConfigurationServiceImpl implements ExamConfigurationService {
}
} catch (final Exception e) {
this.pageContext.notifyError(e);
this.pageContext.notifySaveError(EntityType.CONFIGURATION_VALUE, e);
}
}

View file

@ -15,7 +15,9 @@ import org.eclipse.swt.widgets.Shell;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gui.service.ResourceService;
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
@ -44,6 +46,17 @@ public interface PageContext {
}
/** The resource-bundle key of the generic load entity error message. */
public static final String GENERIC_LOAD_ERROR_TEXT_KEY = "sebserver.error.get.entity";
public static final String GENERIC_REMOVE_ERROR_TEXT_KEY = "sebserver.error.remove.entity";
public static final String GENERIC_SAVE_ERROR_TEXT_KEY = "sebserver.error.save.entity";
public static final String GENERIC_ACTIVATE_ERROR_TEXT_KEY = "sebserver.error.activate.entity";
public static final String GENERIC_IMPORT_ERROR_TEXT_KEY = "sebserver.error.import";
public static final LocTextKey SUCCESS_MSG_TITLE =
new LocTextKey("sebserver.page.message");
public static final LocTextKey UNEXPECTED_ERROR_KEY =
new LocTextKey("sebserver.error.action.unexpected.message");
/** Get the I18nSupport service
*
* @return the I18nSupport service */
@ -187,14 +200,74 @@ public interface PageContext {
*
* @param errorMessage the error message to display
* @param error the error as Exception */
void notifyError(String errorMessage, Exception error);
void notifyError(LocTextKey errorMessage, Exception error);
/** Shows an error message to the user with the message of the given Exception.
* This mainly is used for debugging so far
/** Notify a generic load error to the user by pop-up
*
* @param error the Exception to display
* @return adaption to be used with functional approaches */
<T> T notifyError(Exception error);
* @param entityType the type of the entity
* @param error the original error */
default void notifyLoadError(final EntityType entityType, final Exception error) {
notifyError(
new LocTextKey(
GENERIC_LOAD_ERROR_TEXT_KEY,
getI18nSupport().getText(ResourceService.getEntityTypeNameKey(entityType))),
error);
}
/** Notify a generic remove error to the user by pop-up
*
* @param entityType the type of the entity
* @param error the original error */
default void notifyRemoveError(final EntityType entityType, final Exception error) {
notifyError(
new LocTextKey(
GENERIC_REMOVE_ERROR_TEXT_KEY,
getI18nSupport().getText(ResourceService.getEntityTypeNameKey(entityType))),
error);
}
/** Notify a generic save error to the user by pop-up
*
* @param entityType the type of the entity
* @param error the original error */
default void notifySaveError(final EntityType entityType, final Exception error) {
notifyError(
new LocTextKey(
GENERIC_SAVE_ERROR_TEXT_KEY,
getI18nSupport().getText(ResourceService.getEntityTypeNameKey(entityType))),
error);
}
/** Notify a generic activation error to the user by pop-up
*
* @param entityType the type of the entity
* @param error the original error */
default void notifyActivationError(final EntityType entityType, final Exception error) {
notifyError(
new LocTextKey(
GENERIC_ACTIVATE_ERROR_TEXT_KEY,
getI18nSupport().getText(ResourceService.getEntityTypeNameKey(entityType))),
error);
}
/** Notify a generic import error to the user by pop-up
*
* @param entityType the type of the entity
* @param error the original error */
default void notifyImportError(final EntityType entityType, final Exception error) {
notifyError(
new LocTextKey(
GENERIC_IMPORT_ERROR_TEXT_KEY,
getI18nSupport().getText(ResourceService.getEntityTypeNameKey(entityType))),
error);
}
/** Notify a generic unexpected error to the user by pop-up
*
* @param error the original error */
default void notifyUnexpectedError(final Exception error) {
notifyError(UNEXPECTED_ERROR_KEY, error);
}
/** Publish and shows a message to the user with the given localized title and
* localized message. The message text can also be HTML text as far as RWT supports it.

View file

@ -313,12 +313,13 @@ public interface PageService {
final Class<? extends RestCall<T>> restCallType) {
this.exec = action -> {
final PageContext pageContext = action.pageContext();
restService.getBuilder(restCallType)
.withURIVariable(
API.PARAM_MODEL_ID,
action.pageContext().getAttribute(AttributeKeys.ENTITY_ID))
.call()
.onError(t -> action.pageContext().notifyError(t));
.onError(pageContext::notifyUnexpectedError);
return action;
};

View file

@ -20,6 +20,7 @@ import org.slf4j.LoggerFactory;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
@ -32,11 +33,8 @@ public final class PageAction {
private static final Logger log = LoggerFactory.getLogger(PageAction.class);
public static final LocTextKey SUCCESS_MSG_TITLE = new LocTextKey("sebserver.page.message");
public final ActionDefinition definition;
private final Supplier<LocTextKey> confirm;
final LocTextKey successMessage;
private final Supplier<Set<EntityKey>> selectionSupplier;
private final LocTextKey noSelectionMessage;
private PageContext pageContext;
@ -44,6 +42,8 @@ public final class PageAction {
final boolean fireActionEvent;
final boolean ignoreMoveAwayFromEdit;
final LocTextKey successMessage;
public PageAction(
final ActionDefinition definition,
final Supplier<LocTextKey> confirm,
@ -76,6 +76,14 @@ public final class PageAction {
}
}
public String getName() {
if (this.definition != null) {
return this.definition.name();
}
return Constants.EMPTY_NOTE;
}
public EntityKey getEntityKey() {
return this.pageContext.getEntityKey();
}
@ -144,7 +152,9 @@ public final class PageAction {
final PageAction apply = this.exec.apply(this);
if (this.successMessage != null) {
apply.pageContext.publishPageMessage(SUCCESS_MSG_TITLE, this.successMessage);
apply.pageContext.publishPageMessage(
PageContext.SUCCESS_MSG_TITLE,
this.successMessage);
}
return Result.of(apply);
@ -153,13 +163,23 @@ public final class PageAction {
return Result.ofError(pme);
} catch (final RestCallError restCallError) {
if (!restCallError.isFieldValidationError()) {
log.error("Failed to execute action: {}", PageAction.this, restCallError);
PageAction.this.pageContext.notifyError("action.error.unexpected.message", restCallError);
log.error("Failed to execute action: {} | error: {} | cause: {}",
PageAction.this.getName(),
restCallError.getMessage(),
Utils.getErrorCauseMessage(restCallError));
PageAction.this.pageContext.notifyError(
PageContext.UNEXPECTED_ERROR_KEY,
restCallError);
}
return Result.ofError(restCallError);
} catch (final Exception e) {
log.error("Failed to execute action: {}", PageAction.this, e);
PageAction.this.pageContext.notifyError("action.error.unexpected.message", e);
log.error("Failed to execute action: {} | error: {} | cause: {}",
PageAction.this.getName(),
e.getMessage(),
Utils.getErrorCauseMessage(e));
PageAction.this.pageContext.notifyError(
PageContext.UNEXPECTED_ERROR_KEY,
e);
return Result.ofError(e);
}
}
@ -179,6 +199,31 @@ public final class PageAction {
return this;
}
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("PageAction [definition=");
builder.append(this.definition);
builder.append(", confirm=");
builder.append(this.confirm);
builder.append(", selectionSupplier=");
builder.append(this.selectionSupplier);
builder.append(", noSelectionMessage=");
builder.append(this.noSelectionMessage);
builder.append(", pageContext=");
builder.append(this.pageContext);
builder.append(", exec=");
builder.append(this.exec);
builder.append(", fireActionEvent=");
builder.append(this.fireActionEvent);
builder.append(", ignoreMoveAwayFromEdit=");
builder.append(this.ignoreMoveAwayFromEdit);
builder.append(", successMessage=");
builder.append(this.successMessage);
builder.append("]");
return builder.toString();
}
public static PageAction applySingleSelection(final PageAction action) {
return action.withEntityKey(action.getSingleSelection());
}

View file

@ -280,13 +280,17 @@ public class PageContextImpl implements PageContext {
}
@Override
public void notifyError(final String errorMessage, final Exception error) {
public void notifyError(final LocTextKey message, final Exception error) {
final String errorMessage = message != null
? this.i18nSupport.getText(message)
: error.getMessage();
if (error instanceof APIMessageError) {
final List<APIMessage> errorMessages = ((APIMessageError) error).getErrorMessages();
final MessageBox messageBox = new Message(
getShell(),
this.i18nSupport.getText("sebserver.error.unexpected"),
APIMessage.toHTML(errorMessages),
APIMessage.toHTML(errorMessage, errorMessages),
SWT.ERROR);
messageBox.setMarkupEnabled(true);
messageBox.open(null);
@ -301,12 +305,6 @@ public class PageContextImpl implements PageContext {
messageBox.open(null);
}
@Override
public <T> T notifyError(final Exception error) {
notifyError(error.getMessage(), error);
return null;
}
@Override
public String toString() {
return "PageContextImpl [root=" + this.root + ", parent=" + this.parent + ", attributes=" + this.attributes

View file

@ -55,6 +55,8 @@ public class PageServiceImpl implements PageService {
private static final LocTextKey MSG_GO_AWAY_FROM_EDIT =
new LocTextKey("sebserver.overall.action.goAwayFromEditPageConfirm");
private static final LocTextKey LOGOUT_ERROR_MESSAGE =
new LocTextKey("sebserver.error.logout");
private static final String ATTR_PAGE_STATE = "PAGE_STATE";
private static final ListenerComparator LIST_COMPARATOR = new ListenerComparator();
@ -234,7 +236,9 @@ public class PageServiceImpl implements PageService {
if (!logoutSuccessful) {
log.error("Failed to logout. See logfiles for more information");
pageContext.notifyError(new RuntimeException("Failed to logout. See logfiles for more information"));
pageContext.notifyError(
LOGOUT_ERROR_MESSAGE,
new RuntimeException("Failed to logout. See logfiles for more information"));
}
} catch (final Exception e) {

View file

@ -94,6 +94,14 @@ public abstract class RestCall<T> {
return this;
}
public EntityType getResultType() {
if (this.typeKey != null) {
return this.typeKey.entityType;
}
return null;
}
protected Result<T> exchange(final RestCallBuilder builder) {
log.debug("Call webservice API on {} for {}", this.path, builder);

View file

@ -393,7 +393,7 @@ public class EntityTable<ROW extends Entity> {
.call()
.map(this::createTableRowsFromPage)
.map(this.navigator::update)
.onError(this.pageContext::notifyError);
.onError(this.pageContext::notifyUnexpectedError);
this.composite.getParent().layout(true, true);
PageService.updateScrolledComposite(this.composite);

View file

@ -10,6 +10,7 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction;
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl.BulkAction;
/** Service to address bulk actions like activation or deletion where the action
* or state-change of one Entity has an effect on other entities that that has

View file

@ -21,12 +21,12 @@ import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ActivatableEntityDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.DAOLoggingSupport;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.EntityDAO;
/** Defines overall DAO support for bulk-actions like activate, deactivate, delete...
*
*
* @param <T> The type of the Entity of a concrete BulkActionSupportDAO */
public interface BulkActionSupportDAO<T extends Entity> {

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction;
package ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl;
import java.util.Arrays;
import java.util.Collection;

View file

@ -6,10 +6,11 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction;
package ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl;
import org.springframework.context.ApplicationEvent;
/** Defines a bulk-action event fired after a bulk-action happened */
public class BulkActionEvent extends ApplicationEvent {
private static final long serialVersionUID = 1102149193640832829L;
@ -18,6 +19,9 @@ public class BulkActionEvent extends ApplicationEvent {
super(source);
}
/** Get the wrapped BulkAction instance
*
* @return the wrapped BulkAction instance */
public BulkAction getBulkAction() {
return (BulkAction) this.source;
}

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction;
package ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl;
import java.util.Arrays;
import java.util.Collection;
@ -28,6 +28,8 @@ import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
import ch.ethz.seb.sebserver.gbl.model.user.UserLogActivityType;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionService;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionSupportDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;
@Service

View file

@ -0,0 +1 @@
/ExamDAO.java

View file

@ -14,22 +14,50 @@ import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.AdditionalAttributeRecord;
/** Defines functionality to access additional attributes.
*
* Additional attributes are name/value pairs associated with a specified entity but stored
* in a separated data-base table. */
public interface AdditionalAttributesDAO {
/** Use this to get all additional attribute records for a specific entity.
*
* @param type the entity type
* @param entityId the entity identifier (primary key)
* @return Result refer to the collection of additional attribute records or to an error if happened */
Result<Collection<AdditionalAttributeRecord>> getAdditionalAttributes(
EntityType type,
Long entityId);
/** Use this to save an additional attribute for a specific entity.
* If the additional attribute with specified name already exists for the specified entity
* this updates just the value for this additional attribute. Otherwise create a new instance
* of additional attribute with the given data
*
* @param type the entity type
* @param entityId the entity identifier (primary key)
* @param name the name of the attribute
* @param value the value of the attribute */
void saveAdditionalAttribute(
EntityType type,
Long entityId,
String name,
String value);
/** Use this to delete an additional attribute by identifier (primary-key)
*
* @param id identifier (primary-key) */
void delete(Long id);
/** Use this to delete an additional attribute by its entity identifier and name.
*
* @param entityId the entity identifier (primary-key)
* @param name the name of the additional attribute */
void delete(Long entityId, String name);
/** Use this to delete all additional attributes for a given entity.
*
* @param entityId the entity identifier (primary-key) */
void deleteAll(Long entityId);
}

View file

@ -17,6 +17,11 @@ import ch.ethz.seb.sebserver.gbl.util.Result;
public interface ClientEventDAO extends EntityDAO<ClientEvent, ClientEvent> {
/** Use this to get all matching ExtendedClientEvent from persistent storage.
*
* @param filterMap the FilterMap containing all the filter criteria
* @param predicate an additional predicate to filter the list
* @return Result refer to all matching ExtendedClientEvent from persistent storage or to an error if happened. */
Result<Collection<ExtendedClientEvent>> allMatchingExtended(
FilterMap filterMap,
Predicate<ExtendedClientEvent> predicate);

View file

@ -18,9 +18,14 @@ public interface ConfigurationAttributeDAO extends EntityDAO<ConfigurationAttrib
/** Use this to get all ConfigurationAttribute that are root attributes and no child
* attributes (has no parent reference).
*
* @return Collection of all ConfigurationAttribute that are root attributes */
* @return Result refer to a Collection of all ConfigurationAttribute that are root attributes or to an error if
* happened */
Result<Collection<ConfigurationAttribute>> getAllRootAttributes();
/** Use this to get all ConfigurationAttribute that are children of a specified ConfigurationAttribute.
*
* @param parentId the identifier of the ConfigurationAttribute to get the children for
* @return Result refer to a collection of child ConfigurationAttribute or to an error if happened */
Result<Collection<ConfigurationAttribute>> allChildAttributes(final Long parentId);
}

View file

@ -17,6 +17,12 @@ public interface ConfigurationNodeDAO extends
EntityDAO<ConfigurationNode, ConfigurationNode>,
BulkActionSupportDAO<ConfigurationNode> {
/** Use this to create a copy from an existing configuration.
*
* @param institutionId the institution identifier of the existing configuration
* @param newOwner the owner of the created copy
* @param copyInfo the ConfigCreationInfo containing additional copy information
* @return Result refer to the configuration copy root node or to an error if happened */
Result<ConfigurationNode> createCopy(
Long institutionId,
String newOwner,

View file

@ -59,6 +59,13 @@ public interface ConfigurationValueDAO extends EntityDAO<ConfigurationValue, Con
* @return the saved table values of the attribute and configuration */
Result<ConfigurationTableValues> saveTableValues(ConfigurationTableValues value);
/** Use this to (re)set the default value(s) for a configuration attributes of a given configuration entry.
* This uses also the ExamConfigInitService to initialize table values
*
* @param institutionId the institution identifier of the configuration
* @param configurationId the configuration identifier
* @param attributeId the configuration attribute identifier
* @return Result refer to a set of all keys of default values or to an error if happened */
Result<Set<EntityKey>> setDefaultValues(
Long institutionId,
Long configurationId,

View file

@ -41,22 +41,68 @@ public interface ExamDAO extends ActivatableEntityDAO<Exam, Exam>, BulkActionSup
* @return a Result containing the Exam by a given ClientConnection id or refer to an error if happened */
Result<Exam> byClientConnection(Long connectionId);
/** Use this to get identifiers of all exams in a specified state for a specified institution.
*
* @param institutionId the institution identifier. May be null for all institutions
* @param status the ExamStatus
* @return Result refer to collection of exam identifiers or to an error if happened */
Result<Collection<Long>> getExamIdsForStatus(Long institutionId, ExamStatus status);
/** This is used to get all Exams to check if they have to set into running state in the meanwhile.
* Gets all exams in the upcoming status for run-check
*
* @return Result refer to a collection of exams or to an error if happened */
Result<Collection<Exam>> allForRunCheck();
/** This is used to get all Exams to check if they have to set into finished state in the meanwhile.
* Gets all exams in the running status for end-check
*
* @return Result refer to a collection of exams or to an error if happened */
Result<Collection<Exam>> allForEndCheck();
Result<Exam> placeLock(Long examId, String update);
/** This is used to place an internal (write)lock for the specified exam.
* The exam will be marked as locked on the persistence level to prevent other running web-service instances
* to write concurrently to the specified exam while it is been updated by an internal batch process.
*
* @param examId the exam identifier
* @param updateId an update identifier
* @return Result refer to the specified exam or to an error if happened */
Result<Exam> placeLock(Long examId, String updateId);
Result<Exam> releaseLock(Long examId, String update);
/** This is used to release an internal (write)lock for the specified exam.
* The exam will be marked as not locked on the persistence level.
*
* @param examId the exam identifier
* @param updateId an update identifier
* @return Result refer to the specified exam or to an error if happened */
Result<Exam> releaseLock(Long examId, String updateId);
/** This is used to force release an internal (write)lock for the specified exam.
* The exam will be marked as not locked on the persistence level even if it is currently locked by another process
*
* @param examId the exam identifier
* @param updateId an update identifier
* @return Result refer to the specified exam or to an error if happened */
Result<Long> forceUnlock(Long examId);
/** Indicates if the exam with specified identifier has an internal write lock.
*
* @param examId the exam identifier
* @return Result refer to the lock-check-result or to an error if happened */
Result<Boolean> isLocked(Long examId);
Result<Boolean> upToDate(Long examId, String lastUpdate);
/** Use this to check of the exam with the specified identifier is up to date
*
* @param examId the exam identifier
* @param updateId the update identifier of the exam
* @return Result refer to the up-to-date result or to an error if happened */
Result<Boolean> upToDate(Long examId, String updateId);
Result<Exam> setSebRestriction(Long id, boolean sebRestriction);
/** This is used to set the seb-restriction flag for a specified exam.
*
* @param examId the exam identifier
* @param sebRestriction the seb-restriction flag value
* @return Result refer to the updated Exam or to an error if happened */
Result<Exam> setSebRestriction(Long examId, boolean sebRestriction);
}

View file

@ -24,5 +24,9 @@ public interface LmsSetupDAO extends ActivatableEntityDAO<LmsSetup, LmsSetup>, B
* @return the configured ClientCredentials for a given LmsSetup */
Result<ClientCredentials> getLmsAPIAccessCredentials(String lmsSetupId);
/** Use this to get additional proxy data for specified LMS Setup.
*
* @param lmsSetupId the LMS Setup identifier
* @return Result refer to the proxy data or to an error if happened */
Result<ProxyData> getLmsAPIAccessProxyData(String lmsSetupId);
}

View file

@ -41,7 +41,7 @@ import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ConfigurationReco
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ConfigurationValueRecordDynamicSqlSupport;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ConfigurationValueRecordMapper;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ConfigurationNodeRecord;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ConfigurationNodeDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.DAOLoggingSupport;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;

View file

@ -17,6 +17,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
@ -33,6 +34,7 @@ import org.springframework.transaction.annotation.Transactional;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues.TableValue;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
@ -51,6 +53,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.dao.DAOLoggingSupport;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ResourceNotFoundException;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.TransactionHandler;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ExamConfigInitService;
@Lazy
@Component
@ -63,17 +66,20 @@ public class ConfigurationValueDAOImpl implements ConfigurationValueDAO {
private final ConfigurationAttributeRecordMapper configurationAttributeRecordMapper;
private final ConfigurationRecordMapper configurationRecordMapper;
private final ConfigurationDAOBatchService configurationDAOBatchService;
private final ExamConfigInitService examConfigInitService;
protected ConfigurationValueDAOImpl(
final ConfigurationValueRecordMapper configurationValueRecordMapper,
final ConfigurationAttributeRecordMapper configurationAttributeRecordMapper,
final ConfigurationRecordMapper configurationRecordMapper,
final ConfigurationDAOBatchService configurationDAOBatchService) {
final ConfigurationDAOBatchService configurationDAOBatchService,
final ExamConfigInitService examConfigInitService) {
this.configurationValueRecordMapper = configurationValueRecordMapper;
this.configurationAttributeRecordMapper = configurationAttributeRecordMapper;
this.configurationRecordMapper = configurationRecordMapper;
this.configurationDAOBatchService = configurationDAOBatchService;
this.examConfigInitService = examConfigInitService;
}
@Override
@ -388,10 +394,12 @@ public class ConfigurationValueDAOImpl implements ConfigurationValueDAO {
.map(r -> new EntityKey(r.getId(), EntityType.CONFIGURATION_VALUE))
.collect(Collectors.toSet()));
// if there are table values, delete them first
// if there are table values, delete them first and init defaults
if (tableValues != null && !tableValues.isEmpty()) {
this.delete(tableValues)
.getOrThrow();
initTableValues(institutionId, configurationId, attributeId);
}
}
@ -413,7 +421,7 @@ public class ConfigurationValueDAOImpl implements ConfigurationValueDAO {
return tableValues;
} else {
if (values.size() > 1) {
throw new IllegalStateException("Expacted one but get: " + values.size());
throw new IllegalStateException("Expected one but get: " + values.size());
}
final ConfigurationAttributeRecord attribute = this.configurationAttributeRecordMapper
@ -439,6 +447,41 @@ public class ConfigurationValueDAOImpl implements ConfigurationValueDAO {
});
}
private void initTableValues(final Long institutionId, final Long configurationId, final Long attributeId) {
// get table init values and save
final List<Long> childAttributes = this.configurationAttributeRecordMapper.selectIdsByExample()
.where(
ConfigurationAttributeRecordDynamicSqlSupport.parentId,
isEqualTo(attributeId))
.build()
.execute();
// get all attributes and map the names to id's
final Map<String, ConfigurationAttribute> attributeMap = this.configurationAttributeRecordMapper
.selectByExample()
.build()
.execute()
.stream()
.map(ConfigurationAttributeDAOImpl::toDomainModel)
.map(Result::get)
.filter(Objects::nonNull)
.collect(Collectors.toMap(
attr -> attr.name,
Function.identity()));
this.examConfigInitService
.getAdditionalDefaultValues(institutionId, configurationId, attributeMap::get)
.stream()
.filter(attrValue -> childAttributes.contains(attrValue.attributeId))
.forEach(attrValue -> this.configurationValueRecordMapper
.insert(new ConfigurationValueRecord(
null,
attrValue.institutionId,
attrValue.configurationId,
attrValue.attributeId,
attrValue.listIndex,
attrValue.value)));
}
// get all attributes of the table (columns) mapped to attribute id
private Result<Map<Long, ConfigurationAttributeRecord>> getAttributeMapping(
final ConfigurationAttributeRecord attributeRecord) {

View file

@ -47,7 +47,7 @@ import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ExamRecordMapper;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ConfigurationNodeRecord;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ExamConfigurationMapRecord;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ExamRecord;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.client.ClientCredentialService;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.DAOLoggingSupport;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamConfigurationMapDAO;

View file

@ -44,7 +44,7 @@ import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientConnectionR
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ExamRecordDynamicSqlSupport;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ExamRecordMapper;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ExamRecord;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl.BulkAction;
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.ResourceNotFoundException;
@ -170,6 +170,12 @@ public class ExamDAOImpl implements ExamDAO {
public Result<Exam> save(final Exam exam) {
return Result.tryCatch(() -> {
// check internal persistent write-lock
final ExamRecord oldRecord = this.examRecordMapper.selectByPrimaryKey(exam.id);
if (BooleanUtils.isTrue(BooleanUtils.toBooleanObject(oldRecord.getUpdating()))) {
throw new IllegalStateException("Exam is currently locked: " + String.valueOf(exam));
}
final ExamRecord examRecord = new ExamRecord(
exam.id,
null, null, null, null,
@ -376,7 +382,7 @@ public class ExamDAOImpl implements ExamDAO {
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public Result<Exam> placeLock(final Long examId, final String update) {
public Result<Exam> placeLock(final Long examId, final String updateId) {
return Result.tryCatch(() -> {
final ExamRecord examRec = this.recordById(examId)
@ -391,7 +397,7 @@ public class ExamDAOImpl implements ExamDAO {
examId,
null, null, null, null, null, null, null, null, null, null,
BooleanUtils.toInteger(true),
update,
updateId,
null);
this.examRecordMapper.updateByPrimaryKeySelective(newRecord);
@ -404,7 +410,7 @@ public class ExamDAOImpl implements ExamDAO {
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public Result<Exam> releaseLock(final Long examId, final String update) {
public Result<Exam> releaseLock(final Long examId, final String updateId) {
return Result.tryCatch(() -> {
final ExamRecord examRec = this.recordById(examId)
@ -412,7 +418,7 @@ public class ExamDAOImpl implements ExamDAO {
// consistency check
if (BooleanUtils.isFalse(BooleanUtils.toBooleanObject(examRec.getUpdating()))
|| !update.equals(examRec.getLastupdate())) {
|| !updateId.equals(examRec.getLastupdate())) {
throw new IllegalStateException("Exam to end update is not in expected state: " + examRec);
}
@ -421,7 +427,7 @@ public class ExamDAOImpl implements ExamDAO {
examId,
null, null, null, null, null, null, null, null, null, null,
BooleanUtils.toInteger(false),
update,
updateId,
null);
this.examRecordMapper.updateByPrimaryKeySelective(newRecord);
@ -461,13 +467,13 @@ public class ExamDAOImpl implements ExamDAO {
@Override
@Transactional(readOnly = true)
public Result<Boolean> upToDate(final Long examId, final String lastUpdate) {
public Result<Boolean> upToDate(final Long examId, final String updateId) {
return this.recordById(examId)
.map(rec -> {
if (lastUpdate == null) {
if (updateId == null) {
return rec.getLastupdate() == null;
} else {
return lastUpdate.equals(rec.getLastupdate());
return updateId.equals(rec.getLastupdate());
}
});
}

View file

@ -40,7 +40,7 @@ import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ThresholdRecordDy
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ThresholdRecordMapper;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.IndicatorRecord;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ThresholdRecord;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.DAOLoggingSupport;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.IndicatorDAO;

View file

@ -36,7 +36,7 @@ import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.InstitutionRecordDynamicSqlSupport;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.InstitutionRecordMapper;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.InstitutionRecord;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.DAOLoggingSupport;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.InstitutionDAO;

View file

@ -37,7 +37,7 @@ import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.LmsSetupRecordDynamicSqlSupport;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.LmsSetupRecordMapper;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.LmsSetupRecord;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.client.ClientCredentialService;
import ch.ethz.seb.sebserver.webservice.servicelayer.client.ClientCredentials;
import ch.ethz.seb.sebserver.webservice.servicelayer.client.ProxyData;

View file

@ -40,7 +40,7 @@ import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.SebClientConfigRe
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.SebClientConfigRecordMapper;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.AdditionalAttributeRecord;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.SebClientConfigRecord;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.client.ClientCredentialService;
import ch.ethz.seb.sebserver.webservice.servicelayer.client.ClientCredentials;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.DAOLoggingSupport;

View file

@ -55,7 +55,7 @@ import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.UserRecordMapper;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.RoleRecord;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.UserRecord;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.impl.SEBServerUser;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.DAOLoggingSupport;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.TransactionHandler;

View file

@ -199,20 +199,15 @@ public class OpenEdxCourseRestriction {
final HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
return () -> {
try {
final OpenEdxCourseRestrictionData body = this.restTemplate.exchange(
url,
HttpMethod.PUT,
new HttpEntity<>(toJson(restriction), httpHeaders),
OpenEdxCourseRestrictionData.class)
.getBody();
final OpenEdxCourseRestrictionData body = this.restTemplate.exchange(
url,
HttpMethod.PUT,
new HttpEntity<>(toJson(restriction), httpHeaders),
OpenEdxCourseRestrictionData.class)
.getBody();
if (log.isDebugEnabled()) {
log.debug("Successfully PUT SEB Client restriction on course: {} : {}", courseId, body);
}
} catch (final Exception e) {
log.error("Unexpected error while trying to call API for PUT. Course: ", courseId, e);
return false;
if (log.isDebugEnabled()) {
log.debug("Successfully PUT SEB Client restriction on course: {} : {}", courseId, body);
}
return true;
@ -223,23 +218,18 @@ public class OpenEdxCourseRestriction {
final String url = this.lmsSetup.lmsApiUrl + getSebRestrictionUrl(courseId);
return () -> {
try {
final ResponseEntity<Object> exchange = this.restTemplate.exchange(
url,
HttpMethod.DELETE,
new HttpEntity<>(new HttpHeaders()),
Object.class);
final ResponseEntity<Object> exchange = this.restTemplate.exchange(
url,
HttpMethod.DELETE,
new HttpEntity<>(new HttpHeaders()),
Object.class);
if (exchange.getStatusCode() == HttpStatus.NO_CONTENT) {
if (log.isDebugEnabled()) {
log.debug("Successfully PUT SEB Client restriction on course: {}", courseId);
}
} else {
log.error("Unexpected response for deletion: {}", exchange);
return false;
if (exchange.getStatusCode() == HttpStatus.NO_CONTENT) {
if (log.isDebugEnabled()) {
log.debug("Successfully PUT SEB Client restriction on course: {}", courseId);
}
} catch (final Exception e) {
log.error("Unexpected error while trying to call API for DELETE. Course: ", courseId, e);
} else {
log.error("Unexpected response for deletion: {}", exchange);
return false;
}

View file

@ -19,7 +19,7 @@ import org.springframework.security.oauth2.provider.ClientDetails;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SebClientConfig;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionEvent;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl.BulkActionEvent;
public interface ClientConfigService {

View file

@ -42,8 +42,8 @@ import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.webservice.WebserviceInfo;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionEvent;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl.BulkActionEvent;
import ch.ethz.seb.sebserver.webservice.servicelayer.client.ClientCredentialService;
import ch.ethz.seb.sebserver.webservice.servicelayer.client.ClientCredentials;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.InstitutionDAO;

View file

@ -26,8 +26,8 @@ import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationService;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.UserService;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionService;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ActivatableEntityDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;

View file

@ -44,8 +44,8 @@ import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationService;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.UserService;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionService;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.EntityDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;

View file

@ -81,6 +81,14 @@ sebserver.dialog.confirm.title=Confirmation
sebserver.dialog.confirm.deactivation=Note that there are {0} other entities that belongs to this entity.<br/>Those will also be deactivated by deactivating this entity.<br/><br/>Are You sure to deactivate this entity?
sebserver.dialog.confirm.deactivation.noDependencies=Are You sure you want to deactivate?
sebserver.error.action.unexpected.message=<br/><br/>Failed to process action. There was an unexpected error.<br/> Please try again or contact a system-administrator if this error persists
sebserver.error.get.entity=<br/><br/>Failed to load {0}.<br/> Please try again or contact a system-administrator if this error persists
sebserver.error.remove.entity=<br/><br/>Failed to remove {0}.<br/> Please try again or contact a system-administrator if this error persists
sebserver.error.activate.entity=<br/><br/>Failed to activate/deactivate {0}.<br/> Please try again or contact a system-administrator if this error persists
sebserver.error.save.entity=<br/><br/>Failed to save {0}.<br/> Please try again or contact a system-administrator if this error persists
sebserver.error.exam.seb.restriction=<br/><br/>Failed to automatically set Safe Exam Browser restriction on/off for this exam on the corresponding LMS.<br/> Please check the LMS Setup and try again or contact a system-administrator if this error persists
sebserver.error.import=<br/><br/>Failed to import {0}.<br/> Please try again or contact a system-administrator if this error persists
sebserver.error.logout=<br/><br/>Failed to logout properly.<br/> Please try again or contact a system-administrator if this error persists
################################
# Login Page
################################