SEBSERV-44 SEBSERV-45 validation on back end

This commit is contained in:
anhefti 2019-04-30 21:39:59 +02:00
parent 8bbf515717
commit f4af098a6f
7 changed files with 230 additions and 87 deletions

View file

@ -9,7 +9,6 @@
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
import java.util.Collection;
import java.util.function.Consumer;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.swt.SWT;
@ -85,59 +84,26 @@ public class TextFieldBuilder implements InputFieldBuilder {
errorLabel.setVisible(false);
errorLabel.setData(RWT.CUSTOM_VARIANT, "error");
addValueChangeListener(
text,
attribute,
orientation,
viewContext);
return new TextInputField(attribute, orientation, text, errorLabel);
}
private void addValueChangeListener(
final Text control,
final ConfigurationAttribute attribute,
final Orientation orientation,
final ViewContext viewContext) {
final TextInputField textInputField = new TextInputField(attribute, orientation, text, errorLabel);
final ValueChangeListener valueListener = viewContext.getValueChangeListener();
if (attribute.type == AttributeType.INTEGER) {
addNumberCheckListener(control, attribute, s -> Integer.parseInt(s), viewContext);
} else if (attribute.type == AttributeType.DECIMAL) {
addNumberCheckListener(control, attribute, s -> Double.parseDouble(s), viewContext);
} else {
control.addListener(
SWT.FocusOut,
event -> valueListener.valueChanged(
text.addListener(
SWT.FocusOut,
event -> {
textInputField.clearError();
valueListener.valueChanged(
viewContext,
attribute,
String.valueOf(control.getText()),
0));
}
}
String.valueOf(text.getText()),
textInputField.listIndex);
});
private void addNumberCheckListener(
final Text control,
final ConfigurationAttribute attribute,
final Consumer<String> numberCheck,
final ViewContext viewContext) {
final ValueChangeListener valueListener = viewContext.getValueChangeListener();
control.addListener(SWT.FocusOut, event -> {
try {
final String text = control.getText();
numberCheck.accept(text);
viewContext.clearError(attribute.id);
valueListener.valueChanged(viewContext, attribute, text, 0);
} catch (final NumberFormatException e) {
viewContext.showError(attribute.id, "Not A Number");
}
});
return textInputField;
}
static final class TextInputField extends ControlFieldAdapter<Text> {
private String initValue = "";
private int listIndex = 0;
TextInputField(
final ConfigurationAttribute attribute,
@ -155,6 +121,7 @@ public class TextFieldBuilder implements InputFieldBuilder {
.findFirst()
.map(v -> {
this.initValue = v.value;
this.listIndex = (v.listIndex != null) ? v.listIndex : 0;
setDefaultValue();
return this.initValue;
});

View file

@ -33,6 +33,7 @@ import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValue;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ConfigurationAttributeRecordDynamicSqlSupport;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ConfigurationAttributeRecordMapper;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ConfigurationRecordMapper;
@ -156,9 +157,29 @@ public class ConfigurationValueDAOImpl implements ConfigurationValueDAO {
.flatMap(this::attributeRecord)
.map(attributeRecord -> {
final Long id;
if (data.id == null) {
id = this.configurationValueRecordMapper.selectIdsByExample()
.where(
ConfigurationValueRecordDynamicSqlSupport.configurationId,
isEqualTo(data.configurationId))
.and(
ConfigurationValueRecordDynamicSqlSupport.configurationAttributeId,
isEqualTo(data.attributeId))
.and(
ConfigurationValueRecordDynamicSqlSupport.listIndex,
isEqualTo(data.listIndex))
.build()
.execute()
.stream()
.collect(Utils.toSingleton());
} else {
id = data.id;
}
final boolean bigValue = isBigValue(attributeRecord);
final ConfigurationValueRecord newRecord = new ConfigurationValueRecord(
data.id,
id,
null,
null,
null,
@ -166,13 +187,8 @@ public class ConfigurationValueDAOImpl implements ConfigurationValueDAO {
(bigValue) ? null : data.value,
(bigValue) ? data.value : null);
if (data.id != null) {
this.configurationValueRecordMapper.updateByPrimaryKeySelective(newRecord);
} else {
saveByMatch(data, newRecord);
}
return this.configurationValueRecordMapper.selectByPrimaryKey(data.id);
this.configurationValueRecordMapper.updateByPrimaryKeySelective(newRecord);
return this.configurationValueRecordMapper.selectByPrimaryKey(id);
})
.flatMap(ConfigurationValueDAOImpl::toDomainModel)
.onError(TransactionHandler::rollback);
@ -424,29 +440,4 @@ public class ConfigurationValueDAOImpl implements ConfigurationValueDAO {
return data;
}
/** Try to identify and save attribute value by configurationId and configurationAttributeId and listIndex
*
* @param data
* @param newRecord
* @throws ResourceNotFoundException if no matching attribute value was found */
private void saveByMatch(final ConfigurationValue data, final ConfigurationValueRecord newRecord) {
final Integer execute = this.configurationValueRecordMapper.updateByExample(newRecord)
.where(
ConfigurationValueRecordDynamicSqlSupport.configurationId,
isEqualTo(data.configurationId))
.and(
ConfigurationValueRecordDynamicSqlSupport.configurationAttributeId,
isEqualTo(data.attributeId))
.and(
ConfigurationValueRecordDynamicSqlSupport.listIndex,
isEqualTo(data.listIndex))
.build()
.execute();
if (execute == null || execute < 0) {
throw new ResourceNotFoundException(EntityType.CONFIGURATION_VALUE, data.toString());
}
}
}

View file

@ -0,0 +1,41 @@
/*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig;
import ch.ethz.seb.sebserver.gbl.api.APIMessage.FieldValidationException;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
public interface ConfigurationValueValidator {
public static final String MESSAGE_VALUE_OBJECT_NAME = "examConfigValue";
String name();
boolean validate(
ConfigurationValue value,
ConfigurationAttribute attribute);
default void throwValidationError(
final ConfigurationValue value,
final ConfigurationAttribute attribute) {
throw new FieldValidationException(
attribute.name,
this.createErrorMessage(value, attribute));
}
default String createErrorMessage(
final ConfigurationValue value,
final ConfigurationAttribute attribute) {
return "examConfigValue:" + attribute.name + ":" + name() + ":" + value.listIndex;
}
}

View file

@ -0,0 +1,20 @@
/*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValue;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
public interface SebExamConfigService {
void validate(ConfigurationValue value);
void validate(ConfigurationTableValue tableValue);
}

View file

@ -0,0 +1,55 @@
/*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ConfigurationValueValidator;
@Lazy
@Component
@WebServiceProfile
public class IntegerTypeValueValidator implements ConfigurationValueValidator {
@Override
public String name() {
return AttributeType.INTEGER.name();
}
@Override
public boolean validate(
final ConfigurationValue value,
final ConfigurationAttribute attribute) {
// if value is not an integer type or another specific validation is defined --> skip
if (attribute.type != AttributeType.INTEGER ||
StringUtils.isNoneBlank(attribute.validator)) {
return true;
}
if (StringUtils.isBlank(value.value)) {
return true;
}
try {
Integer.parseInt(value.value);
return true;
} catch (final NumberFormatException nfe) {
return false;
}
}
}

View file

@ -0,0 +1,61 @@
/*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl;
import java.util.Collection;
import java.util.Objects;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValue;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ConfigurationAttributeDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ConfigurationValueValidator;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebExamConfigService;
@Lazy
@Service
@WebServiceProfile
public class SebExamConfigServiceImpl implements SebExamConfigService {
private final ConfigurationAttributeDAO configurationAttributeDAO;
private final Collection<ConfigurationValueValidator> validators;
protected SebExamConfigServiceImpl(
final ConfigurationAttributeDAO configurationAttributeDAO,
final Collection<ConfigurationValueValidator> validators) {
this.configurationAttributeDAO = configurationAttributeDAO;
this.validators = validators;
}
@Override
public void validate(final ConfigurationValue value) {
Objects.requireNonNull(value);
final ConfigurationAttribute attribute = this.configurationAttributeDAO.byPK(value.attributeId)
.getOrThrow();
this.validators
.stream()
.filter(validator -> !validator.validate(value, attribute))
.findFirst()
.ifPresent(validator -> validator.throwValidationError(value, attribute));
}
@Override
public void validate(final ConfigurationTableValue tableValue) {
// TODO Auto-generated method stub
}
}

View file

@ -35,6 +35,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionServic
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ConfigurationDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ConfigurationValueDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebExamConfigService;
import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationService;
@WebServiceProfile
@ -44,6 +45,7 @@ public class ConfigurationValueController extends EntityController<Configuration
private final ConfigurationDAO configurationDAO;
private final ConfigurationValueDAO configurationValueDAO;
private final SebExamConfigService sebExamConfigService;
protected ConfigurationValueController(
final AuthorizationService authorization,
@ -52,7 +54,8 @@ public class ConfigurationValueController extends EntityController<Configuration
final UserActivityLogDAO userActivityLogDAO,
final PaginationService paginationService,
final BeanValidationService beanValidationService,
final ConfigurationDAO configurationDAO) {
final ConfigurationDAO configurationDAO,
final SebExamConfigService sebExamConfigService) {
super(authorization,
bulkActionService,
@ -63,6 +66,7 @@ public class ConfigurationValueController extends EntityController<Configuration
this.configurationDAO = configurationDAO;
this.configurationValueDAO = entityDAO;
this.sebExamConfigService = sebExamConfigService;
}
@Override
@ -138,17 +142,21 @@ public class ConfigurationValueController extends EntityController<Configuration
_entity = entity;
}
// test either id or (configurationId and attributeId and listIndex) are set
if (_entity.id != null ||
(_entity.configurationId != null &&
_entity.attributeId != null &&
_entity.listIndex != null)) {
// ConfigurationValue identity constraint
// test either id or (configurationId and attributeId and listIndex) must be set
final boolean idSet = _entity.id != null;
final boolean idsSet = _entity.configurationId != null &&
_entity.attributeId != null &&
_entity.listIndex != null;
if (!idSet && !idsSet) {
throw new IllegalAPIArgumentException(
"Missing some mandatory attributes. Either id must be set or all of configurationId, attributeId and listIndex");
return _entity;
}
throw new IllegalAPIArgumentException(
"Missing some mandatory attributes. Either id must be set or all of configurationId, attributeId and listIndex");
// apply field type validation
this.sebExamConfigService.validate(_entity);
return _entity;
});
}