SEBSERV-44 SEBSERV-45 validation on back end
This commit is contained in:
parent
8bbf515717
commit
f4af098a6f
7 changed files with 230 additions and 87 deletions
|
@ -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;
|
||||
});
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue