=== added file 'dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/DefaultValidationService.java' --- dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/DefaultValidationService.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/DefaultValidationService.java 2013-05-17 06:44:41 +0000 @@ -0,0 +1,164 @@ +package org.hisp.dhis.dxf2; + +/* + * Copyright (c) 2004-2013, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.hisp.dhis.dataelement.DataElement; +import org.hisp.dhis.i18n.I18nFormat; +import org.hisp.dhis.i18n.I18nManager; +import org.hisp.dhis.i18n.I18nManagerException; +import org.hisp.dhis.i18n.locale.LocaleManager; +import org.hisp.dhis.system.util.MathUtils; +import org.hisp.dhis.user.UserService; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * @author Morten Olav Hansen + */ +public class DefaultValidationService implements ValidationService +{ + // ------------------------------------------------------------------------- + // Dependencies + // ------------------------------------------------------------------------- + + @Autowired + private I18nManager i18nManager; + + @Autowired + private UserService userService; + + // ------------------------------------------------------------------------- + // ValidationService Implementation + // ------------------------------------------------------------------------- + + @Override + public ValidationStatus validateDataElement( DataElement dataElement, String value ) + { + I18nFormat format; + + try + { + format = i18nManager.getI18nFormat(); + } + catch ( I18nManagerException ex ) + { + return new ValidationStatus( false, ex.getMessage() ); + } + + value = value.trim(); + + if ( value.length() >= 255 ) + { + return new ValidationStatus( false, value + " is more than 255 characters." ); + } + + if ( dataElement.getType().equals( DataElement.VALUE_TYPE_BOOL ) ) + { + if ( !(value.equalsIgnoreCase( "true" ) || value.equalsIgnoreCase( "false" )) ) + { + return new ValidationStatus( false, value + " is not a valid boolean expression." ); + } + } + else if ( dataElement.getType().equals( DataElement.VALUE_TYPE_TRUE_ONLY ) ) + { + if ( !value.equalsIgnoreCase( "true" ) ) + { + return new ValidationStatus( false, value + " can only be true." ); + } + } + else if ( dataElement.getType().equals( DataElement.VALUE_TYPE_DATE ) ) + { + boolean dateIsValidated = format.parseDate( value ) != null; + + if ( !dateIsValidated ) + { + return new ValidationStatus( false, value + " is not a valid date expression." ); + } + } + else if ( dataElement.getType().equals( DataElement.VALUE_TYPE_USER_NAME ) ) + { + if ( userService.getUserCredentialsByUsername( value ) == null ) + { + return new ValidationStatus( false, value + " is not a valid username." ); + } + } + else if ( dataElement.getType().equals( DataElement.VALUE_TYPE_STRING ) ) + { + if ( dataElement.getOptionSet() != null ) + { + if ( !dataElement.getOptionSet().getOptions().contains( value ) ) + { + return new ValidationStatus( false, value + " is not a valid option for this optionSet." ); + } + } + else if ( dataElement.getTextType().equals( DataElement.VALUE_TYPE_TEXT ) || + dataElement.getTextType().equals( DataElement.VALUE_TYPE_LONG_TEXT ) ) + { + // no validation for this right now, we already to length validation + } + } + else if ( dataElement.getType().equals( DataElement.VALUE_TYPE_NUMBER ) ) + { + if ( !MathUtils.isNumeric( value ) ) + { + return new ValidationStatus( false, value + " is not a valid number." ); + } + + if ( dataElement.getOptionSet() != null ) + { + if ( !dataElement.getOptionSet().getOptions().contains( value ) ) + { + return new ValidationStatus( false, value + " is not a valid option for this optionSet." ); + } + } + + if ( dataElement.getNumberType().equals( DataElement.VALUE_TYPE_INT ) ) + { + if ( !MathUtils.isInteger( value ) ) + { + return new ValidationStatus( false, value + " is not a valid integer." ); + } + } + else if ( dataElement.getNumberType().equals( DataElement.VALUE_TYPE_POSITIVE_INT ) ) + { + if ( !MathUtils.isPositiveInteger( value ) ) + { + return new ValidationStatus( false, value + " is not a valid positive integer." ); + } + } + else if ( dataElement.getNumberType().equals( DataElement.VALUE_TYPE_NEGATIVE_INT ) ) + { + if ( !MathUtils.isNegativeInteger( value ) ) + { + return new ValidationStatus( false, value + " is not a valid negative integer." ); + } + } + } + + return new ValidationStatus( true ); + } +} === added file 'dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/ValidationService.java' --- dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/ValidationService.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/ValidationService.java 2013-05-17 06:44:41 +0000 @@ -0,0 +1,66 @@ +package org.hisp.dhis.dxf2; + +/* + * Copyright (c) 2004-2013, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.hisp.dhis.dataelement.DataElement; + +/** + * @author Morten Olav Hansen + */ +public interface ValidationService +{ + class ValidationStatus + { + private boolean success; + + private String message; + + public ValidationStatus( boolean success ) + { + this.success = success; + } + + public ValidationStatus( boolean success, String message ) + { + this.success = success; + this.message = message; + } + + public boolean isSuccess() + { + return success; + } + + public String getMessage() + { + return message; + } + } + + ValidationStatus validateDataElement( DataElement dataElement, String value ); +} === modified file 'dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/event/BaseEventService.java' --- dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/event/BaseEventService.java 2013-05-17 03:29:07 +0000 +++ dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/event/BaseEventService.java 2013-05-17 06:44:41 +0000 @@ -29,6 +29,7 @@ import org.hisp.dhis.dataelement.DataElement; import org.hisp.dhis.dataelement.DataElementService; +import org.hisp.dhis.dxf2.ValidationService; import org.hisp.dhis.dxf2.importsummary.ImportConflict; import org.hisp.dhis.dxf2.importsummary.ImportStatus; import org.hisp.dhis.dxf2.importsummary.ImportSummary; @@ -82,8 +83,13 @@ private PatientDataValueService patientDataValueService; @Autowired + private ValidationService validationService; + + @Autowired private I18nManager i18nManager; + private I18nFormat format; + // ------------------------------------------------------------------------- // Implementation // ------------------------------------------------------------------------- @@ -122,8 +128,6 @@ private ImportSummary saveSingleEventWithoutRegistration( Program program, OrganisationUnit organisationUnit, Event event ) { - I18nFormat format = null; - try { format = i18nManager.getI18nFormat(); @@ -141,6 +145,7 @@ } ImportSummary importSummary = new ImportSummary(); + importSummary.setStatus( ImportStatus.SUCCESS ); ProgramStageInstance programStageInstance = saveExecutionDate( program, organisationUnit, executionDate, event.getCompleted() ); @@ -155,16 +160,31 @@ } else { - saveDataValue( programStageInstance, dataElement, dataValue.getValue(), dataValue.getProvidedElsewhere() ); - importSummary.getDataValueCount().incrementImported(); + if ( validateDataElement( dataElement, dataValue.getValue(), importSummary ) ) + { + saveDataValue( programStageInstance, dataElement, dataValue.getValue(), dataValue.getProvidedElsewhere() ); + importSummary.getDataValueCount().incrementImported(); + } } } - importSummary.setStatus( ImportStatus.SUCCESS ); - return importSummary; } + private boolean validateDataElement( DataElement dataElement, String value, ImportSummary importSummary ) + { + ValidationService.ValidationStatus status = validationService.validateDataElement( dataElement, value ); + + if ( !status.isSuccess() ) + { + importSummary.getConflicts().add( new ImportConflict( dataElement.getUid(), status.getMessage() ) ); + importSummary.getDataValueCount().incrementIgnored(); + return false; + } + + return true; + } + private ProgramStageInstance saveExecutionDate( Program program, OrganisationUnit organisationUnit, Date date, Boolean completed ) { ProgramStage programStage = program.getProgramStages().iterator().next(); === modified file 'dhis-2/dhis-dxf2/src/main/resources/META-INF/dhis/beans.xml' --- dhis-2/dhis-dxf2/src/main/resources/META-INF/dhis/beans.xml 2013-05-17 03:29:07 +0000 +++ dhis-2/dhis-dxf2/src/main/resources/META-INF/dhis/beans.xml 2013-05-17 06:44:41 +0000 @@ -16,6 +16,8 @@ + + *
    *
  • Be between 8 and 80 characters long
  • *
  • Include at least one digit
  • *
  • Include at least one uppercase letter
  • *
- * + * * @param password the password. * @return true if the password is valid, false otherwise. */ @@ -118,13 +118,13 @@ { return false; } - + return DIGIT_PATTERN.matcher( password ).matches() && UPPERCASE_PATTERN.matcher( password ).matches(); } - + /** * Validates whether a coordinate is valid. - * + * * @return true if the coordinate is valid, false otherwise. */ public static boolean coordinateIsValid( String coordinate ) @@ -133,17 +133,17 @@ { return false; } - + Matcher matcher = POINT_PATTERN.matcher( coordinate ); - + if ( !matcher.find() ) { return false; } - + double longitude = 0.0; double latitude = 0.0; - + try { longitude = Double.parseDouble( matcher.group( 1 ) ); @@ -153,15 +153,15 @@ { return false; } - + return longitude >= LONG_MIN && longitude <= LONG_MAX && latitude >= LAT_MIN && latitude <= LAT_MAX; } - + /** * Returns the longitude from the given coordinate. Returns null if the * coordinate string is not valid. The coordinate is on the form * longitude / latitude. - * + * * @param coordinate the coordinate string. * @return the longitude. */ @@ -171,9 +171,9 @@ { return null; } - + Matcher matcher = POINT_PATTERN.matcher( coordinate ); - + return matcher.find() ? matcher.group( 1 ) : null; } @@ -181,7 +181,7 @@ * Returns the latitude from the given coordinate. Returns null if the * coordinate string is not valid. The coordinate is on the form * longitude / latitude. - * + * * @param coordinate the coordinate string. * @return the latitude. */ @@ -191,31 +191,31 @@ { return null; } - + Matcher matcher = POINT_PATTERN.matcher( coordinate ); - + return matcher.find() ? matcher.group( 2 ) : null; } /** - * Returns a coordinate string based on the given latitude and longitude. + * Returns a coordinate string based on the given latitude and longitude. * The coordinate is on the form longitude / latitude. - * + * * @param longitude the longitude string. - * @param latitude the latitude string. + * @param latitude the latitude string. * @return a coordinate string. */ public static String getCoordinate( String longitude, String latitude ) { return "[" + longitude + "," + latitude + "]"; } - + /** * Checks if the given data value is valid according to the value type of the * given data element. Considers the value to be valid if null or empty. * Returns a string if the valid is invalid, possible * values are: - * + *

*

    *
  • value_null_or_empty
  • *
  • data_element_or_type_null_or_empty
  • @@ -226,8 +226,8 @@ *
  • value_not_negative_integer
  • *
  • value_is_zero_and_not_zero_significant
  • *
- * - * @param value the data value. + * + * @param value the data value. * @param dataElement the data element. * @return null if the value is valid, a string if not. */ @@ -237,47 +237,47 @@ { return null; } - + if ( dataElement == null || dataElement.getType() == null || dataElement.getType().isEmpty() ) { return "data_element_or_type_null_or_empty"; } - + List types = Arrays.asList( VALUE_TYPE_STRING, VALUE_TYPE_INT, VALUE_TYPE_NUMBER, VALUE_TYPE_POSITIVE_INT, VALUE_TYPE_NEGATIVE_INT ); - + String type = dataElement.getDetailedNumberType(); - + if ( types.contains( type ) && value.length() > 255 ) { return "value_length_greater_than_max_length"; } - + if ( VALUE_TYPE_NUMBER.equals( type ) && !MathUtils.isNumeric( value ) ) { return "value_not_numeric"; } - + if ( VALUE_TYPE_INT.equals( type ) && !MathUtils.isInteger( value ) ) { return "value_not_integer"; } - + if ( VALUE_TYPE_POSITIVE_INT.equals( type ) && !MathUtils.isPositiveInteger( value ) ) { return "value_not_positive_integer"; } - + if ( VALUE_TYPE_NEGATIVE_INT.equals( type ) && !MathUtils.isNegativeInteger( value ) ) { return "value_not_negative_integer"; } - - if ( VALUE_TYPE_INT.equals( dataElement.getType() ) && MathUtils.isZero( value ) && + + if ( VALUE_TYPE_INT.equals( dataElement.getType() ) && MathUtils.isZero( value ) && !dataElement.isZeroIsSignificant() && !AGGREGATION_OPERATOR_AVERAGE.equals( dataElement.getAggregationOperator() ) ) { return "value_is_zero_and_not_zero_significant"; } - + return null; - } + } }