=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/DefaultDataApprovalService.java' --- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/DefaultDataApprovalService.java 2013-12-25 15:01:48 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/DefaultDataApprovalService.java 2013-12-26 15:31:04 +0000 @@ -114,7 +114,6 @@ case APPROVAL_NOT_NEEDED: break; // Do nothing. } - } // @@ -136,15 +135,15 @@ return DataApprovalState.APPROVAL_NOT_NEEDED; } - public boolean mayApprove( OrganisationUnit source, User user, + public boolean mayApprove( OrganisationUnit organisationUnit, User user, boolean mayApproveAtSameLevel, boolean mayApproveAtLowerLevels ) { - if ( mayApproveAtSameLevel && user.getOrganisationUnits().contains( source ) ) + if ( mayApproveAtSameLevel && user.getOrganisationUnits().contains( organisationUnit ) ) { return true; } - if ( mayApproveAtLowerLevels && CollectionUtils.containsAny( user.getOrganisationUnits(), source.getAncestors() ) ) + if ( mayApproveAtLowerLevels && CollectionUtils.containsAny( user.getOrganisationUnits(), organisationUnit.getAncestors() ) ) { return true; } === added file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/DataApprovalController.java' --- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/DataApprovalController.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/DataApprovalController.java 2013-12-26 15:31:04 +0000 @@ -0,0 +1,183 @@ +package org.hisp.dhis.api.controller; + +/* + * 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 java.util.Date; + +import javax.servlet.http.HttpServletResponse; + +import org.hisp.dhis.api.utils.ContextUtils; +import org.hisp.dhis.api.utils.InputUtils; +import org.hisp.dhis.dataapproval.DataApproval; +import org.hisp.dhis.dataapproval.DataApprovalService; +import org.hisp.dhis.dataapproval.DataApprovalState; +import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo; +import org.hisp.dhis.dataelement.DataElementCategoryService; +import org.hisp.dhis.dataset.DataSet; +import org.hisp.dhis.dataset.DataSetService; +import org.hisp.dhis.organisationunit.OrganisationUnit; +import org.hisp.dhis.organisationunit.OrganisationUnitService; +import org.hisp.dhis.period.Period; +import org.hisp.dhis.period.PeriodType; +import org.hisp.dhis.user.CurrentUserService; +import org.hisp.dhis.user.User; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +/** + * @author Lars Helge Overland + */ +@Controller +@RequestMapping(value = DataApprovalController.RESOURCE_PATH) +public class DataApprovalController +{ + public static final String RESOURCE_PATH = "/dataApprovals"; + + @Autowired + private DataApprovalService dataApprovalService; + + @Autowired + private DataSetService dataSetService; + + @Autowired + private OrganisationUnitService organisationUnitService; + + @Autowired + private DataElementCategoryService categoryService; + + @Autowired + private CurrentUserService currentUserService; + + @Autowired + private InputUtils inputUtils; + + @PreAuthorize( "hasRole('ALL') or hasRole('F_APPROVE_DATA')" ) + @RequestMapping( method = RequestMethod.POST, produces = "text/plain" ) + public void saveApproval( + @RequestParam String ds, + @RequestParam String pe, + @RequestParam String ou, + @RequestParam( required = false ) String cc, + @RequestParam( required = false ) String cp, HttpServletResponse response ) + { + DataSet dataSet = dataSetService.getDataSet( ds ); + + if ( dataSet == null ) + { + ContextUtils.conflictResponse( response, "Illegal data set identifier: " + ds ); + return; + } + + Period period = PeriodType.getPeriodFromIsoString( pe ); + + if ( period == null ) + { + ContextUtils.conflictResponse( response, "Illegal period identifier: " + pe ); + return; + } + + OrganisationUnit organisationUnit = organisationUnitService.getOrganisationUnit( ou ); + + if ( organisationUnit == null ) + { + ContextUtils.conflictResponse( response, "Illegal organisation unit identifier: " + ou ); + return; + } + + DataElementCategoryOptionCombo attributeOptionCombo = inputUtils.getAttributeOptionCombo( response, cc, cp ); + + if ( attributeOptionCombo == null ) + { + return; + } + + User user = currentUserService.getCurrentUser(); + + DataApprovalState state = dataApprovalService.getDataApprovalState( dataSet, period, organisationUnit, attributeOptionCombo ); + + if ( DataApprovalState.READY_FOR_APPROVAL.equals( state ) ) + { + DataApproval approval = new DataApproval( dataSet, period, organisationUnit, attributeOptionCombo, new Date(), user ); + + dataApprovalService.addDataApproval( approval ); + } + } + + @PreAuthorize( "hasRole('ALL') or hasRole('F_APPROVE_DATA')" ) + @RequestMapping( method = RequestMethod.DELETE, produces = "text/plain" ) + public void removeApproval( + @RequestParam String ds, + @RequestParam String pe, + @RequestParam String ou, + @RequestParam( required = false ) String cc, + @RequestParam( required = false ) String cp, HttpServletResponse response ) + { + DataSet dataSet = dataSetService.getDataSet( ds ); + + if ( dataSet == null ) + { + ContextUtils.conflictResponse( response, "Illegal data set identifier: " + ds ); + return; + } + + Period period = PeriodType.getPeriodFromIsoString( pe ); + + if ( period == null ) + { + ContextUtils.conflictResponse( response, "Illegal period identifier: " + pe ); + return; + } + + OrganisationUnit organisationUnit = organisationUnitService.getOrganisationUnit( ou ); + + if ( organisationUnit == null ) + { + ContextUtils.conflictResponse( response, "Illegal organisation unit identifier: " + ou ); + return; + } + + DataElementCategoryOptionCombo attributeOptionCombo = inputUtils.getAttributeOptionCombo( response, cc, cp ); + + if ( attributeOptionCombo == null ) + { + return; + } + + DataApproval approval = dataApprovalService.getDataApproval( dataSet, period, organisationUnit, attributeOptionCombo ); + + if ( approval != null ) + { + dataApprovalService.deleteDataApproval( approval ); + } + } +} === modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/DataValueController.java' --- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/DataValueController.java 2013-12-22 09:15:53 +0000 +++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/DataValueController.java 2013-12-26 15:31:04 +0000 @@ -29,17 +29,13 @@ */ import java.util.Date; -import java.util.HashSet; -import java.util.List; -import java.util.Set; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringUtils; import org.hisp.dhis.api.utils.ContextUtils; +import org.hisp.dhis.api.utils.InputUtils; import org.hisp.dhis.dataelement.DataElement; -import org.hisp.dhis.dataelement.DataElementCategoryCombo; -import org.hisp.dhis.dataelement.DataElementCategoryOption; import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo; import org.hisp.dhis.dataelement.DataElementCategoryService; import org.hisp.dhis.dataelement.DataElementService; @@ -85,6 +81,9 @@ @Autowired private DataSetService dataSetService; + + @Autowired + private InputUtils inputUtils; @PreAuthorize( "hasRole('ALL') or hasRole('F_DATAVALUE_ADD')" ) @RequestMapping( method = RequestMethod.POST, produces = "text/plain" ) @@ -99,12 +98,10 @@ @RequestParam( required = false ) String comment, @RequestParam( required = false ) boolean followUp, HttpServletResponse response ) { - List opts = ContextUtils.getQueryParamValues( cp ); + // --------------------------------------------------------------------- + // Input validation + // --------------------------------------------------------------------- - // --------------------------------------------------------------------- - // Data element validation - // --------------------------------------------------------------------- - DataElement dataElement = dataElementService.getDataElement( de ); if ( dataElement == null ) @@ -113,10 +110,6 @@ return; } - // --------------------------------------------------------------------- - // Category option combo validation - // --------------------------------------------------------------------- - DataElementCategoryOptionCombo categoryOptionCombo = null; if ( co != null ) @@ -134,65 +127,13 @@ return; } - // --------------------------------------------------------------------- - // Attribute category combo validation - // --------------------------------------------------------------------- - - if ( ( cc == null && opts != null || ( cc != null && opts == null ) ) ) - { - ContextUtils.conflictResponse( response, "Both or none of category combination and category options must be present" ); - return; - } - - DataElementCategoryCombo categoryCombo = null; + DataElementCategoryOptionCombo attributeOptionCombo = inputUtils.getAttributeOptionCombo( response, cc, cp ); - if ( cc != null && ( categoryCombo = categoryService.getDataElementCategoryCombo( cc ) ) == null ) - { - ContextUtils.conflictResponse( response, "Illegal category combo identifier: " + cc ); - return; - } - - // --------------------------------------------------------------------- - // Attribute category options validation - // --------------------------------------------------------------------- - - DataElementCategoryOptionCombo attributeOptionCombo = null; - - if ( opts != null ) - { - Set categoryOptions = new HashSet(); - - for ( String id : opts ) - { - DataElementCategoryOption categoryOption = categoryService.getDataElementCategoryOption( id ); - - if ( categoryOption == null ) - { - ContextUtils.conflictResponse( response, "Illegal category option identifier: " + id ); - return; - } - - categoryOptions.add( categoryOption ); - } - - attributeOptionCombo = categoryService.getDataElementCategoryOptionCombo( categoryCombo, categoryOptions ); - - if ( attributeOptionCombo == null ) - { - ContextUtils.conflictResponse( response, "Attribute option combo does not exist for given category combo and category options" ); - return; - } - } - if ( attributeOptionCombo == null ) { - attributeOptionCombo = categoryService.getDefaultDataElementCategoryOptionCombo(); + return; } - // --------------------------------------------------------------------- - // Period validation - // --------------------------------------------------------------------- - Period period = PeriodType.getPeriodFromIsoString( pe ); if ( period == null ) @@ -201,10 +142,6 @@ return; } - // --------------------------------------------------------------------- - // Organisation unit validation - // --------------------------------------------------------------------- - OrganisationUnit organisationUnit = organisationUnitService.getOrganisationUnit( ou ); if ( organisationUnit == null ) @@ -213,10 +150,6 @@ return; } - // --------------------------------------------------------------------- - // Data value and comment validation - // --------------------------------------------------------------------- - String valid = ValidationUtils.dataValueIsValid( value, dataElement ); if ( valid != null ) === added file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/utils/InputUtils.java' --- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/utils/InputUtils.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/utils/InputUtils.java 2013-12-26 15:31:04 +0000 @@ -0,0 +1,103 @@ +package org.hisp.dhis.api.utils; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.servlet.http.HttpServletResponse; + +import org.hisp.dhis.dataelement.DataElementCategoryCombo; +import org.hisp.dhis.dataelement.DataElementCategoryOption; +import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo; +import org.hisp.dhis.dataelement.DataElementCategoryService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @author Lars Helge Overland + */ +@Component +public class InputUtils +{ + @Autowired + private DataElementCategoryService categoryService; + + /** + * Validates and retrieves the attribute option combo. 409 conflict as status + * code along with a textual message will be set on the response in case of + * invalid input. + * + * @param response the servlet response. + * @param cc the category combo identifier. + * @param cp the category and option query string. + * @return the attribute option combo identified from the given input, or null + * if the input was invalid. + */ + public DataElementCategoryOptionCombo getAttributeOptionCombo( HttpServletResponse response, String cc, String cp ) + { + List opts = ContextUtils.getQueryParamValues( cp ); + + // --------------------------------------------------------------------- + // Attribute category combo validation + // --------------------------------------------------------------------- + + if ( ( cc == null && opts != null || ( cc != null && opts == null ) ) ) + { + ContextUtils.conflictResponse( response, "Both or none of category combination and category options must be present" ); + return null; + } + + DataElementCategoryCombo categoryCombo = null; + + if ( cc != null && ( categoryCombo = categoryService.getDataElementCategoryCombo( cc ) ) == null ) + { + ContextUtils.conflictResponse( response, "Illegal category combo identifier: " + cc ); + return null; + } + + // --------------------------------------------------------------------- + // Attribute category options validation + // --------------------------------------------------------------------- + + DataElementCategoryOptionCombo attributeOptionCombo = null; + + if ( opts != null ) + { + Set categoryOptions = new HashSet(); + + for ( String id : opts ) + { + DataElementCategoryOption categoryOption = categoryService.getDataElementCategoryOption( id ); + + if ( categoryOption == null ) + { + ContextUtils.conflictResponse( response, "Illegal category option identifier: " + id ); + return null; + } + + categoryOptions.add( categoryOption ); + } + + attributeOptionCombo = categoryService.getDataElementCategoryOptionCombo( categoryCombo, categoryOptions ); + + if ( attributeOptionCombo == null ) + { + ContextUtils.conflictResponse( response, "Attribute option combo does not exist for given category combo and category options" ); + return null; + } + } + + if ( attributeOptionCombo == null ) + { + attributeOptionCombo = categoryService.getDefaultDataElementCategoryOptionCombo(); + } + + if ( attributeOptionCombo == null ) + { + ContextUtils.conflictResponse( response, "Default attribute option combo does not exist" ); + return null; + } + + return attributeOptionCombo; + } +}