diff --git a/mdm-core/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/core/facet/AnnotationController.groovy b/mdm-core/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/core/facet/AnnotationController.groovy index 280fc0fbd7..643a6f79ee 100644 --- a/mdm-core/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/core/facet/AnnotationController.groovy +++ b/mdm-core/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/core/facet/AnnotationController.groovy @@ -59,7 +59,7 @@ class AnnotationController extends FacetController { protected Annotation createResource() { Annotation resource = super.createResource() as Annotation if (params.annotationId) { - annotationService.get(params.annotationId)?.addToChildAnnotations(resource) + annotationService.findByMultiFacetAwareItemIdAndId(params.multiFacetAwareItemId, params.annotationId)?.addToChildAnnotations(resource) } if (!resource.label && resource.parentAnnotation) { resource.label = "${resource.parentAnnotation.label} [${resource.parentAnnotation.childAnnotations.size()}]" diff --git a/mdm-core/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/core/facet/AnnotationInterceptor.groovy b/mdm-core/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/core/facet/AnnotationInterceptor.groovy index 170d54506f..68924bafe2 100644 --- a/mdm-core/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/core/facet/AnnotationInterceptor.groovy +++ b/mdm-core/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/core/facet/AnnotationInterceptor.groovy @@ -17,11 +17,14 @@ */ package uk.ac.ox.softeng.maurodatamapper.core.facet +import uk.ac.ox.softeng.maurodatamapper.api.exception.ApiBadRequestException import uk.ac.ox.softeng.maurodatamapper.core.interceptor.FacetInterceptor import uk.ac.ox.softeng.maurodatamapper.util.Utils class AnnotationInterceptor extends FacetInterceptor { + AnnotationService annotationService + @Override Class getFacetClass() { Annotation @@ -32,6 +35,14 @@ class AnnotationInterceptor extends FacetInterceptor { Utils.toUuid(params, 'annotationId') } + @Override + void checkParentId() throws ApiBadRequestException { + if (params.annotationId && !annotationService.existsByMultiFacetAwareItemIdAndId(params.multiFacetAwareItemId, params.annotationId)) { + throw new ApiBadRequestException('AI01', 'Provided annotationId is not inside provided multiFacetAwareItemId') + } + } + + boolean before() { facetResourceChecks() checkActionAllowedOnFacet() diff --git a/mdm-core/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/core/facet/rule/RuleRepresentationController.groovy b/mdm-core/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/core/facet/rule/RuleRepresentationController.groovy index a00dfdc70c..c55b73f0ef 100644 --- a/mdm-core/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/core/facet/rule/RuleRepresentationController.groovy +++ b/mdm-core/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/core/facet/rule/RuleRepresentationController.groovy @@ -46,9 +46,9 @@ class RuleRepresentationController extends EditLoggingController(Annotation).inList('multiFacetAwareItemId', multiFacetAwareItemIds) } - static DetachedCriteria byyMultiFacetAwareItemIdAndId(Serializable multiFacetAwareItemId, Serializable resourceId) { + static DetachedCriteria byMultiFacetAwareItemIdAndId(Serializable multiFacetAwareItemId, Serializable resourceId) { byMultiFacetAwareItemId(multiFacetAwareItemId).idEq(Utils.toUuid(resourceId)) } diff --git a/mdm-core/grails-app/services/uk/ac/ox/softeng/maurodatamapper/core/facet/AnnotationService.groovy b/mdm-core/grails-app/services/uk/ac/ox/softeng/maurodatamapper/core/facet/AnnotationService.groovy index 572c2cd981..9c82ecfc07 100644 --- a/mdm-core/grails-app/services/uk/ac/ox/softeng/maurodatamapper/core/facet/AnnotationService.groovy +++ b/mdm-core/grails-app/services/uk/ac/ox/softeng/maurodatamapper/core/facet/AnnotationService.groovy @@ -78,9 +78,13 @@ class AnnotationService implements MultiFacetItemAwareService { annotation } + boolean existsByMultiFacetAwareItemIdAndId(UUID multiFacetAwareItemId, Serializable id) { + Annotation.byMultiFacetAwareItemIdAndId(multiFacetAwareItemId, id).count() == 1 + } + @Override Annotation findByMultiFacetAwareItemIdAndId(UUID multiFacetAwareItemId, Serializable id) { - Annotation.byyMultiFacetAwareItemIdAndId(multiFacetAwareItemId, id).get() + Annotation.byMultiFacetAwareItemIdAndId(multiFacetAwareItemId, id).get() } @Override diff --git a/mdm-core/grails-app/services/uk/ac/ox/softeng/maurodatamapper/core/facet/RuleService.groovy b/mdm-core/grails-app/services/uk/ac/ox/softeng/maurodatamapper/core/facet/RuleService.groovy index 0020e63c6e..1b0bf8811d 100644 --- a/mdm-core/grails-app/services/uk/ac/ox/softeng/maurodatamapper/core/facet/RuleService.groovy +++ b/mdm-core/grails-app/services/uk/ac/ox/softeng/maurodatamapper/core/facet/RuleService.groovy @@ -108,6 +108,11 @@ class RuleService implements MultiFacetItemAwareService { true } + + boolean existsByMultiFacetAwareItemIdAndId(UUID multiFacetAwareItemId, Serializable id) { + Rule.byMultiFacetAwareItemIdAndId(multiFacetAwareItemId, id).count() == 1 + } + @Override Rule findByMultiFacetAwareItemIdAndId(UUID multiFacetAwareItemId, Serializable id) { Rule.byMultiFacetAwareItemIdAndId(multiFacetAwareItemId, id).get() diff --git a/mdm-core/src/main/groovy/uk/ac/ox/softeng/maurodatamapper/core/interceptor/FacetInterceptor.groovy b/mdm-core/src/main/groovy/uk/ac/ox/softeng/maurodatamapper/core/interceptor/FacetInterceptor.groovy index 5aa08fa28e..eb9bc6c78a 100644 --- a/mdm-core/src/main/groovy/uk/ac/ox/softeng/maurodatamapper/core/interceptor/FacetInterceptor.groovy +++ b/mdm-core/src/main/groovy/uk/ac/ox/softeng/maurodatamapper/core/interceptor/FacetInterceptor.groovy @@ -58,12 +58,17 @@ abstract class FacetInterceptor implements MdmInterceptor { // No-op } + void checkParentId() throws ApiBadRequestException { + // no op + } + void facetResourceChecks() { Utils.toUuid(params, 'id') - params.multiFacetAwareItemDomainType = params.multiFacetAwareItemDomainType?: params.catalogueItemDomainType ?: params.containerDomainType + params.multiFacetAwareItemDomainType = params.multiFacetAwareItemDomainType ?: params.catalogueItemDomainType ?: params.containerDomainType params.multiFacetAwareItemId = params.multiFacetAwareItemId ?: params.catalogueItemId ?: params.containerId checkAdditionalIds() mapDomainTypeToClass(getOwningType(), true) + checkParentId() } boolean checkActionAllowedOnFacet() { diff --git a/mdm-core/src/main/groovy/uk/ac/ox/softeng/maurodatamapper/core/interceptor/ModelItemInterceptor.groovy b/mdm-core/src/main/groovy/uk/ac/ox/softeng/maurodatamapper/core/interceptor/ModelItemInterceptor.groovy new file mode 100644 index 0000000000..969dc7375b --- /dev/null +++ b/mdm-core/src/main/groovy/uk/ac/ox/softeng/maurodatamapper/core/interceptor/ModelItemInterceptor.groovy @@ -0,0 +1,80 @@ +/* + * Copyright 2020-2022 University of Oxford and Health and Social Care Information Centre, also known as NHS Digital + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package uk.ac.ox.softeng.maurodatamapper.core.interceptor + +import uk.ac.ox.softeng.maurodatamapper.api.exception.ApiBadRequestException +import uk.ac.ox.softeng.maurodatamapper.core.traits.controller.MdmInterceptor +import uk.ac.ox.softeng.maurodatamapper.util.Utils + +/** + * @since 02/03/2022 + */ +abstract class ModelItemInterceptor implements MdmInterceptor { + + abstract Class getModelItemClass() + + abstract Class getModelClass() + + abstract String getModelIdParameterField() + + abstract String getOtherModelIdParameterField() + + void checkIds() { + Utils.toUuid(params, getModelIdParameterField()) + Utils.toUuid(params, getOtherModelIdParameterField()) + Utils.toUuid(params, 'id') + } + + void checkModelId() throws ApiBadRequestException { + if (!params[modelIdParameterField]) throw new ApiBadRequestException('MII01', 'No Model Id provided against secured resource') + } + + /** + * Check that when an is MI accessed through another MI the parent MI is contained inside the Model + * Should throw ApiBadRequestException + */ + void checkParentModelItemId() throws ApiBadRequestException { + } + + void performChecks() { + checkIds() + checkModelId() + checkParentModelItemId() + } + + boolean checkStandardActions() { + checkActionAuthorisationOnUnsecuredResource(getModelItemClass(), params.id, getModelClass(), params[modelIdParameterField]) + } + + boolean canReadModel() { + currentUserSecurityPolicyManager.userCanReadSecuredResourceId(getModelClass(), params[modelIdParameterField]) ?: + notFound(getModelClass(), params[modelIdParameterField].toString() + ) + } + + boolean canEditModelAndReadOtherModel() { + boolean canRead = currentUserSecurityPolicyManager.userCanReadSecuredResourceId(getModelClass(), params[modelIdParameterField]) + if (!currentUserSecurityPolicyManager.userCanEditSecuredResourceId(getModelClass(), params[modelIdParameterField])) { + return forbiddenOrNotFound(canRead, getModelClass(), params[modelIdParameterField]) + } + if (!currentUserSecurityPolicyManager.userCanReadSecuredResourceId(getModelClass(), params[otherModelIdParameterField])) { + return notFound(getModelClass(), params[otherModelIdParameterField]) + } + true + } +} diff --git a/mdm-core/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/core/facet/NestedAnnotationControllerSpec.groovy b/mdm-core/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/core/facet/NestedAnnotationControllerSpec.groovy index d0e9637fcc..4fb348558e 100644 --- a/mdm-core/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/core/facet/NestedAnnotationControllerSpec.groovy +++ b/mdm-core/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/core/facet/NestedAnnotationControllerSpec.groovy @@ -90,7 +90,7 @@ class NestedAnnotationControllerSpec extends ResourceControllerSpec {String domain, UUID bid -> basicModel.id == bid ? basicModel : null} findByMultiFacetAwareItemIdAndId(_, _) >> {UUID iid, Serializable mid -> if (iid != basicModel.id) return null - mid == domain.id ? domain : null + mid == domain.id ? domain : Annotation.get(mid) } findAllWhereRootAnnotationOfMultiFacetAwareItemId(_, _) >> { Annotation.whereRootAnnotationOfMultiFacetAwareItemId(basicModel.id).list() diff --git a/mdm-plugin-dataflow/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/dataflow/component/DataClassComponentController.groovy b/mdm-plugin-dataflow/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/dataflow/component/DataClassComponentController.groovy index f59277a4b3..b8cd7ecc8f 100644 --- a/mdm-plugin-dataflow/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/dataflow/component/DataClassComponentController.groovy +++ b/mdm-plugin-dataflow/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/dataflow/component/DataClassComponentController.groovy @@ -95,7 +95,7 @@ class DataClassComponentController extends EditLoggingController { DataFlow.byTargetDataModelIdAndId(dataModelId, Utils.toUuid(id)).get() } + boolean existsByTargetDataModelIdAndId(UUID dataModelId, Serializable id) { + DataFlow.byTargetDataModelIdAndId(dataModelId, Utils.toUuid(id)).count() == 1 + } + List findAllReadableByUser(UserSecurityPolicyManager userSecurityPolicyManager, Map pagination = [:]) { if (!userSecurityPolicyManager.listReadableSecuredResourceIds(DataModel)) return [] DataFlow.byDataModelIdInList( diff --git a/mdm-plugin-dataflow/grails-app/services/uk/ac/ox/softeng/maurodatamapper/dataflow/component/DataClassComponentService.groovy b/mdm-plugin-dataflow/grails-app/services/uk/ac/ox/softeng/maurodatamapper/dataflow/component/DataClassComponentService.groovy index 283a9fa176..57a47dbb43 100644 --- a/mdm-plugin-dataflow/grails-app/services/uk/ac/ox/softeng/maurodatamapper/dataflow/component/DataClassComponentService.groovy +++ b/mdm-plugin-dataflow/grails-app/services/uk/ac/ox/softeng/maurodatamapper/dataflow/component/DataClassComponentService.groovy @@ -144,6 +144,10 @@ class DataClassComponentService extends ModelItemService { DataClassComponent.byDataFlowIdAndId(dataFlowId, Utils.toUuid(id)).get() } + boolean existsByDataFlowIdAndId(UUID dataFlowId, Serializable id) { + DataClassComponent.byDataFlowIdAndId(dataFlowId, Utils.toUuid(id)).count() == 1 + } + List findAllByDataFlowId(UUID dataFlowId, Map pagination = [:]) { DataClassComponent.byDataFlowId(dataFlowId).list(pagination) } diff --git a/mdm-plugin-dataflow/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/dataflow/DataFlowInterceptorSpec.groovy b/mdm-plugin-dataflow/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/dataflow/DataFlowInterceptorSpec.groovy index 96775be743..8016e475d1 100644 --- a/mdm-plugin-dataflow/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/dataflow/DataFlowInterceptorSpec.groovy +++ b/mdm-plugin-dataflow/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/dataflow/DataFlowInterceptorSpec.groovy @@ -46,7 +46,7 @@ class DataFlowInterceptorSpec extends ContainedResourceInterceptorUnitSpec imple @Override String getExpectedExceptionCodeForNoContainingItem() { - 'DMSI01' + 'MII01' } @Override diff --git a/mdm-plugin-dataflow/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/dataflow/component/DataClassComponentInterceptorSpec.groovy b/mdm-plugin-dataflow/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/dataflow/component/DataClassComponentInterceptorSpec.groovy index 5c169179fb..6d809881e8 100644 --- a/mdm-plugin-dataflow/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/dataflow/component/DataClassComponentInterceptorSpec.groovy +++ b/mdm-plugin-dataflow/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/dataflow/component/DataClassComponentInterceptorSpec.groovy @@ -18,6 +18,7 @@ package uk.ac.ox.softeng.maurodatamapper.dataflow.component import uk.ac.ox.softeng.maurodatamapper.dataflow.DataFlow +import uk.ac.ox.softeng.maurodatamapper.dataflow.DataFlowService import uk.ac.ox.softeng.maurodatamapper.dataflow.component.DataClassComponent import uk.ac.ox.softeng.maurodatamapper.dataflow.component.DataElementComponent import uk.ac.ox.softeng.maurodatamapper.datamodel.DataModel @@ -33,6 +34,9 @@ class DataClassComponentInterceptorSpec extends ContainedResourceInterceptorUnit def setup() { log.debug('Setting up DataClassComponentInterceptorSpec') mockDomains(DataModel, DataClass, DataClassComponent, DataElementComponent, DataFlow) + interceptor.dataFlowService = Stub(DataFlowService) { + existsByTargetDataModelIdAndId(_, _) >> true + } } @Override @@ -48,7 +52,7 @@ class DataClassComponentInterceptorSpec extends ContainedResourceInterceptorUnit @Override String getExpectedExceptionCodeForNoContainingItem() { - 'DMSI01' + 'MII01' } @Override diff --git a/mdm-plugin-dataflow/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/dataflow/component/DataElementComponentInterceptorSpec.groovy b/mdm-plugin-dataflow/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/dataflow/component/DataElementComponentInterceptorSpec.groovy index 5e8ca7e192..83906b0d39 100644 --- a/mdm-plugin-dataflow/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/dataflow/component/DataElementComponentInterceptorSpec.groovy +++ b/mdm-plugin-dataflow/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/dataflow/component/DataElementComponentInterceptorSpec.groovy @@ -18,6 +18,7 @@ package uk.ac.ox.softeng.maurodatamapper.dataflow.component import uk.ac.ox.softeng.maurodatamapper.dataflow.DataFlow +import uk.ac.ox.softeng.maurodatamapper.dataflow.DataFlowService import uk.ac.ox.softeng.maurodatamapper.dataflow.component.DataClassComponent import uk.ac.ox.softeng.maurodatamapper.dataflow.component.DataElementComponent import uk.ac.ox.softeng.maurodatamapper.datamodel.DataModel @@ -34,6 +35,12 @@ class DataElementComponentInterceptorSpec extends ContainedResourceInterceptorUn def setup() { log.debug('Setting up DataElementComponentInterceptorSpec') mockDomains(DataModel, DataClass, DataClassComponent, DataElementComponent, DataFlow) + interceptor.dataFlowService = Stub(DataFlowService) { + existsByTargetDataModelIdAndId(_, _) >> true + } + interceptor.dataClassComponentService = Stub(DataClassComponentService) { + existsByDataFlowIdAndId(_, _) >> true + } } @Override @@ -50,7 +57,7 @@ class DataElementComponentInterceptorSpec extends ContainedResourceInterceptorUn @Override String getExpectedExceptionCodeForNoContainingItem() { - 'DMSI01' + 'MII01' } @Override diff --git a/mdm-plugin-datamodel/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/datamodel/facet/summarymetadata/SummaryMetadataReportController.groovy b/mdm-plugin-datamodel/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/datamodel/facet/summarymetadata/SummaryMetadataReportController.groovy index 21a0d3f9b1..42b4242c99 100644 --- a/mdm-plugin-datamodel/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/datamodel/facet/summarymetadata/SummaryMetadataReportController.groovy +++ b/mdm-plugin-datamodel/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/datamodel/facet/summarymetadata/SummaryMetadataReportController.groovy @@ -51,7 +51,7 @@ class SummaryMetadataReportController extends EditLoggingController { protected DataClass createResource() { DataClass resource = super.createResource() as DataClass if (params.dataClassId) { - dataClassService.get(params.dataClassId)?.addToDataClasses(resource) + dataClassService.findByDataModelIdAndId(params.dataModelId, params.dataClassId)?.addToDataClasses(resource) } dataModelService.get(params.dataModelId)?.addToDataClasses(resource) diff --git a/mdm-plugin-datamodel/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataClassInterceptor.groovy b/mdm-plugin-datamodel/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataClassInterceptor.groovy index d05066dcde..0143f33dc5 100644 --- a/mdm-plugin-datamodel/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataClassInterceptor.groovy +++ b/mdm-plugin-datamodel/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataClassInterceptor.groovy @@ -17,12 +17,14 @@ */ package uk.ac.ox.softeng.maurodatamapper.datamodel.item - +import uk.ac.ox.softeng.maurodatamapper.api.exception.ApiBadRequestException import uk.ac.ox.softeng.maurodatamapper.datamodel.traits.controller.DataModelSecuredInterceptor import uk.ac.ox.softeng.maurodatamapper.util.Utils class DataClassInterceptor extends DataModelSecuredInterceptor { + DataClassService dataClassService + @Override Class getModelItemClass() { DataClass @@ -36,15 +38,22 @@ class DataClassInterceptor extends DataModelSecuredInterceptor { Utils.toUuid(params, 'otherDataElementId') } + @Override + void checkParentModelItemId() throws ApiBadRequestException { + if (params.dataClassId && !dataClassService.existsByDataModelIdAndId(params.dataModelId, params.dataClassId)) { + throw new ApiBadRequestException('DCI01', 'Provided dataClassId is not inside provided dataModelId') + } + } + boolean before() { performChecks() if (actionName in ['content', 'all', 'search']) { - return canReadDataModel() + return canReadModel() } if (actionName in ['copyDataClass', 'extendDataClass', 'importDataElement', 'importDataClass']) { - return canEditDataModelAndReadOtherDataModel() + return canEditModelAndReadOtherModel() } checkStandardActions() diff --git a/mdm-plugin-datamodel/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataElementController.groovy b/mdm-plugin-datamodel/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataElementController.groovy index 70ccfd5993..cd6774ff20 100644 --- a/mdm-plugin-datamodel/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataElementController.groovy +++ b/mdm-plugin-datamodel/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataElementController.groovy @@ -160,7 +160,8 @@ class DataElementController extends CatalogueItemController { @Override protected DataElement createResource() { DataElement resource = super.createResource() as DataElement - dataClassService.get(params.dataClassId)?.addToDataElements(resource) + // Protect against mismatch DM and DC (DC not inside DM + dataClassService.findByDataModelIdAndId(params.dataModelId, params.dataClassId)?.addToDataElements(resource) resource } diff --git a/mdm-plugin-datamodel/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataElementInterceptor.groovy b/mdm-plugin-datamodel/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataElementInterceptor.groovy index 8d53212b3c..57c93767a6 100644 --- a/mdm-plugin-datamodel/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataElementInterceptor.groovy +++ b/mdm-plugin-datamodel/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataElementInterceptor.groovy @@ -17,12 +17,15 @@ */ package uk.ac.ox.softeng.maurodatamapper.datamodel.item +import uk.ac.ox.softeng.maurodatamapper.api.exception.ApiBadRequestException import uk.ac.ox.softeng.maurodatamapper.datamodel.DataModel import uk.ac.ox.softeng.maurodatamapper.datamodel.traits.controller.DataModelSecuredInterceptor import uk.ac.ox.softeng.maurodatamapper.util.Utils class DataElementInterceptor extends DataModelSecuredInterceptor { + DataClassService dataClassService + @Override Class getModelItemClass() { DataElement @@ -36,6 +39,13 @@ class DataElementInterceptor extends DataModelSecuredInterceptor { Utils.toUuid(params, 'otherDataElementId') } + @Override + void checkParentModelItemId() throws ApiBadRequestException { + if (params.containsKey('dataClassId') && !dataClassService.existsByDataModelIdAndId(params.dataModelId, params.dataClassId)) { + throw new ApiBadRequestException('DEI01', 'Provided dataClassId is not inside provided dataModelId') + } + } + boolean before() { performChecks() @@ -50,7 +60,7 @@ class DataElementInterceptor extends DataModelSecuredInterceptor { } if (actionName == 'copyDataElement') { - return canEditDataModelAndReadOtherDataModel() + return canEditModelAndReadOtherModel() } checkStandardActions() diff --git a/mdm-plugin-datamodel/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/datamodel/item/datatype/DataTypeInterceptor.groovy b/mdm-plugin-datamodel/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/datamodel/item/datatype/DataTypeInterceptor.groovy index cf9473a51e..d9f684d988 100644 --- a/mdm-plugin-datamodel/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/datamodel/item/datatype/DataTypeInterceptor.groovy +++ b/mdm-plugin-datamodel/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/datamodel/item/datatype/DataTypeInterceptor.groovy @@ -26,7 +26,7 @@ class DataTypeInterceptor extends DataModelSecuredInterceptor { performChecks() if (actionName == 'copyDataType') { - return canEditDataModelAndReadOtherDataModel() + return canEditModelAndReadOtherModel() } checkStandardActions() } diff --git a/mdm-plugin-datamodel/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/datamodel/item/datatype/enumeration/EnumerationValueController.groovy b/mdm-plugin-datamodel/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/datamodel/item/datatype/enumeration/EnumerationValueController.groovy index ef88e185f7..28c0026acd 100644 --- a/mdm-plugin-datamodel/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/datamodel/item/datatype/enumeration/EnumerationValueController.groovy +++ b/mdm-plugin-datamodel/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/datamodel/item/datatype/enumeration/EnumerationValueController.groovy @@ -55,7 +55,7 @@ class EnumerationValueController extends CatalogueItemController implements SummaryMet false } + boolean existsByDataModelIdAndId(UUID dataModelId, Serializable id) { + DataClass.byDataModelId(dataModelId).idEq(id).count() == 1 + } + DataClass findByDataModelIdAndId(UUID dataModelId, Serializable id) { DataClass.byDataModelId(dataModelId).idEq(id).find() } diff --git a/mdm-plugin-datamodel/grails-app/services/uk/ac/ox/softeng/maurodatamapper/datamodel/item/datatype/EnumerationTypeService.groovy b/mdm-plugin-datamodel/grails-app/services/uk/ac/ox/softeng/maurodatamapper/datamodel/item/datatype/EnumerationTypeService.groovy index 75dbe00852..e3284fce67 100644 --- a/mdm-plugin-datamodel/grails-app/services/uk/ac/ox/softeng/maurodatamapper/datamodel/item/datatype/EnumerationTypeService.groovy +++ b/mdm-plugin-datamodel/grails-app/services/uk/ac/ox/softeng/maurodatamapper/datamodel/item/datatype/EnumerationTypeService.groovy @@ -209,4 +209,12 @@ class EnumerationTypeService extends ModelItemService implement } } } + + EnumerationType findByDataModelIdAndId(Serializable dataModelId, Serializable id) { + EnumerationType.byDataModelIdAndId(dataModelId, id).find() as EnumerationType + } + + boolean existsByDataModelIdAndId(Serializable dataModelId, Serializable id) { + EnumerationType.byDataModelIdAndId(dataModelId, id).count() == 1 + } } diff --git a/mdm-plugin-datamodel/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/item/NestedDataClassFunctionalSpec.groovy b/mdm-plugin-datamodel/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/item/NestedDataClassFunctionalSpec.groovy index 33c05e6e3e..05649b45ae 100644 --- a/mdm-plugin-datamodel/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/item/NestedDataClassFunctionalSpec.groovy +++ b/mdm-plugin-datamodel/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/item/NestedDataClassFunctionalSpec.groovy @@ -31,6 +31,8 @@ import spock.lang.Shared import static uk.ac.ox.softeng.maurodatamapper.core.bootstrap.StandardEmailAddress.FUNCTIONAL_TEST +import static io.micronaut.http.HttpStatus.BAD_REQUEST + /** * @see DataClassController* Controller: dataClass * | POST | /api/dataModels/${dataModelId}/dataClasses/${dataClassId}/dataClasses | Action: save | @@ -59,6 +61,9 @@ class NestedDataClassFunctionalSpec extends ResourceFunctionalSpec { @Shared UUID dataClassId + @Shared + UUID otherDataClassId + @RunOnce @Transactional def setup() { @@ -70,12 +75,19 @@ class NestedDataClassFunctionalSpec extends ResourceFunctionalSpec { DataModel dataModel = new DataModel(label: 'Functional Test DataModel', createdBy: FUNCTIONAL_TEST, folder: folder, authority: testAuthority).save(flush: true) dataModelId = dataModel.id - otherDataModelId = new DataModel(label: 'Functional Test DataModel 2', createdBy: FUNCTIONAL_TEST, - folder: folder, authority: testAuthority).save(flush: true).id DataClass dataClass = new DataClass(label: 'Functional Test DataClass', createdBy: FUNCTIONAL_TEST, dataModel: dataModel).save(flush: true) dataClassId = dataClass.id + DataModel otherDataModel = new DataModel(label: 'Functional Test DataModel 2', createdBy: FUNCTIONAL_TEST, + folder: folder, authority: testAuthority).save(flush: true) + otherDataModelId = otherDataModel.id + + + DataClass otherDataClass = new DataClass(label: 'Functional Test DataClass 2', createdBy: FUNCTIONAL_TEST, + dataModel: otherDataModel).save(flush: true) + otherDataClassId = otherDataClass.id + dataTypeId = new PrimitiveType(label: 'string', createdBy: FUNCTIONAL_TEST, dataModel: dataModel).save(flush: true).id @@ -149,4 +161,14 @@ class NestedDataClassFunctionalSpec extends ResourceFunctionalSpec { ] }''' } + + + void 'Test adding DC to a DC in a different DM to the one in the url'() { + when: + POST(getResourcePath(dataModelId, otherDataClassId), validJson, MAP_ARG, true) + + then: + verifyResponse(BAD_REQUEST, response) + responseBody().message == 'Provided dataClassId is not inside provided dataModelId' + } } \ No newline at end of file diff --git a/mdm-plugin-datamodel/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/test/functional/CatalogueItemSummaryMetadataReportFunctionalSpec.groovy b/mdm-plugin-datamodel/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/test/functional/CatalogueItemSummaryMetadataReportFunctionalSpec.groovy index 551c91a56d..8a5ee1da19 100644 --- a/mdm-plugin-datamodel/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/test/functional/CatalogueItemSummaryMetadataReportFunctionalSpec.groovy +++ b/mdm-plugin-datamodel/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/test/functional/CatalogueItemSummaryMetadataReportFunctionalSpec.groovy @@ -57,11 +57,6 @@ abstract class CatalogueItemSummaryMetadataReportFunctionalSpec extends Catalogu "summaryMetadata/${summaryMetadata.id}/summaryMetadataReports" } - @Override - String getCopyResourcePath(String copyId) { - "${catalogueItemDomainResourcePath}/${copyId}/${facetResourcePath}" - } - String getCatalogueItemCopyPath() { "dataModels/${destinationDataModelId}/${catalogueItemDomainResourcePath}/${sourceDataModelId}/${catalogueItemId}" } @@ -104,13 +99,15 @@ abstract class CatalogueItemSummaryMetadataReportFunctionalSpec extends Catalogu HttpResponse requestCIF01CopiedCatalogueItemFacet(HttpResponse response) { String copyId = response.body().id - GET(getCopyResourcePath(copyId), MAP_ARG, true) + // Get the SM that was copied + GET("${catalogueItemDomainResourcePath}/${copyId}/summaryMetadata", MAP_ARG, true) } void verifyCIF01CopiedFacetSuccessfully(HttpResponse response) { verifyResponse(HttpStatus.OK, response) - assert response.body().count == 1 - assert response.body().items.size() == 1 + // summary metadata should not be copied for DC/DT/DE + assert response.body().count == 0 + assert response.body().items.size() == 0 } void 'CIF01 : Test facet copied with catalogue item'() { diff --git a/mdm-plugin-datamodel/src/main/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/traits/controller/DataModelSecuredInterceptor.groovy b/mdm-plugin-datamodel/src/main/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/traits/controller/DataModelSecuredInterceptor.groovy index 1a3d5b19fc..5c723a2cc0 100644 --- a/mdm-plugin-datamodel/src/main/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/traits/controller/DataModelSecuredInterceptor.groovy +++ b/mdm-plugin-datamodel/src/main/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/traits/controller/DataModelSecuredInterceptor.groovy @@ -17,51 +17,27 @@ */ package uk.ac.ox.softeng.maurodatamapper.datamodel.traits.controller -import uk.ac.ox.softeng.maurodatamapper.api.exception.ApiBadRequestException -import uk.ac.ox.softeng.maurodatamapper.core.traits.controller.MdmInterceptor + +import uk.ac.ox.softeng.maurodatamapper.core.interceptor.ModelItemInterceptor import uk.ac.ox.softeng.maurodatamapper.datamodel.DataModel -import uk.ac.ox.softeng.maurodatamapper.util.Utils /** * @since 20/03/2020 */ -abstract class DataModelSecuredInterceptor implements MdmInterceptor { - - abstract Class getModelItemClass() - - void checkIds() { - Utils.toUuid(params, 'dataModelId') - Utils.toUuid(params, 'id') - Utils.toUuid(params, 'otherDataModelId') - } - - void checkDataModelId() { - if (!params.dataModelId) throw new ApiBadRequestException('DMSI01', 'No DataModel Id provided against secured resource') - } - - void performChecks() { - checkIds() - checkDataModelId() - } +abstract class DataModelSecuredInterceptor extends ModelItemInterceptor { - boolean checkStandardActions() { - checkActionAuthorisationOnUnsecuredResource(getModelItemClass(), params.id, DataModel, params.dataModelId) + @Override + Class getModelClass() { + DataModel } - boolean canReadDataModel() { - currentUserSecurityPolicyManager.userCanReadSecuredResourceId(DataModel, params.dataModelId) ?: notFound(DataModel, - params.dataModelId.toString() - ) + @Override + String getModelIdParameterField() { + 'dataModelId' } - boolean canEditDataModelAndReadOtherDataModel() { - boolean canRead = currentUserSecurityPolicyManager.userCanReadSecuredResourceId(DataModel, params.dataModelId) - if (!currentUserSecurityPolicyManager.userCanEditSecuredResourceId(DataModel, params.dataModelId)) { - return forbiddenOrNotFound(canRead, DataModel, params.dataModelId) - } - if (!currentUserSecurityPolicyManager.userCanReadSecuredResourceId(DataModel, params.otherDataModelId)) { - return notFound(DataModel, params.otherDataModelId) - } - true + @Override + String getOtherModelIdParameterField() { + 'otherDataModelId' } } diff --git a/mdm-plugin-datamodel/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/facet/summarymetadata/SummaryMetadataReportInterceptorSpec.groovy b/mdm-plugin-datamodel/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/facet/summarymetadata/SummaryMetadataReportInterceptorSpec.groovy index 0818795de6..1a93d568ba 100644 --- a/mdm-plugin-datamodel/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/facet/summarymetadata/SummaryMetadataReportInterceptorSpec.groovy +++ b/mdm-plugin-datamodel/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/facet/summarymetadata/SummaryMetadataReportInterceptorSpec.groovy @@ -19,6 +19,7 @@ package uk.ac.ox.softeng.maurodatamapper.datamodel.facet.summarymetadata import uk.ac.ox.softeng.maurodatamapper.datamodel.DataModel import uk.ac.ox.softeng.maurodatamapper.datamodel.facet.SummaryMetadata +import uk.ac.ox.softeng.maurodatamapper.datamodel.facet.SummaryMetadataService import uk.ac.ox.softeng.maurodatamapper.test.unit.interceptor.VariableContainedResourceInterceptorSpec import grails.testing.web.interceptor.InterceptorUnitTest @@ -28,6 +29,9 @@ class SummaryMetadataReportInterceptorSpec extends VariableContainedResourceInte def setup() { mockDomains(DataModel, SummaryMetadata) + interceptor.summaryMetadataService = Stub(SummaryMetadataService) { + existsByMultiFacetAwareItemIdAndId(_, _) >> true + } } @Override diff --git a/mdm-plugin-datamodel/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataClassInterceptorSpec.groovy b/mdm-plugin-datamodel/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataClassInterceptorSpec.groovy index 39b4d33611..cf6d5c1bc3 100644 --- a/mdm-plugin-datamodel/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataClassInterceptorSpec.groovy +++ b/mdm-plugin-datamodel/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataClassInterceptorSpec.groovy @@ -34,6 +34,9 @@ class DataClassInterceptorSpec extends ContainedResourceInterceptorUnitSpec impl def setup() { log.debug('Setting up DataClassInterceptorSpec') mockDomains(DataModel, DataClass, DataElement, DataType, PrimitiveType, ReferenceType, EnumerationType, EnumerationValue) + interceptor.dataClassService = Stub(DataClassService) { + existsByDataModelIdAndId(_, _) >> true + } } @Override @@ -48,7 +51,7 @@ class DataClassInterceptorSpec extends ContainedResourceInterceptorUnitSpec impl @Override String getExpectedExceptionCodeForNoContainingItem() { - 'DMSI01' + 'MII01' } @Override diff --git a/mdm-plugin-datamodel/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataElementInterceptorSpec.groovy b/mdm-plugin-datamodel/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataElementInterceptorSpec.groovy index 8473b3baa8..06aff0db5b 100644 --- a/mdm-plugin-datamodel/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataElementInterceptorSpec.groovy +++ b/mdm-plugin-datamodel/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataElementInterceptorSpec.groovy @@ -34,6 +34,9 @@ class DataElementInterceptorSpec extends ContainedResourceInterceptorUnitSpec im def setup() { log.debug('Setting up DataElementInterceptorSpec') mockDomains(DataModel, DataClass, DataElement, DataType, PrimitiveType, ReferenceType, EnumerationType, EnumerationValue) + interceptor.dataClassService = Stub(DataClassService) { + existsByDataModelIdAndId(_, _) >> true + } } @Override @@ -53,6 +56,6 @@ class DataElementInterceptorSpec extends ContainedResourceInterceptorUnitSpec im @Override String getExpectedExceptionCodeForNoContainingItem() { - 'DMSI01' + 'MII01' } } diff --git a/mdm-plugin-datamodel/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/item/datatype/DataTypeInterceptorSpec.groovy b/mdm-plugin-datamodel/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/item/datatype/DataTypeInterceptorSpec.groovy index c6d9986159..ec9ddf9443 100644 --- a/mdm-plugin-datamodel/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/item/datatype/DataTypeInterceptorSpec.groovy +++ b/mdm-plugin-datamodel/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/item/datatype/DataTypeInterceptorSpec.groovy @@ -51,6 +51,6 @@ class DataTypeInterceptorSpec extends ContainedResourceInterceptorUnitSpec imple @Override String getExpectedExceptionCodeForNoContainingItem() { - 'DMSI01' + 'MII01' } } diff --git a/mdm-plugin-datamodel/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/item/datatype/enumeration/EnumerationValueInterceptorSpec.groovy b/mdm-plugin-datamodel/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/item/datatype/enumeration/EnumerationValueInterceptorSpec.groovy index 2b91d96500..520dca7cde 100644 --- a/mdm-plugin-datamodel/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/item/datatype/enumeration/EnumerationValueInterceptorSpec.groovy +++ b/mdm-plugin-datamodel/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/item/datatype/enumeration/EnumerationValueInterceptorSpec.groovy @@ -17,12 +17,12 @@ */ package uk.ac.ox.softeng.maurodatamapper.datamodel.item.datatype.enumeration - import uk.ac.ox.softeng.maurodatamapper.datamodel.DataModel import uk.ac.ox.softeng.maurodatamapper.datamodel.item.DataClass import uk.ac.ox.softeng.maurodatamapper.datamodel.item.DataElement import uk.ac.ox.softeng.maurodatamapper.datamodel.item.datatype.DataType import uk.ac.ox.softeng.maurodatamapper.datamodel.item.datatype.EnumerationType +import uk.ac.ox.softeng.maurodatamapper.datamodel.item.datatype.EnumerationTypeService import uk.ac.ox.softeng.maurodatamapper.datamodel.item.datatype.PrimitiveType import uk.ac.ox.softeng.maurodatamapper.datamodel.item.datatype.ReferenceType import uk.ac.ox.softeng.maurodatamapper.test.unit.interceptor.ContainedResourceInterceptorUnitSpec @@ -37,6 +37,9 @@ class EnumerationValueInterceptorSpec extends ContainedResourceInterceptorUnitSp log.debug('Setting up EnumerationValueInterceptorSpec') mockDomains(DataModel, DataClass, DataElement, DataType, PrimitiveType, ReferenceType, EnumerationType, EnumerationValue) + interceptor.enumerationTypeService = Stub(EnumerationTypeService) { + existsByDataModelIdAndId(_, _) >> true + } } @Override @@ -56,6 +59,6 @@ class EnumerationValueInterceptorSpec extends ContainedResourceInterceptorUnitSp @Override String getExpectedExceptionCodeForNoContainingItem() { - 'DMSI01' + 'MII01' } } diff --git a/mdm-plugin-referencedata/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/referencedata/facet/summarymetadata/ReferenceSummaryMetadataReportController.groovy b/mdm-plugin-referencedata/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/referencedata/facet/summarymetadata/ReferenceSummaryMetadataReportController.groovy index a764848505..13cb2415c2 100644 --- a/mdm-plugin-referencedata/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/referencedata/facet/summarymetadata/ReferenceSummaryMetadataReportController.groovy +++ b/mdm-plugin-referencedata/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/referencedata/facet/summarymetadata/ReferenceSummaryMetadataReportController.groovy @@ -51,7 +51,7 @@ class ReferenceSummaryMetadataReportController extends EditLoggingController findAllByMetadataNamespace(String namespace, Map pagination) { ReferenceEnumerationType.byMetadataNamespace(namespace).list(pagination) } + + boolean existsByReferenceDataModelIdAndId(Serializable referenceDataModelId, Serializable id) { + ReferenceEnumerationType.byReferenceDataModelIdAndId(referenceDataModelId, id).count() == 1 + } + + ReferenceEnumerationType findByReferenceDataModelIdAndId(Serializable referenceDataModelId, Serializable id) { + ReferenceEnumerationType.byReferenceDataModelIdAndId(referenceDataModelId, id).find() as ReferenceEnumerationType + } } \ No newline at end of file diff --git a/mdm-plugin-referencedata/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/facet/summarymetadata/report/ReferenceDataElementReferenceSummaryMetadataReportFunctionalSpec.groovy b/mdm-plugin-referencedata/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/facet/summarymetadata/report/ReferenceDataElementReferenceSummaryMetadataReportFunctionalSpec.groovy index 8f7987debe..790bfe2c98 100644 --- a/mdm-plugin-referencedata/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/facet/summarymetadata/report/ReferenceDataElementReferenceSummaryMetadataReportFunctionalSpec.groovy +++ b/mdm-plugin-referencedata/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/facet/summarymetadata/report/ReferenceDataElementReferenceSummaryMetadataReportFunctionalSpec.groovy @@ -49,10 +49,6 @@ class ReferenceDataElementReferenceSummaryMetadataReportFunctionalSpec extends C @Shared ReferenceDataType referenceDataType - String getCatalogueItemCopyPath() { - """referenceDataModels/${destinationDataModelId}/${catalogueItemDomainResourcePath}/${sourceDataModelId}/${catalogueItemId}""" - } - @Transactional String getSourceDataModelId() { ReferenceDataModel.findByLabel('Functional Test DataModel').id.toString() @@ -63,11 +59,6 @@ class ReferenceDataElementReferenceSummaryMetadataReportFunctionalSpec extends C ReferenceDataModel.findByLabel('Destination Test DataModel').id.toString() } - @Override - String getFacetResourcePath() { - "referenceSummaryMetadata/${summaryMetadata.id}/summaryMetadataReports" - } - @RunOnce @Transactional def setup() { @@ -83,8 +74,7 @@ class ReferenceDataElementReferenceSummaryMetadataReportFunctionalSpec extends C referenceDataModel: referenceDataModel, referenceDataType: referenceDataType).save(flush: true) summaryMetadata = new ReferenceSummaryMetadata(label: 'Functional Test Summary Metadata', createdBy: StandardEmailAddress.FUNCTIONAL_TEST, multiFacetAwareItem: referenceDataElement, - summaryMetadataType: ReferenceSummaryMetadataType.NUMBER). - save(flush: true) + summaryMetadataType: ReferenceSummaryMetadataType.NUMBER).save(flush: true) sessionFactory.currentSession.flush() } diff --git a/mdm-plugin-referencedata/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/facet/summarymetadata/report/ReferenceDataModelReferenceSummaryMetadataReportFunctionalSpec.groovy b/mdm-plugin-referencedata/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/facet/summarymetadata/report/ReferenceDataModelReferenceSummaryMetadataReportFunctionalSpec.groovy index 98611b4abb..cb60ef369c 100644 --- a/mdm-plugin-referencedata/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/facet/summarymetadata/report/ReferenceDataModelReferenceSummaryMetadataReportFunctionalSpec.groovy +++ b/mdm-plugin-referencedata/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/facet/summarymetadata/report/ReferenceDataModelReferenceSummaryMetadataReportFunctionalSpec.groovy @@ -50,10 +50,6 @@ class ReferenceDataModelReferenceSummaryMetadataReportFunctionalSpec extends Cat @Shared ReferenceDataType referenceDataType - String getCatalogueItemCopyPath() { - """referenceDataModels/${destinationDataModelId}/${catalogueItemDomainResourcePath}/${sourceDataModelId}/${catalogueItemId}""" - } - @Transactional String getSourceDataModelId() { ReferenceDataModel.findByLabel('Functional Test DataModel').id.toString() @@ -64,11 +60,6 @@ class ReferenceDataModelReferenceSummaryMetadataReportFunctionalSpec extends Cat ReferenceDataModel.findByLabel('Destination Test DataModel').id.toString() } - @Override - String getFacetResourcePath() { - "referenceSummaryMetadata/${summaryMetadata.id}/summaryMetadataReports" - } - @RunOnce @Transactional def setup() { @@ -83,7 +74,7 @@ class ReferenceDataModelReferenceSummaryMetadataReportFunctionalSpec extends Cat referenceDataElement = new ReferenceDataElement(label: 'Functional Test DataElement', createdBy: StandardEmailAddress.FUNCTIONAL_TEST, referenceDataModel: referenceDataModel, referenceDataType: referenceDataType).save(flush: true) summaryMetadata = new ReferenceSummaryMetadata(label: 'Functional Test Summary Metadata', createdBy: StandardEmailAddress.FUNCTIONAL_TEST, - multiFacetAwareItem: referenceDataElement, + multiFacetAwareItem: referenceDataModel, summaryMetadataType: ReferenceSummaryMetadataType.NUMBER).save(flush: true) sessionFactory.currentSession.flush() } diff --git a/mdm-plugin-referencedata/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/facet/summarymetadata/report/ReferenceDataTypeReferenceSummaryMetadataReportFunctionalSpec.groovy b/mdm-plugin-referencedata/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/facet/summarymetadata/report/ReferenceDataTypeReferenceSummaryMetadataReportFunctionalSpec.groovy index ee1c63f6ee..87d6658033 100644 --- a/mdm-plugin-referencedata/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/facet/summarymetadata/report/ReferenceDataTypeReferenceSummaryMetadataReportFunctionalSpec.groovy +++ b/mdm-plugin-referencedata/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/facet/summarymetadata/report/ReferenceDataTypeReferenceSummaryMetadataReportFunctionalSpec.groovy @@ -49,10 +49,6 @@ class ReferenceDataTypeReferenceSummaryMetadataReportFunctionalSpec extends Cata @Shared ReferenceDataType referenceDataType - String getCatalogueItemCopyPath() { - """referenceDataModels/${destinationDataModelId}/${catalogueItemDomainResourcePath}/${sourceDataModelId}/${catalogueItemId}""" - } - @Transactional String getSourceDataModelId() { ReferenceDataModel.findByLabel('Functional Test DataModel').id.toString() @@ -63,11 +59,6 @@ class ReferenceDataTypeReferenceSummaryMetadataReportFunctionalSpec extends Cata ReferenceDataModel.findByLabel('Destination Test DataModel').id.toString() } - @Override - String getFacetResourcePath() { - "referenceSummaryMetadata/${summaryMetadata.id}/summaryMetadataReports" - } - @RunOnce @Transactional def setup() { @@ -82,7 +73,7 @@ class ReferenceDataTypeReferenceSummaryMetadataReportFunctionalSpec extends Cata referenceDataElement = new ReferenceDataElement(label: 'Functional Test DataElement', createdBy: StandardEmailAddress.FUNCTIONAL_TEST, referenceDataModel: referenceDataModel, referenceDataType: referenceDataType).save(flush: true) summaryMetadata = new ReferenceSummaryMetadata(label: 'Functional Test Summary Metadata', createdBy: StandardEmailAddress.FUNCTIONAL_TEST, - multiFacetAwareItem: referenceDataElement, + multiFacetAwareItem: referenceDataType, summaryMetadataType: ReferenceSummaryMetadataType.NUMBER).save(flush: true) sessionFactory.currentSession.flush() } diff --git a/mdm-plugin-referencedata/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/test/functional/CatalogueItemReferenceSummaryMetadataReportFunctionalSpec.groovy b/mdm-plugin-referencedata/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/test/functional/CatalogueItemReferenceSummaryMetadataReportFunctionalSpec.groovy index d5e17cc66a..87f59cf641 100644 --- a/mdm-plugin-referencedata/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/test/functional/CatalogueItemReferenceSummaryMetadataReportFunctionalSpec.groovy +++ b/mdm-plugin-referencedata/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/test/functional/CatalogueItemReferenceSummaryMetadataReportFunctionalSpec.groovy @@ -56,16 +56,11 @@ abstract class CatalogueItemReferenceSummaryMetadataReportFunctionalSpec extends @Override String getFacetResourcePath() { - "summaryMetadata/${summaryMetadata.id}/summaryMetadataReports" - } - - @Override - String getCopyResourcePath(String copyId) { - "${catalogueItemDomainResourcePath}/${copyId}/${facetResourcePath}" + "referenceSummaryMetadata/${summaryMetadata.id}/summaryMetadataReports" } String getCatalogueItemCopyPath() { - "dataModels/${destinationDataModelId}/${catalogueItemDomainResourcePath}/${sourceDataModelId}/${catalogueItemId}" + "referenceDataModels/${destinationDataModelId}/${catalogueItemDomainResourcePath}/${sourceDataModelId}/${catalogueItemId}" } @Override @@ -106,13 +101,14 @@ abstract class CatalogueItemReferenceSummaryMetadataReportFunctionalSpec extends HttpResponse requestCIF01CopiedCatalogueItemFacet(HttpResponse response) { String copyId = response.body().id - GET(getCopyResourcePath(copyId), MAP_ARG, true) + GET("${catalogueItemDomainResourcePath}/${copyId}/referenceSummaryMetadata", MAP_ARG, true) } void verifyCIF01CopiedFacetSuccessfully(HttpResponse response) { verifyResponse(HttpStatus.OK, response) - assert response.body().count == 1 - assert response.body().items.size() == 1 + // summary metadata should not be copied for DC/DT/DE + assert response.body().count == 0 + assert response.body().items.size() == 0 } void 'CIF01 : Test facet copied with catalogue item'() { diff --git a/mdm-plugin-referencedata/src/main/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/traits/controller/ReferenceDataModelSecuredInterceptor.groovy b/mdm-plugin-referencedata/src/main/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/traits/controller/ReferenceDataModelSecuredInterceptor.groovy index 28151022e6..2c6a5d88d5 100644 --- a/mdm-plugin-referencedata/src/main/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/traits/controller/ReferenceDataModelSecuredInterceptor.groovy +++ b/mdm-plugin-referencedata/src/main/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/traits/controller/ReferenceDataModelSecuredInterceptor.groovy @@ -17,41 +17,28 @@ */ package uk.ac.ox.softeng.maurodatamapper.referencedata.traits.controller -import uk.ac.ox.softeng.maurodatamapper.api.exception.ApiBadRequestException -import uk.ac.ox.softeng.maurodatamapper.core.traits.controller.MdmInterceptor + +import uk.ac.ox.softeng.maurodatamapper.core.interceptor.ModelItemInterceptor import uk.ac.ox.softeng.maurodatamapper.referencedata.ReferenceDataModel -import uk.ac.ox.softeng.maurodatamapper.util.Utils /** * @since 20/03/2020 */ -abstract class ReferenceDataModelSecuredInterceptor implements MdmInterceptor { - - abstract Class getModelItemClass() - - void checkIds() { - Utils.toUuid(params, 'referenceDataModelId') - Utils.toUuid(params, 'id') - Utils.toUuid(params, 'otherReferenceDataModelId') - } - - void checkReferenceDataModelId() { - if (!params.referenceDataModelId) throw new ApiBadRequestException('DMSI01', 'No Reference Data Model Id provided against secured resource') - } +abstract class ReferenceDataModelSecuredInterceptor extends ModelItemInterceptor { - void performChecks() { - checkIds() - checkReferenceDataModelId() + @Override + Class getModelClass() { + ReferenceDataModel } - boolean checkStandardActions() { - checkActionAuthorisationOnUnsecuredResource(getModelItemClass(), params.id, ReferenceDataModel, params.referenceDataModelId) + @Override + String getModelIdParameterField() { + 'referenceDataModelId' } - boolean canReadReferenceDataModel() { - currentUserSecurityPolicyManager.userCanReadSecuredResourceId(ReferenceDataModel, params.referenceDataModelId) ?: notFound(ReferenceDataModel, - params.referenceDataModelId.toString() - ) + @Override + String getOtherModelIdParameterField() { + 'otherReferenceDataModelId' } boolean canCopyFromReferenceDataModelToOtherReferenceDataModel() { diff --git a/mdm-plugin-referencedata/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/facet/summarymetadata/ReferenceSummaryMetadataReportInterceptorSpec.groovy b/mdm-plugin-referencedata/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/facet/summarymetadata/ReferenceSummaryMetadataReportInterceptorSpec.groovy index 09de277560..c807cce5cb 100644 --- a/mdm-plugin-referencedata/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/facet/summarymetadata/ReferenceSummaryMetadataReportInterceptorSpec.groovy +++ b/mdm-plugin-referencedata/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/facet/summarymetadata/ReferenceSummaryMetadataReportInterceptorSpec.groovy @@ -19,6 +19,7 @@ package uk.ac.ox.softeng.maurodatamapper.referencedata.facet.summarymetadata import uk.ac.ox.softeng.maurodatamapper.referencedata.ReferenceDataModel import uk.ac.ox.softeng.maurodatamapper.referencedata.facet.ReferenceSummaryMetadata +import uk.ac.ox.softeng.maurodatamapper.referencedata.facet.ReferenceSummaryMetadataService import uk.ac.ox.softeng.maurodatamapper.test.unit.interceptor.VariableContainedResourceInterceptorSpec import grails.testing.web.interceptor.InterceptorUnitTest @@ -28,6 +29,9 @@ class ReferenceSummaryMetadataReportInterceptorSpec extends VariableContainedRes def setup() { mockDomains(ReferenceDataModel, ReferenceSummaryMetadata) + interceptor.referenceSummaryMetadataService = Stub(ReferenceSummaryMetadataService) { + existsByMultiFacetAwareItemIdAndId(_, _) >> true + } } @Override diff --git a/mdm-plugin-referencedata/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/item/ReferenceDataElementInterceptorSpec.groovy b/mdm-plugin-referencedata/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/item/ReferenceDataElementInterceptorSpec.groovy index 17043f50f1..220739a2bf 100644 --- a/mdm-plugin-referencedata/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/item/ReferenceDataElementInterceptorSpec.groovy +++ b/mdm-plugin-referencedata/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/item/ReferenceDataElementInterceptorSpec.groovy @@ -52,6 +52,6 @@ class ReferenceDataElementInterceptorSpec extends ContainedResourceInterceptorUn @Override String getExpectedExceptionCodeForNoContainingItem() { - 'DMSI01' + 'MII01' } } diff --git a/mdm-plugin-referencedata/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/item/datatype/ReferenceDataTypeInterceptorSpec.groovy b/mdm-plugin-referencedata/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/item/datatype/ReferenceDataTypeInterceptorSpec.groovy index 4ddc2ba2f1..985a02c4a4 100644 --- a/mdm-plugin-referencedata/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/item/datatype/ReferenceDataTypeInterceptorSpec.groovy +++ b/mdm-plugin-referencedata/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/item/datatype/ReferenceDataTypeInterceptorSpec.groovy @@ -51,6 +51,6 @@ class ReferenceDataTypeInterceptorSpec extends ContainedResourceInterceptorUnitS @Override String getExpectedExceptionCodeForNoContainingItem() { - 'DMSI01' + 'MII01' } } diff --git a/mdm-plugin-referencedata/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/item/datatype/enumeration/ReferenceEnumerationValueInterceptorSpec.groovy b/mdm-plugin-referencedata/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/item/datatype/enumeration/ReferenceEnumerationValueInterceptorSpec.groovy index 54f3380695..35d695ad3c 100644 --- a/mdm-plugin-referencedata/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/item/datatype/enumeration/ReferenceEnumerationValueInterceptorSpec.groovy +++ b/mdm-plugin-referencedata/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/referencedata/item/datatype/enumeration/ReferenceEnumerationValueInterceptorSpec.groovy @@ -22,6 +22,7 @@ import uk.ac.ox.softeng.maurodatamapper.referencedata.ReferenceDataModel import uk.ac.ox.softeng.maurodatamapper.referencedata.item.ReferenceDataElement import uk.ac.ox.softeng.maurodatamapper.referencedata.item.datatype.ReferenceDataType import uk.ac.ox.softeng.maurodatamapper.referencedata.item.datatype.ReferenceEnumerationType +import uk.ac.ox.softeng.maurodatamapper.referencedata.item.datatype.ReferenceEnumerationTypeService import uk.ac.ox.softeng.maurodatamapper.referencedata.item.datatype.ReferencePrimitiveType import uk.ac.ox.softeng.maurodatamapper.test.unit.interceptor.ContainedResourceInterceptorUnitSpec @@ -35,6 +36,9 @@ class ReferenceEnumerationValueInterceptorSpec extends ContainedResourceIntercep log.debug('Setting up ReferenceEnumerationValueInterceptorSpec') mockDomains(ReferenceDataModel, ReferenceDataElement, ReferenceDataType, ReferencePrimitiveType, ReferenceEnumerationType, ReferenceEnumerationValue) + interceptor.referenceEnumerationTypeService = Stub(ReferenceEnumerationTypeService) { + existsByReferenceDataModelIdAndId(_, _) >> true + } } @Override @@ -54,6 +58,6 @@ class ReferenceEnumerationValueInterceptorSpec extends ContainedResourceIntercep @Override String getExpectedExceptionCodeForNoContainingItem() { - 'DMSI01' + 'MII01' } } diff --git a/mdm-plugin-terminology/grails-app/conf/application.yml b/mdm-plugin-terminology/grails-app/conf/application.yml index 32b27a9bba..77582c1b0e 100644 --- a/mdm-plugin-terminology/grails-app/conf/application.yml +++ b/mdm-plugin-terminology/grails-app/conf/application.yml @@ -176,7 +176,6 @@ environments: url: 'jdbc:h2:mem:${database.name};LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE;MODE=PostgreSQL;INIT=${database.creation}' development: dataSource: - dbCreate: create-drop username: maurodatamapper password: MauroDataMapper1234 diff --git a/mdm-plugin-terminology/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/terminology/item/TermInterceptor.groovy b/mdm-plugin-terminology/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/terminology/item/TermInterceptor.groovy index 4875d9a2c4..16c61a431b 100644 --- a/mdm-plugin-terminology/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/terminology/item/TermInterceptor.groovy +++ b/mdm-plugin-terminology/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/terminology/item/TermInterceptor.groovy @@ -36,7 +36,7 @@ class TermInterceptor extends TerminologySecuredInterceptor { } @Override - void checkTerminologyId() { + void checkModelId() { if (!params.codeSetId && !params.terminologyId) { throw new ApiBadRequestException('TSI01', 'No TerminologyId or CodeSet provided against secured resource') } @@ -46,7 +46,7 @@ class TermInterceptor extends TerminologySecuredInterceptor { performChecks() if (actionName in ['search', 'tree']) { - return canReadTerminology() + return canReadModel() } if (isIndex() && params.containsKey('codeSetId')) { diff --git a/mdm-plugin-terminology/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/terminology/item/term/TermRelationshipController.groovy b/mdm-plugin-terminology/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/terminology/item/term/TermRelationshipController.groovy index 01d184491e..5a2b2794c4 100644 --- a/mdm-plugin-terminology/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/terminology/item/term/TermRelationshipController.groovy +++ b/mdm-plugin-terminology/grails-app/controllers/uk/ac/ox/softeng/maurodatamapper/terminology/item/term/TermRelationshipController.groovy @@ -19,6 +19,8 @@ package uk.ac.ox.softeng.maurodatamapper.terminology.item.term import uk.ac.ox.softeng.maurodatamapper.core.controller.CatalogueItemController +import grails.gorm.transactions.Transactional + class TermRelationshipController extends CatalogueItemController { static responseFormats = ['json', 'xml'] @@ -63,4 +65,24 @@ class TermRelationshipController extends CatalogueItemController { static constraints = { CallableConstraints.call(ModelItemConstraints, delegate) - sourceTerm validator: {val, obj -> val == obj.targetTerm ? ['invalid.same.property.message', 'targetTerm'] : true} + sourceTerm validator: {val, obj -> + if (val == obj.targetTerm) return ['invalid.same.property.message', 'targetTerm'] + if (val.terminology != obj.targetTerm.terminology) return ['invalid.relationship.different.terminologies'] + } } static mapping = { diff --git a/mdm-plugin-terminology/grails-app/i18n/messages.properties b/mdm-plugin-terminology/grails-app/i18n/messages.properties index 86d3443f4f..62d981261e 100644 --- a/mdm-plugin-terminology/grails-app/i18n/messages.properties +++ b/mdm-plugin-terminology/grails-app/i18n/messages.properties @@ -15,4 +15,5 @@ # # SPDX-License-Identifier: Apache-2.0 # - +invalid.relationship.different.terminologies=Term Relationship must use Terms from inside the same Terminology +invalid.relationship.different.terms=Term Relationship must define one of its Terms as the termId requested \ No newline at end of file diff --git a/mdm-plugin-terminology/grails-app/services/uk/ac/ox/softeng/maurodatamapper/terminology/item/TermRelationshipTypeService.groovy b/mdm-plugin-terminology/grails-app/services/uk/ac/ox/softeng/maurodatamapper/terminology/item/TermRelationshipTypeService.groovy index be98492285..81bf20bd0f 100644 --- a/mdm-plugin-terminology/grails-app/services/uk/ac/ox/softeng/maurodatamapper/terminology/item/TermRelationshipTypeService.groovy +++ b/mdm-plugin-terminology/grails-app/services/uk/ac/ox/softeng/maurodatamapper/terminology/item/TermRelationshipTypeService.groovy @@ -93,6 +93,10 @@ class TermRelationshipTypeService extends ModelItemService TermRelationshipType.byTerminologyIdAndId(terminologyId, Utils.toUuid(id)).find() } + boolean existsByTerminologyIdAndId(UUID terminologyId, Serializable id) { + TermRelationshipType.byTerminologyIdAndId(terminologyId, Utils.toUuid(id)).count() == 1 + } + @Override TermRelationshipType copy(Model copiedTerminology, TermRelationshipType original, CatalogueItem nonModelParent, UserSecurityPolicyManager userSecurityPolicyManager) { diff --git a/mdm-plugin-terminology/grails-app/services/uk/ac/ox/softeng/maurodatamapper/terminology/item/TermService.groovy b/mdm-plugin-terminology/grails-app/services/uk/ac/ox/softeng/maurodatamapper/terminology/item/TermService.groovy index e49a755d0c..db4ab2c175 100644 --- a/mdm-plugin-terminology/grails-app/services/uk/ac/ox/softeng/maurodatamapper/terminology/item/TermService.groovy +++ b/mdm-plugin-terminology/grails-app/services/uk/ac/ox/softeng/maurodatamapper/terminology/item/TermService.groovy @@ -184,6 +184,11 @@ class TermService extends ModelItemService { Term.byTerminologyId(terminologyId).id().list() as List } + boolean existsByTerminologyIdAndId(UUID terminologyId, Serializable id) { + Term.byTerminologyIdAndId(terminologyId, Utils.toUuid(id)).count() == 1 + } + + Term findByTerminologyIdAndId(UUID terminologyId, Serializable id) { Term.byTerminologyIdAndId(terminologyId, Utils.toUuid(id)).find() } diff --git a/mdm-plugin-terminology/grails-app/services/uk/ac/ox/softeng/maurodatamapper/terminology/item/term/TermRelationshipService.groovy b/mdm-plugin-terminology/grails-app/services/uk/ac/ox/softeng/maurodatamapper/terminology/item/term/TermRelationshipService.groovy index c6ab3753fb..05fffefc6a 100644 --- a/mdm-plugin-terminology/grails-app/services/uk/ac/ox/softeng/maurodatamapper/terminology/item/term/TermRelationshipService.groovy +++ b/mdm-plugin-terminology/grails-app/services/uk/ac/ox/softeng/maurodatamapper/terminology/item/term/TermRelationshipService.groovy @@ -51,6 +51,12 @@ class TermRelationshipService extends ModelItemService { TermRelationship.count() } + @Override + TermRelationship validate(TermRelationship modelItem) { + modelItem.validate() + modelItem + } + void delete(Serializable id) { TermRelationship termRelationship = get(id) if (termRelationship) delete(termRelationship) diff --git a/mdm-plugin-terminology/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/terminology/TerminologyFunctionalSpec.groovy b/mdm-plugin-terminology/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/terminology/TerminologyFunctionalSpec.groovy index a35a14758b..57ad6d3dbc 100644 --- a/mdm-plugin-terminology/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/terminology/TerminologyFunctionalSpec.groovy +++ b/mdm-plugin-terminology/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/terminology/TerminologyFunctionalSpec.groovy @@ -890,7 +890,7 @@ class TerminologyFunctionalSpec extends ResourceFunctionalSpec impl responseBody().parentalRelationship when: 'checking relationships' - GET("$id/terms/$terms.DAM/termRelationships") + GET("$branchId/terms/$terms.DAM/termRelationships") then: verifyResponse(OK, response) @@ -900,7 +900,7 @@ class TerminologyFunctionalSpec extends ResourceFunctionalSpec impl responseBody().items.first().relationshipType.id == relationshipTypes.inverseOf when: 'checking relationships' - GET("$id/terms/$terms.MLO/termRelationships") + GET("$branchId/terms/$terms.MLO/termRelationships") then: verifyResponse(OK, response) @@ -917,7 +917,7 @@ class TerminologyFunctionalSpec extends ResourceFunctionalSpec impl } when: 'checking relationships' - GET("$id/terms/$terms.SMLO/termRelationships") + GET("$branchId/terms/$terms.SMLO/termRelationships") then: verifyResponse(OK, response) diff --git a/mdm-plugin-terminology/src/main/groovy/uk/ac/ox/softeng/maurodatamapper/terminology/traits/controller/TerminologySecuredInterceptor.groovy b/mdm-plugin-terminology/src/main/groovy/uk/ac/ox/softeng/maurodatamapper/terminology/traits/controller/TerminologySecuredInterceptor.groovy index 16df759a6c..b2b2ea5bc5 100644 --- a/mdm-plugin-terminology/src/main/groovy/uk/ac/ox/softeng/maurodatamapper/terminology/traits/controller/TerminologySecuredInterceptor.groovy +++ b/mdm-plugin-terminology/src/main/groovy/uk/ac/ox/softeng/maurodatamapper/terminology/traits/controller/TerminologySecuredInterceptor.groovy @@ -17,49 +17,26 @@ */ package uk.ac.ox.softeng.maurodatamapper.terminology.traits.controller -import uk.ac.ox.softeng.maurodatamapper.api.exception.ApiBadRequestException -import uk.ac.ox.softeng.maurodatamapper.core.traits.controller.MdmInterceptor +import uk.ac.ox.softeng.maurodatamapper.core.interceptor.ModelItemInterceptor import uk.ac.ox.softeng.maurodatamapper.terminology.Terminology -import uk.ac.ox.softeng.maurodatamapper.util.Utils /** * @since 20/03/2020 */ -abstract class TerminologySecuredInterceptor implements MdmInterceptor { +abstract class TerminologySecuredInterceptor extends ModelItemInterceptor { - abstract Class getModelItemClass() - - void checkIds() { - Utils.toUuid(params, 'terminologyId') - Utils.toUuid(params, 'id') - } - - void checkTerminologyId() { - if (!params.terminologyId) throw new ApiBadRequestException('TSI01', 'No Terminology Id provided against secured resource') - } - - void performChecks() { - checkIds() - checkTerminologyId() - } - - boolean checkStandardActions() { - checkActionAuthorisationOnUnsecuredResource(getModelItemClass(), params.id, Terminology, params.terminologyId) + @Override + Class getModelClass() { + Terminology } - boolean canReadTerminology() { - currentUserSecurityPolicyManager.userCanReadSecuredResourceId(Terminology, params.terminologyId) ?: - notFound(Terminology, params.terminologyId.toString()) + @Override + String getModelIdParameterField() { + 'terminologyId' } - boolean canCopyFromTerminologyToOtherTerminology() { - boolean canRead = currentUserSecurityPolicyManager.userCanReadSecuredResourceId(Terminology, params.terminologyId) - if (!currentUserSecurityPolicyManager.userCanEditSecuredResourceId(Terminology, params.terminologyId)) { - return forbiddenOrNotFound(canRead, Terminology, params.terminologyId) - } - if (!currentUserSecurityPolicyManager.userCanReadSecuredResourceId(Terminology, params.otherTerminologyId)) { - return notFound(Terminology, params.otherTerminologyId) - } - true + @Override + String getOtherModelIdParameterField() { + 'otherTerminologyId' } } diff --git a/mdm-plugin-terminology/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/terminology/item/TermRelationshipTypeInterceptorSpec.groovy b/mdm-plugin-terminology/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/terminology/item/TermRelationshipTypeInterceptorSpec.groovy index 39bb0f302d..a5ff0079f9 100644 --- a/mdm-plugin-terminology/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/terminology/item/TermRelationshipTypeInterceptorSpec.groovy +++ b/mdm-plugin-terminology/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/terminology/item/TermRelationshipTypeInterceptorSpec.groovy @@ -50,7 +50,7 @@ class TermRelationshipTypeInterceptorSpec extends ContainedResourceInterceptorUn @Override String getExpectedExceptionCodeForNoContainingItem() { - 'TSI01' + 'MII01' } @Override diff --git a/mdm-plugin-terminology/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/terminology/item/term/TermRelationshipInterceptorSpec.groovy b/mdm-plugin-terminology/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/terminology/item/term/TermRelationshipInterceptorSpec.groovy index c30213f860..e90e0927ba 100644 --- a/mdm-plugin-terminology/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/terminology/item/term/TermRelationshipInterceptorSpec.groovy +++ b/mdm-plugin-terminology/src/test/groovy/uk/ac/ox/softeng/maurodatamapper/terminology/item/term/TermRelationshipInterceptorSpec.groovy @@ -22,6 +22,7 @@ import uk.ac.ox.softeng.maurodatamapper.terminology.CodeSet import uk.ac.ox.softeng.maurodatamapper.terminology.Terminology import uk.ac.ox.softeng.maurodatamapper.terminology.item.Term import uk.ac.ox.softeng.maurodatamapper.terminology.item.TermRelationshipType +import uk.ac.ox.softeng.maurodatamapper.terminology.item.TermService import uk.ac.ox.softeng.maurodatamapper.test.unit.interceptor.ContainedResourceInterceptorUnitSpec import grails.testing.web.interceptor.InterceptorUnitTest @@ -33,6 +34,9 @@ class TermRelationshipInterceptorSpec extends ContainedResourceInterceptorUnitSp def setup() { log.debug('Setting up TermRelationshipInterceptorSpec') mockDomains(Folder, Terminology, Term, TermRelationship, TermRelationshipType, CodeSet) + interceptor.termService = Stub(TermService) { + existsByTerminologyIdAndId(_, _) >> true + } } @Override @@ -47,7 +51,7 @@ class TermRelationshipInterceptorSpec extends ContainedResourceInterceptorUnitSp @Override String getExpectedExceptionCodeForNoContainingItem() { - 'TSI01' + 'MII01' } @Override diff --git a/mdm-testing-framework/src/main/groovy/uk/ac/ox/softeng/maurodatamapper/test/functional/facet/CatalogueItemFacetFunctionalSpec.groovy b/mdm-testing-framework/src/main/groovy/uk/ac/ox/softeng/maurodatamapper/test/functional/facet/CatalogueItemFacetFunctionalSpec.groovy index 3a98708f28..c9fd4a8655 100644 --- a/mdm-testing-framework/src/main/groovy/uk/ac/ox/softeng/maurodatamapper/test/functional/facet/CatalogueItemFacetFunctionalSpec.groovy +++ b/mdm-testing-framework/src/main/groovy/uk/ac/ox/softeng/maurodatamapper/test/functional/facet/CatalogueItemFacetFunctionalSpec.groovy @@ -22,6 +22,7 @@ import uk.ac.ox.softeng.maurodatamapper.core.container.Folder import uk.ac.ox.softeng.maurodatamapper.test.functional.ResourceFunctionalSpec import grails.gorm.transactions.Transactional +import grails.testing.spock.RunOnce import groovy.util.logging.Slf4j import org.grails.datastore.gorm.GormEntity import spock.lang.Shared @@ -45,8 +46,9 @@ abstract class CatalogueItemFacetFunctionalSpec extends Re "${getCatalogueItemDomainResourcePath()}/${getCatalogueItemId()}/${getFacetResourcePath()}" } + @RunOnce @Transactional - def setupSpec() { + def setup() { log.debug('Check and setup folder') folder = new Folder(label: 'Functional Test Folder', createdBy: FUNCTIONAL_TEST) checkAndSave(folder) diff --git a/mdm-testing-framework/src/main/groovy/uk/ac/ox/softeng/maurodatamapper/test/unit/interceptor/ResourceInterceptorUnitSpec.groovy b/mdm-testing-framework/src/main/groovy/uk/ac/ox/softeng/maurodatamapper/test/unit/interceptor/ResourceInterceptorUnitSpec.groovy index 4f7eb33f14..60101cac12 100644 --- a/mdm-testing-framework/src/main/groovy/uk/ac/ox/softeng/maurodatamapper/test/unit/interceptor/ResourceInterceptorUnitSpec.groovy +++ b/mdm-testing-framework/src/main/groovy/uk/ac/ox/softeng/maurodatamapper/test/unit/interceptor/ResourceInterceptorUnitSpec.groovy @@ -17,7 +17,6 @@ */ package uk.ac.ox.softeng.maurodatamapper.test.unit.interceptor - import uk.ac.ox.softeng.maurodatamapper.security.basic.NoAccessSecurityPolicyManager import uk.ac.ox.softeng.maurodatamapper.security.basic.PublicAccessSecurityPolicyManager import uk.ac.ox.softeng.maurodatamapper.test.unit.BaseUnitSpec