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); 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) { public static String toHTML(final Collection<APIMessage> messages) {
final StringBuilder builder = new StringBuilder(); final StringBuilder builder = new StringBuilder();
builder.append("<b>Messages:</b><br/><br/>"); 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); org.springframework.http.MediaType.APPLICATION_JSON_UTF8_VALUE);
return headers; 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.Constants;
import ch.ethz.seb.sebserver.gbl.api.API; 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.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration; import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration;
@ -96,131 +97,138 @@ public class ConfigTemplateAttributeForm implements TemplateComposer {
final EntityKey templateKey = pageContext.getParentEntityKey(); final EntityKey templateKey = pageContext.getParentEntityKey();
final Long templateId = Long.valueOf(templateKey.modelId); final Long templateId = Long.valueOf(templateKey.modelId);
final ConfigurationNode template = this.restService try {
.getBuilder(GetExamConfigNode.class)
.withURIVariable(API.PARAM_MODEL_ID, templateKey.modelId)
.call()
.get(pageContext::notifyError);
final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(template); final ConfigurationNode template = this.restService
final boolean modifyGrant = entityGrant.m(); .getBuilder(GetExamConfigNode.class)
.withURIVariable(API.PARAM_MODEL_ID, templateKey.modelId)
.call()
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_NODE, error))
.getOrThrow();
// the attribute final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(template);
final TemplateAttribute attribute = this.restService.getBuilder(GetTemplateAttribute.class) final boolean modifyGrant = entityGrant.m();
.withURIVariable(API.PARAM_PARENT_MODEL_ID, templateKey.modelId)
.withURIVariable(API.PARAM_MODEL_ID, attributeKey.modelId)
.call()
.getOrThrow();
// the follow-up configuration // the attribute
final Configuration configuration = this.restService.getBuilder(GetConfigurations.class) final TemplateAttribute attribute = this.restService.getBuilder(GetTemplateAttribute.class)
.withQueryParam(Configuration.FILTER_ATTR_CONFIGURATION_NODE_ID, templateKey.getModelId()) .withURIVariable(API.PARAM_PARENT_MODEL_ID, templateKey.modelId)
.withQueryParam(Configuration.FILTER_ATTR_FOLLOWUP, Constants.TRUE_STRING) .withURIVariable(API.PARAM_MODEL_ID, attributeKey.modelId)
.call() .call()
.map(Utils::toSingleton) .onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_NODE, error))
.onError(pageContext::notifyError) .getOrThrow();
.getOrThrow();
// the default page layout with title // the follow-up configuration
final Composite content = widgetFactory.defaultPageLayout( final Configuration configuration = this.restService.getBuilder(GetConfigurations.class)
pageContext.getParent(), .withQueryParam(Configuration.FILTER_ATTR_CONFIGURATION_NODE_ID, templateKey.getModelId())
FORM_TITLE); .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( final boolean hasView = attribute.getOrientation() != null;
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();
widgetFactory.labelLocalized( this.pageService.formBuilder(
content, formContext, 4)
CustomVariant.TEXT_H2, .readonly(true) // TODO change this for next version
FORM_VALUE_TEXT_KEY); .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); widgetFactory.labelLocalized(
grid.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); content,
grid.setLayout(new GridLayout(6, true)); 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 PageContext valueContext = formContext.copyOf(grid);
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 InputFieldBuilder inputFieldBuilder = this.examConfigurationService.getInputFieldBuilder( final Orientation defaultOrientation = getDefaultOrientation(attribute);
attribute.getConfigAttribute(), final AttributeMapping attributeMapping = this.examConfigurationService
defaultOrientation); .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( final InputFieldBuilder inputFieldBuilder = this.examConfigurationService.getInputFieldBuilder(
content, attribute.getConfigAttribute(),
attribute.getConfigAttribute(), defaultOrientation);
viewContext);
viewContext.registerInputField(createInputField); final InputField createInputField = inputFieldBuilder.createInputField(
content,
attribute.getConfigAttribute(),
viewContext);
this.examConfigurationService.initInputFieldValues( viewContext.registerInputField(createInputField);
configuration.id,
Arrays.asList(viewContext));
this.pageService.pageActionBuilder(formContext.clearEntityKeys()) this.examConfigurationService.initInputFieldValues(
configuration.id,
Arrays.asList(viewContext));
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_FORM_SET_DEFAULT) this.pageService.pageActionBuilder(formContext.clearEntityKeys())
.withEntityKey(attributeKey)
.withParentEntityKey(templateKey)
.withExec(this.examConfigurationService::resetToDefaults)
.ignoreMoveAwayFromEdit()
.publishIf(() -> modifyGrant)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_REMOVE_VIEW) .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_FORM_SET_DEFAULT)
.withEntityKey(attributeKey) .withEntityKey(attributeKey)
.withParentEntityKey(templateKey) .withParentEntityKey(templateKey)
.withExec(this.examConfigurationService::removeFromView) .withExec(this.examConfigurationService::resetToDefaults)
.ignoreMoveAwayFromEdit() .ignoreMoveAwayFromEdit()
.publishIf(() -> modifyGrant && hasView) .publishIf(() -> modifyGrant)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_ATTACH_DEFAULT_VIEW) .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_REMOVE_VIEW)
.withEntityKey(attributeKey) .withEntityKey(attributeKey)
.withParentEntityKey(templateKey) .withParentEntityKey(templateKey)
.withExec(this.examConfigurationService::attachToDefaultView) .withExec(this.examConfigurationService::removeFromView)
.ignoreMoveAwayFromEdit() .ignoreMoveAwayFromEdit()
.publishIf(() -> modifyGrant && !hasView) .publishIf(() -> modifyGrant && hasView)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_FORM_EDIT_TEMPLATE) .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_ATTACH_DEFAULT_VIEW)
.withEntityKey(templateKey) .withEntityKey(attributeKey)
.ignoreMoveAwayFromEdit() .withParentEntityKey(templateKey)
.publish(); .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) { private Orientation getDefaultOrientation(final TemplateAttribute attribute) {

View file

@ -9,13 +9,12 @@
package ch.ethz.seb.sebserver.gui.content; package ch.ethz.seb.sebserver.gui.content;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.Constants;
import ch.ethz.seb.sebserver.gbl.api.API; 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.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode;
@ -53,8 +52,6 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@GuiProfile @GuiProfile
public class ConfigTemplateForm implements TemplateComposer { public class ConfigTemplateForm implements TemplateComposer {
private static final Logger log = LoggerFactory.getLogger(ConfigTemplateForm.class);
private static final LocTextKey FORM_TITLE_NEW = private static final LocTextKey FORM_TITLE_NEW =
new LocTextKey("sebserver.configtemplate.form.title.new"); new LocTextKey("sebserver.configtemplate.form.title.new");
private static final LocTextKey FORM_TITLE = private static final LocTextKey FORM_TITLE =
@ -118,14 +115,8 @@ public class ConfigTemplateForm implements TemplateComposer {
.getBuilder(GetExamConfigNode.class) .getBuilder(GetExamConfigNode.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId) .withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call() .call()
.get(pageContext::notifyError); .onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_NODE, error))
.getOrThrow();
if (examConfig == null) {
log.error("Failed to get ConfigurationNode for Template. "
+ "Error was notified to the User. "
+ "See previous logs for more infomation");
return;
}
final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(examConfig); final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(examConfig);
final boolean writeGrant = entityGrant.w(); 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); 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 = private static final LocTextKey CONFIG_EMPTY_LIST_MESSAGE =
new LocTextKey("sebserver.exam.configuration.list.empty"); new LocTextKey("sebserver.exam.configuration.list.empty");
private static final LocTextKey INDICATOR_EMPTY_LIST_MESSAGE = 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 = private final static LocTextKey CONSISTENCY_MESSAGE_MISSING_SEB_RESTRICTION =
new LocTextKey("sebserver.exam.consistency.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 Map<String, LocTextKey> consistencyMessageMapping;
private final static LocTextKey CONFIRM_MESSAGE_REMOVE_CONFIG = private final static LocTextKey CONFIRM_MESSAGE_REMOVE_CONFIG =
@ -199,15 +206,8 @@ public class ExamForm implements TemplateComposer {
final Exam exam = (importFromQuizData final Exam exam = (importFromQuizData
? createExamFromQuizData(pageContext) ? createExamFromQuizData(pageContext)
: getExistingExam(pageContext)) : getExistingExam(pageContext))
.get(pageContext::notifyError); .onError(error -> pageContext.notifyLoadError(EntityType.EXAM, error))
.getOrThrow();
if (exam == null) {
log.error(
"Failed to get Exam. "
+ "Error was notified to the User. "
+ "See previous logs for more infomation");
return;
}
// new PageContext with actual EntityKey // new PageContext with actual EntityKey
final PageContext formContext = pageContext.withEntityKey(exam.getEntityKey()); final PageContext formContext = pageContext.withEntityKey(exam.getEntityKey());
@ -221,10 +221,9 @@ public class ExamForm implements TemplateComposer {
} }
// the default page layout with title // the default page layout with title
final LocTextKey titleKey = new LocTextKey( final LocTextKey titleKey = importFromQuizData
importFromQuizData ? EXAM_FORM_TITLE_IMPORT_KEY
? "sebserver.exam.form.title.import" : EXAM_FORM_TITLE_KEY;
: "sebserver.exam.form.title");
final Composite content = this.widgetFactory.defaultPageLayout( final Composite content = this.widgetFactory.defaultPageLayout(
formContext.getParent(), formContext.getParent(),
titleKey); titleKey);
@ -579,7 +578,10 @@ public class ExamForm implements TemplateComposer {
} }
private PageAction setSebRestriction(final PageAction action, final boolean sebRestriction) { 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( private PageAction setSebRestriction(
@ -685,7 +687,7 @@ public class ExamForm implements TemplateComposer {
.getBuilder(DeleteExamConfigMapping.class) .getBuilder(DeleteExamConfigMapping.class)
.withURIVariable(API.PARAM_MODEL_ID, examConfigMappingKey.modelId) .withURIVariable(API.PARAM_MODEL_ID, examConfigMappingKey.modelId)
.call() .call()
.onError(error -> action.pageContext().notifyError(error)); .onError(error -> action.pageContext().notifyRemoveError(EntityType.EXAM_CONFIGURATION_MAP, error));
return action; return action;
} }
@ -693,8 +695,7 @@ public class ExamForm implements TemplateComposer {
final EntityKey entityKey = pageContext.getEntityKey(); final EntityKey entityKey = pageContext.getEntityKey();
return this.restService.getBuilder(GetExam.class) return this.restService.getBuilder(GetExam.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId) .withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call() .call();
.onError(error -> pageContext.notifyError(error));
} }
private Result<Exam> createExamFromQuizData(final PageContext pageContext) { 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) .withQueryParam(QuizData.QUIZ_ATTR_LMS_SETUP_ID, parentEntityKey.modelId)
.call() .call()
.map(quizzData -> new Exam(quizzData)) .map(quizzData -> new Exam(quizzData))
.onError(error -> pageContext.notifyError(error)); .onError(error -> pageContext.notifyLoadError(EntityType.EXAM, error));
} }
private String indicatorTypeName(final Indicator indicator) { private String indicatorTypeName(final Indicator indicator) {

View file

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

View file

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

View file

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

View file

@ -13,13 +13,12 @@ import java.util.function.Function;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.Constants;
import ch.ethz.seb.sebserver.gbl.api.API; 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.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup; import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
@ -61,7 +60,10 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@GuiProfile @GuiProfile
public class LmsSetupForm implements TemplateComposer { 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 = private static final LocTextKey FORM_SECRET_LMS_TEXT_KEY =
new LocTextKey("sebserver.lmssetup.form.secret.lms"); new LocTextKey("sebserver.lmssetup.form.secret.lms");
@ -120,23 +122,15 @@ public class LmsSetupForm implements TemplateComposer {
.getBuilder(GetLmsSetup.class) .getBuilder(GetLmsSetup.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId) .withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call() .call()
.get(pageContext::notifyError); .onError(error -> pageContext.notifyLoadError(EntityType.LMS_SETUP, error))
.getOrThrow();
if (lmsSetup == null) {
log.error(
"Failed to get LmsSetup. "
+ "Error was notified to the User. "
+ "See previous logs for more infomation");
return;
}
// new PageContext with actual EntityKey // new PageContext with actual EntityKey
final PageContext formContext = pageContext.withEntityKey(lmsSetup.getEntityKey()); final PageContext formContext = pageContext.withEntityKey(lmsSetup.getEntityKey());
// the default page layout with title // the default page layout with title
final LocTextKey titleKey = new LocTextKey( final LocTextKey titleKey = isNotNew.getAsBoolean()
isNotNew.getAsBoolean() ? TITLE_TEXT_KEY
? "sebserver.lmssetup.form.title" : NEW_TITLE_TEXT_KEY;
: "sebserver.lmssetup.form.title.new");
final Composite content = widgetFactory.defaultPageLayout( final Composite content = widgetFactory.defaultPageLayout(
formContext.getParent(), formContext.getParent(),
titleKey); titleKey);
@ -302,7 +296,7 @@ public class LmsSetupForm implements TemplateComposer {
API.PARAM_MODEL_ID, API.PARAM_MODEL_ID,
action.pageContext().getAttribute(AttributeKeys.ENTITY_ID)) action.pageContext().getAttribute(AttributeKeys.ENTITY_ID))
.call() .call()
.onError(t -> action.pageContext().notifyError(t)); .onError(error -> action.pageContext().notifyActivationError(EntityType.LMS_SETUP, error));
return testLmsSetup; 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.RWT;
import org.eclipse.rap.rwt.client.service.UrlLauncher; import org.eclipse.rap.rwt.client.service.UrlLauncher;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value; 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.api.API; 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.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SebClientConfig; import ch.ethz.seb.sebserver.gbl.model.sebconfig.SebClientConfig;
@ -49,8 +48,6 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@GuiProfile @GuiProfile
public class SebClientConfigForm implements TemplateComposer { public class SebClientConfigForm implements TemplateComposer {
private static final Logger log = LoggerFactory.getLogger(LmsSetupForm.class);
private static final LocTextKey FORM_TITLE_NEW = private static final LocTextKey FORM_TITLE_NEW =
new LocTextKey("sebserver.clientconfig.form.title.new"); new LocTextKey("sebserver.clientconfig.form.title.new");
private static final LocTextKey FORM_TITLE = private static final LocTextKey FORM_TITLE =
@ -106,14 +103,8 @@ public class SebClientConfigForm implements TemplateComposer {
.getBuilder(GetClientConfig.class) .getBuilder(GetClientConfig.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId) .withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call() .call()
.get(pageContext::notifyError); .onError(error -> pageContext.notifyLoadError(EntityType.SEB_CLIENT_CONFIGURATION, error))
.getOrThrow();
if (clientConfig == null) {
log.error("Failed to get SebClientConfig. "
+ "Error was notified to the User. "
+ "See previous logs for more infomation");
return;
}
final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(clientConfig); final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(clientConfig);
final boolean writeGrant = entityGrant.w(); 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.API;
import ch.ethz.seb.sebserver.gbl.api.APIMessage; 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.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration; import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration;
@ -177,13 +178,16 @@ final class SebExamConfigImportPopup {
} else { } else {
formHandle formHandle
.getContext() .getContext()
.notifyError(error); .notifyImportError(EntityType.CONFIGURATION_NODE, error);
} }
}); });
return true; return true;
} }
formHandle.getContext().notifyError(configuration.getError()); formHandle.getContext().notifyError(
SebExamConfigPropForm.FORM_TITLE,
configuration.getError());
return true; return true;
} }
} else { } else {
@ -195,7 +199,7 @@ final class SebExamConfigImportPopup {
return false; return false;
} catch (final Exception e) { } catch (final Exception e) {
formHandle.getContext().notifyError(e); formHandle.getContext().notifyError(SebExamConfigPropForm.FORM_TITLE, e);
return true; 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.SWT;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.Text;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value; 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;
@ -71,8 +69,6 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
@GuiProfile @GuiProfile
public class SebExamConfigPropForm implements TemplateComposer { public class SebExamConfigPropForm implements TemplateComposer {
private static final Logger log = LoggerFactory.getLogger(SebExamConfigPropForm.class);
static final LocTextKey FORM_TITLE_NEW = static final LocTextKey FORM_TITLE_NEW =
new LocTextKey("sebserver.examconfig.form.title.new"); new LocTextKey("sebserver.examconfig.form.title.new");
static final LocTextKey FORM_TITLE = static final LocTextKey FORM_TITLE =
@ -139,13 +135,8 @@ public class SebExamConfigPropForm implements TemplateComposer {
.getBuilder(GetExamConfigNode.class) .getBuilder(GetExamConfigNode.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId) .withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call() .call()
.get(pageContext::notifyError); .onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_NODE, error))
if (examConfig == null) { .getOrThrow();
log.error("Failed to get ConfigurationNode. "
+ "Error was notified to the User. "
+ "See previous logs for more infomation");
return;
}
final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(examConfig); final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(examConfig);
final boolean writeGrant = entityGrant.w(); final boolean writeGrant = entityGrant.w();

View file

@ -102,7 +102,7 @@ public class SebExamConfigSettingsForm implements TemplateComposer {
final ConfigurationNode configNode = this.restService.getBuilder(GetExamConfigNode.class) final ConfigurationNode configNode = this.restService.getBuilder(GetExamConfigNode.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId) .withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call() .call()
.onError(pageContext::notifyError) .onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_NODE, error))
.getOrThrow(); .getOrThrow();
final Configuration configuration = this.restService.getBuilder(GetConfigurations.class) 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) .withQueryParam(Configuration.FILTER_ATTR_FOLLOWUP, Constants.TRUE_STRING)
.call() .call()
.map(Utils::toSingleton) .map(Utils::toSingleton)
.onError(pageContext::notifyError) .onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION, error))
.getOrThrow(); .getOrThrow();
final AttributeMapping attributes = this.examConfigurationService final AttributeMapping attributes = this.examConfigurationService
.getAttributes(configNode.templateId) .getAttributes(configNode.templateId)
.onError(pageContext::notifyError) .onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_ATTRIBUTE, error))
.getOrThrow(); .getOrThrow();
final boolean readonly = pageContext.isReadonly() || configNode.status == ConfigurationStatus.IN_USE; final boolean readonly = pageContext.isReadonly() || configNode.status == ConfigurationStatus.IN_USE;
@ -195,11 +195,11 @@ public class SebExamConfigSettingsForm implements TemplateComposer {
.publish(); .publish();
} catch (final RuntimeException e) { } catch (final RuntimeException e) {
log.error("Unexpected error while trying to fetch exam configuration data and create views", e); pageContext.notifyUnexpectedError(e);
throw e; throw e;
} catch (final Exception e) { } catch (final Exception e) {
log.error("Unexpected error while trying to fetch exam configuration data and create views", 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 org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.api.API; 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.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.user.PasswordChange; 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. */ * password that is also required must match the administrators current password. */
public class UserAccountChangePasswordForm implements TemplateComposer { 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 = private static final LocTextKey FORM_PASSWORD_NEW_TEXT_KEY =
new LocTextKey("sebserver.useraccount.form.password.new"); new LocTextKey("sebserver.useraccount.form.password.new");
private static final LocTextKey FORM_PASSWORD_NEW_CONFIRM_TEXT_KEY = private static final LocTextKey FORM_PASSWORD_NEW_CONFIRM_TEXT_KEY =
@ -79,11 +81,12 @@ public class UserAccountChangePasswordForm implements TemplateComposer {
.getBuilder(GetUserAccount.class) .getBuilder(GetUserAccount.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId) .withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call() .call()
.get(pageContext::notifyError); .onError(error -> pageContext.notifyLoadError(EntityType.USER, error))
.getOrThrow();
final Composite content = widgetFactory.defaultPageLayout( final Composite content = widgetFactory.defaultPageLayout(
pageContext.getParent(), 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()); 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.apache.tomcat.util.buf.StringUtils;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -56,23 +54,26 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@GuiProfile @GuiProfile
public class UserAccountForm implements TemplateComposer { 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"); 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"); 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"); 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"); 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"); 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"); 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"); 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"); new LocTextKey("sebserver.useraccount.form.institution");
private final PageService pageService; private final PageService pageService;
@ -110,15 +111,8 @@ public class UserAccountForm implements TemplateComposer {
.getBuilder(GetUserAccount.class) .getBuilder(GetUserAccount.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId) .withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call() .call()
.get(pageContext::notifyError); .onError(error -> pageContext.notifyLoadError(EntityType.USER, error))
.getOrThrow();
if (userAccount == null) {
log.error(
"Failed to get UserAccount. "
+ "Error was notified to the User. "
+ "See previous logs for more infomation");
return;
}
final boolean roleBasedEditGrant = Privilege.hasRoleBasedUserAccountEditGrant(userAccount, currentUser.get()); final boolean roleBasedEditGrant = Privilege.hasRoleBasedUserAccountEditGrant(userAccount, currentUser.get());
// new PageContext with actual EntityKey // new PageContext with actual EntityKey
@ -138,16 +132,10 @@ public class UserAccountForm implements TemplateComposer {
.map(inst -> inst.active) .map(inst -> inst.active)
.getOr(false); .getOr(false);
if (log.isDebugEnabled()) {
log.debug("UserAccount Form for user {}", userAccount.getName());
}
// the default page layout with title // the default page layout with title
final LocTextKey titleKey = new LocTextKey( final LocTextKey titleKey = isNotNew.getAsBoolean()
isNotNew.getAsBoolean() ? TITLE_TEXT_KEY
? "sebserver.useraccount.form.title" : NEW_TITLE_TEXT_KEY;
: "sebserver.useraccount.form.title.new",
userAccount.getUsername());
final Composite content = widgetFactory.defaultPageLayout( final Composite content = widgetFactory.defaultPageLayout(
formContext.getParent(), formContext.getParent(),
titleKey); titleKey);

View file

@ -14,7 +14,9 @@ import java.util.function.Predicate;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; 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.APIMessage;
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.util.Result; import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.gbl.util.Utils; import ch.ethz.seb.sebserver.gbl.util.Utils;
@ -133,8 +135,16 @@ public class FormHandle<T extends Entity> {
fieldAccessor -> showValidationError(fieldAccessor, fve))); fieldAccessor -> showValidationError(fieldAccessor, fve)));
return true; return true;
} else { } else {
log.error("Unexpected error while trying to post form: ", error); log.error("Unexpected error while trying to post form: {}", error.getMessage());
this.pageContext.notifyError(error); 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; return false;
} }
} }

View file

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

View file

@ -233,6 +233,9 @@ public abstract class AbstractTableFieldBuilder implements InputFieldBuilder {
} }
ConfigurationAttribute attr = tableContext.getAttribute(value.attributeId); ConfigurationAttribute attr = tableContext.getAttribute(value.attributeId);
if (attr == null) {
return false;
}
while (attr.parentId != null) { while (attr.parentId != null) {
if (attribute.id.equals(attr.parentId)) { if (attribute.id.equals(attr.parentId)) {
return true; 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.API;
import ch.ethz.seb.sebserver.gbl.api.APIMessage; import ch.ethz.seb.sebserver.gbl.api.APIMessage;
import ch.ethz.seb.sebserver.gbl.api.APIMessage.ErrorMessage; 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.api.JSONMapper;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration; import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration;
@ -373,7 +374,7 @@ public class ExamConfigurationServiceImpl implements ExamConfigurationService {
} }
} catch (final Exception e) { } 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.Logger;
import org.slf4j.LoggerFactory; 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.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.I18nSupport;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; 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 /** Get the I18nSupport service
* *
* @return the I18nSupport service */ * @return the I18nSupport service */
@ -187,14 +200,74 @@ public interface PageContext {
* *
* @param errorMessage the error message to display * @param errorMessage the error message to display
* @param error the error as Exception */ * @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. /** Notify a generic load error to the user by pop-up
* This mainly is used for debugging so far
* *
* @param error the Exception to display * @param entityType the type of the entity
* @return adaption to be used with functional approaches */ * @param error the original error */
<T> T notifyError(Exception 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 /** 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. * 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) { final Class<? extends RestCall<T>> restCallType) {
this.exec = action -> { this.exec = action -> {
final PageContext pageContext = action.pageContext();
restService.getBuilder(restCallType) restService.getBuilder(restCallType)
.withURIVariable( .withURIVariable(
API.PARAM_MODEL_ID, API.PARAM_MODEL_ID,
action.pageContext().getAttribute(AttributeKeys.ENTITY_ID)) action.pageContext().getAttribute(AttributeKeys.ENTITY_ID))
.call() .call()
.onError(t -> action.pageContext().notifyError(t)); .onError(pageContext::notifyUnexpectedError);
return action; 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.Constants;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.util.Result; 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.content.action.ActionDefinition;
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.page.PageContext; 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); 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; public final ActionDefinition definition;
private final Supplier<LocTextKey> confirm; private final Supplier<LocTextKey> confirm;
final LocTextKey successMessage;
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;
@ -44,6 +42,8 @@ public final class PageAction {
final boolean fireActionEvent; final boolean fireActionEvent;
final boolean ignoreMoveAwayFromEdit; final boolean ignoreMoveAwayFromEdit;
final LocTextKey successMessage;
public PageAction( public PageAction(
final ActionDefinition definition, final ActionDefinition definition,
final Supplier<LocTextKey> confirm, 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() { public EntityKey getEntityKey() {
return this.pageContext.getEntityKey(); return this.pageContext.getEntityKey();
} }
@ -144,7 +152,9 @@ public final class PageAction {
final PageAction apply = this.exec.apply(this); final PageAction apply = this.exec.apply(this);
if (this.successMessage != null) { 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); return Result.of(apply);
@ -153,13 +163,23 @@ public final class PageAction {
return Result.ofError(pme); return Result.ofError(pme);
} catch (final RestCallError restCallError) { } catch (final RestCallError restCallError) {
if (!restCallError.isFieldValidationError()) { if (!restCallError.isFieldValidationError()) {
log.error("Failed to execute action: {}", PageAction.this, restCallError); log.error("Failed to execute action: {} | error: {} | cause: {}",
PageAction.this.pageContext.notifyError("action.error.unexpected.message", restCallError); PageAction.this.getName(),
restCallError.getMessage(),
Utils.getErrorCauseMessage(restCallError));
PageAction.this.pageContext.notifyError(
PageContext.UNEXPECTED_ERROR_KEY,
restCallError);
} }
return Result.ofError(restCallError); return Result.ofError(restCallError);
} catch (final Exception e) { } catch (final Exception e) {
log.error("Failed to execute action: {}", PageAction.this, e); log.error("Failed to execute action: {} | error: {} | cause: {}",
PageAction.this.pageContext.notifyError("action.error.unexpected.message", e); PageAction.this.getName(),
e.getMessage(),
Utils.getErrorCauseMessage(e));
PageAction.this.pageContext.notifyError(
PageContext.UNEXPECTED_ERROR_KEY,
e);
return Result.ofError(e); return Result.ofError(e);
} }
} }
@ -179,6 +199,31 @@ public final class PageAction {
return this; 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) { public static PageAction applySingleSelection(final PageAction action) {
return action.withEntityKey(action.getSingleSelection()); return action.withEntityKey(action.getSingleSelection());
} }

View file

@ -280,13 +280,17 @@ public class PageContextImpl implements PageContext {
} }
@Override @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) { if (error instanceof APIMessageError) {
final List<APIMessage> errorMessages = ((APIMessageError) error).getErrorMessages(); final List<APIMessage> errorMessages = ((APIMessageError) error).getErrorMessages();
final MessageBox messageBox = new Message( final MessageBox messageBox = new Message(
getShell(), getShell(),
this.i18nSupport.getText("sebserver.error.unexpected"), this.i18nSupport.getText("sebserver.error.unexpected"),
APIMessage.toHTML(errorMessages), APIMessage.toHTML(errorMessage, errorMessages),
SWT.ERROR); SWT.ERROR);
messageBox.setMarkupEnabled(true); messageBox.setMarkupEnabled(true);
messageBox.open(null); messageBox.open(null);
@ -301,12 +305,6 @@ public class PageContextImpl implements PageContext {
messageBox.open(null); messageBox.open(null);
} }
@Override
public <T> T notifyError(final Exception error) {
notifyError(error.getMessage(), error);
return null;
}
@Override @Override
public String toString() { public String toString() {
return "PageContextImpl [root=" + this.root + ", parent=" + this.parent + ", attributes=" + this.attributes 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 = private static final LocTextKey MSG_GO_AWAY_FROM_EDIT =
new LocTextKey("sebserver.overall.action.goAwayFromEditPageConfirm"); 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 String ATTR_PAGE_STATE = "PAGE_STATE";
private static final ListenerComparator LIST_COMPARATOR = new ListenerComparator(); private static final ListenerComparator LIST_COMPARATOR = new ListenerComparator();
@ -234,7 +236,9 @@ public class PageServiceImpl implements PageService {
if (!logoutSuccessful) { if (!logoutSuccessful) {
log.error("Failed to logout. See logfiles for more information"); 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) { } catch (final Exception e) {

View file

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

View file

@ -393,7 +393,7 @@ public class EntityTable<ROW extends Entity> {
.call() .call()
.map(this::createTableRowsFromPage) .map(this::createTableRowsFromPage)
.map(this.navigator::update) .map(this.navigator::update)
.onError(this.pageContext::notifyError); .onError(this.pageContext::notifyUnexpectedError);
this.composite.getParent().layout(true, true); this.composite.getParent().layout(true, true);
PageService.updateScrolledComposite(this.composite); 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.model.EntityProcessingReport;
import ch.ethz.seb.sebserver.gbl.util.Result; 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 /** 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 * 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.Entity;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.util.Result; 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.ActivatableEntityDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.DAOLoggingSupport; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.DAOLoggingSupport;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.EntityDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.EntityDAO;
/** Defines overall DAO support for bulk-actions like activate, deactivate, delete... /** Defines overall DAO support for bulk-actions like activate, deactivate, delete...
*
* *
* @param <T> The type of the Entity of a concrete BulkActionSupportDAO */ * @param <T> The type of the Entity of a concrete BulkActionSupportDAO */
public interface BulkActionSupportDAO<T extends Entity> { public interface BulkActionSupportDAO<T extends Entity> {

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * 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.Arrays;
import java.util.Collection; import java.util.Collection;

View file

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

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * 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.Arrays;
import java.util.Collection; 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.model.user.UserLogActivityType;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.gbl.util.Result;
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; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;
@Service @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.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.AdditionalAttributeRecord; 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 { 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( Result<Collection<AdditionalAttributeRecord>> getAdditionalAttributes(
EntityType type, EntityType type,
Long entityId); 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( void saveAdditionalAttribute(
EntityType type, EntityType type,
Long entityId, Long entityId,
String name, String name,
String value); String value);
/** Use this to delete an additional attribute by identifier (primary-key)
*
* @param id identifier (primary-key) */
void delete(Long id); 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); 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); 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> { 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( Result<Collection<ExtendedClientEvent>> allMatchingExtended(
FilterMap filterMap, FilterMap filterMap,
Predicate<ExtendedClientEvent> predicate); 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 /** Use this to get all ConfigurationAttribute that are root attributes and no child
* attributes (has no parent reference). * 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(); 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); Result<Collection<ConfigurationAttribute>> allChildAttributes(final Long parentId);
} }

View file

@ -17,6 +17,12 @@ public interface ConfigurationNodeDAO extends
EntityDAO<ConfigurationNode, ConfigurationNode>, EntityDAO<ConfigurationNode, ConfigurationNode>,
BulkActionSupportDAO<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( Result<ConfigurationNode> createCopy(
Long institutionId, Long institutionId,
String newOwner, 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 */ * @return the saved table values of the attribute and configuration */
Result<ConfigurationTableValues> saveTableValues(ConfigurationTableValues value); 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( Result<Set<EntityKey>> setDefaultValues(
Long institutionId, Long institutionId,
Long configurationId, 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 */ * @return a Result containing the Exam by a given ClientConnection id or refer to an error if happened */
Result<Exam> byClientConnection(Long connectionId); 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); 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(); 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<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); 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> 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 */ * @return the configured ClientCredentials for a given LmsSetup */
Result<ClientCredentials> getLmsAPIAccessCredentials(String lmsSetupId); 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); 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.ConfigurationValueRecordDynamicSqlSupport;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ConfigurationValueRecordMapper; 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.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.ConfigurationNodeDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.DAOLoggingSupport; 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.FilterMap;

View file

@ -17,6 +17,7 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.function.Function; 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.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; 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;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues.TableValue; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues.TableValue;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue; 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.FilterMap;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ResourceNotFoundException; 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.dao.TransactionHandler;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ExamConfigInitService;
@Lazy @Lazy
@Component @Component
@ -63,17 +66,20 @@ public class ConfigurationValueDAOImpl implements ConfigurationValueDAO {
private final ConfigurationAttributeRecordMapper configurationAttributeRecordMapper; private final ConfigurationAttributeRecordMapper configurationAttributeRecordMapper;
private final ConfigurationRecordMapper configurationRecordMapper; private final ConfigurationRecordMapper configurationRecordMapper;
private final ConfigurationDAOBatchService configurationDAOBatchService; private final ConfigurationDAOBatchService configurationDAOBatchService;
private final ExamConfigInitService examConfigInitService;
protected ConfigurationValueDAOImpl( protected ConfigurationValueDAOImpl(
final ConfigurationValueRecordMapper configurationValueRecordMapper, final ConfigurationValueRecordMapper configurationValueRecordMapper,
final ConfigurationAttributeRecordMapper configurationAttributeRecordMapper, final ConfigurationAttributeRecordMapper configurationAttributeRecordMapper,
final ConfigurationRecordMapper configurationRecordMapper, final ConfigurationRecordMapper configurationRecordMapper,
final ConfigurationDAOBatchService configurationDAOBatchService) { final ConfigurationDAOBatchService configurationDAOBatchService,
final ExamConfigInitService examConfigInitService) {
this.configurationValueRecordMapper = configurationValueRecordMapper; this.configurationValueRecordMapper = configurationValueRecordMapper;
this.configurationAttributeRecordMapper = configurationAttributeRecordMapper; this.configurationAttributeRecordMapper = configurationAttributeRecordMapper;
this.configurationRecordMapper = configurationRecordMapper; this.configurationRecordMapper = configurationRecordMapper;
this.configurationDAOBatchService = configurationDAOBatchService; this.configurationDAOBatchService = configurationDAOBatchService;
this.examConfigInitService = examConfigInitService;
} }
@Override @Override
@ -388,10 +394,12 @@ public class ConfigurationValueDAOImpl implements ConfigurationValueDAO {
.map(r -> new EntityKey(r.getId(), EntityType.CONFIGURATION_VALUE)) .map(r -> new EntityKey(r.getId(), EntityType.CONFIGURATION_VALUE))
.collect(Collectors.toSet())); .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()) { if (tableValues != null && !tableValues.isEmpty()) {
this.delete(tableValues) this.delete(tableValues)
.getOrThrow(); .getOrThrow();
initTableValues(institutionId, configurationId, attributeId);
} }
} }
@ -413,7 +421,7 @@ public class ConfigurationValueDAOImpl implements ConfigurationValueDAO {
return tableValues; return tableValues;
} else { } else {
if (values.size() > 1) { 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 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 // get all attributes of the table (columns) mapped to attribute id
private Result<Map<Long, ConfigurationAttributeRecord>> getAttributeMapping( private Result<Map<Long, ConfigurationAttributeRecord>> getAttributeMapping(
final ConfigurationAttributeRecord attributeRecord) { 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.ConfigurationNodeRecord;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ExamConfigurationMapRecord; 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.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.client.ClientCredentialService;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.DAOLoggingSupport; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.DAOLoggingSupport;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamConfigurationMapDAO; 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.ExamRecordDynamicSqlSupport;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ExamRecordMapper; 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.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.ExamDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ResourceNotFoundException; 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) { public Result<Exam> save(final Exam exam) {
return Result.tryCatch(() -> { 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( final ExamRecord examRecord = new ExamRecord(
exam.id, exam.id,
null, null, null, null, null, null, null, null,
@ -376,7 +382,7 @@ public class ExamDAOImpl implements ExamDAO {
@Override @Override
@Transactional(propagation = Propagation.REQUIRES_NEW) @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(() -> { return Result.tryCatch(() -> {
final ExamRecord examRec = this.recordById(examId) final ExamRecord examRec = this.recordById(examId)
@ -391,7 +397,7 @@ public class ExamDAOImpl implements ExamDAO {
examId, examId,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
BooleanUtils.toInteger(true), BooleanUtils.toInteger(true),
update, updateId,
null); null);
this.examRecordMapper.updateByPrimaryKeySelective(newRecord); this.examRecordMapper.updateByPrimaryKeySelective(newRecord);
@ -404,7 +410,7 @@ public class ExamDAOImpl implements ExamDAO {
@Override @Override
@Transactional(propagation = Propagation.REQUIRES_NEW) @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(() -> { return Result.tryCatch(() -> {
final ExamRecord examRec = this.recordById(examId) final ExamRecord examRec = this.recordById(examId)
@ -412,7 +418,7 @@ public class ExamDAOImpl implements ExamDAO {
// consistency check // consistency check
if (BooleanUtils.isFalse(BooleanUtils.toBooleanObject(examRec.getUpdating())) 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); throw new IllegalStateException("Exam to end update is not in expected state: " + examRec);
} }
@ -421,7 +427,7 @@ public class ExamDAOImpl implements ExamDAO {
examId, examId,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
BooleanUtils.toInteger(false), BooleanUtils.toInteger(false),
update, updateId,
null); null);
this.examRecordMapper.updateByPrimaryKeySelective(newRecord); this.examRecordMapper.updateByPrimaryKeySelective(newRecord);
@ -461,13 +467,13 @@ public class ExamDAOImpl implements ExamDAO {
@Override @Override
@Transactional(readOnly = true) @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) return this.recordById(examId)
.map(rec -> { .map(rec -> {
if (lastUpdate == null) { if (updateId == null) {
return rec.getLastupdate() == null; return rec.getLastupdate() == null;
} else { } 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.mapper.ThresholdRecordMapper;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.IndicatorRecord; 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.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.DAOLoggingSupport;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.IndicatorDAO; 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.InstitutionRecordDynamicSqlSupport;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.InstitutionRecordMapper; 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.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.DAOLoggingSupport;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.InstitutionDAO; 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.LmsSetupRecordDynamicSqlSupport;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.LmsSetupRecordMapper; 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.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.ClientCredentialService;
import ch.ethz.seb.sebserver.webservice.servicelayer.client.ClientCredentials; import ch.ethz.seb.sebserver.webservice.servicelayer.client.ClientCredentials;
import ch.ethz.seb.sebserver.webservice.servicelayer.client.ProxyData; 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.mapper.SebClientConfigRecordMapper;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.AdditionalAttributeRecord; 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.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.ClientCredentialService;
import ch.ethz.seb.sebserver.webservice.servicelayer.client.ClientCredentials; import ch.ethz.seb.sebserver.webservice.servicelayer.client.ClientCredentials;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.DAOLoggingSupport; 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.RoleRecord;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.UserRecord; 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.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.DAOLoggingSupport;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.TransactionHandler; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.TransactionHandler;

View file

@ -199,20 +199,15 @@ public class OpenEdxCourseRestriction {
final HttpHeaders httpHeaders = new HttpHeaders(); final HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); httpHeaders.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
return () -> { return () -> {
try { final OpenEdxCourseRestrictionData body = this.restTemplate.exchange(
final OpenEdxCourseRestrictionData body = this.restTemplate.exchange( url,
url, HttpMethod.PUT,
HttpMethod.PUT, new HttpEntity<>(toJson(restriction), httpHeaders),
new HttpEntity<>(toJson(restriction), httpHeaders), OpenEdxCourseRestrictionData.class)
OpenEdxCourseRestrictionData.class) .getBody();
.getBody();
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("Successfully PUT SEB Client restriction on course: {} : {}", courseId, body); 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;
} }
return true; return true;
@ -223,23 +218,18 @@ public class OpenEdxCourseRestriction {
final String url = this.lmsSetup.lmsApiUrl + getSebRestrictionUrl(courseId); final String url = this.lmsSetup.lmsApiUrl + getSebRestrictionUrl(courseId);
return () -> { return () -> {
try { final ResponseEntity<Object> exchange = this.restTemplate.exchange(
final ResponseEntity<Object> exchange = this.restTemplate.exchange( url,
url, HttpMethod.DELETE,
HttpMethod.DELETE, new HttpEntity<>(new HttpHeaders()),
new HttpEntity<>(new HttpHeaders()), Object.class);
Object.class);
if (exchange.getStatusCode() == HttpStatus.NO_CONTENT) { if (exchange.getStatusCode() == HttpStatus.NO_CONTENT) {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("Successfully PUT SEB Client restriction on course: {}", courseId); log.debug("Successfully PUT SEB Client restriction on course: {}", courseId);
}
} else {
log.error("Unexpected response for deletion: {}", exchange);
return false;
} }
} catch (final Exception e) { } else {
log.error("Unexpected error while trying to call API for DELETE. Course: ", courseId, e); log.error("Unexpected response for deletion: {}", exchange);
return false; 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.model.sebconfig.SebClientConfig;
import ch.ethz.seb.sebserver.gbl.util.Result; 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 { 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.Result;
import ch.ethz.seb.sebserver.gbl.util.Utils; import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.webservice.WebserviceInfo; import ch.ethz.seb.sebserver.webservice.WebserviceInfo;
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.bulkaction.BulkActionEvent; 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.ClientCredentialService;
import ch.ethz.seb.sebserver.webservice.servicelayer.client.ClientCredentials; import ch.ethz.seb.sebserver.webservice.servicelayer.client.ClientCredentials;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.InstitutionDAO; 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.PaginationService;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationService; 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.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.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.ActivatableEntityDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;

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.PaginationService;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationService; 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.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.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.EntityDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;

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=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.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 # Login Page
################################ ################################