diff --git a/.travis.yml b/.travis.yml index e7a68b42e0..dde58a2c47 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,11 +14,8 @@ addons: artifacts: paths: - $HOME/reports - apt: - packages: - - mysql-server-5.6 - - mysql-client-core-5.6 - - mysql-client-5.6 +services: + - mysql env: - TEST_SUITE=functional - TEST_SUITE=unit_and_integration diff --git a/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/bs/catalogue.coffee b/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/bs/catalogue.coffee index 92a37512ec..f320dcdbae 100644 --- a/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/bs/catalogue.coffee +++ b/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/bs/catalogue.coffee @@ -27,6 +27,7 @@ angular.module('mc.core.ui.bs.catalogue', ['mc.core.catalogue']).config ['catalo catalogueProvider.setIcon 'mapping', "fa fa-fw fa-superscript" catalogueProvider.setIcon 'validationRule', "fa fa-fw fa-university" catalogueProvider.setIcon 'dataModelPolicy', "fa fa-fw fa-check-square-o" + catalogueProvider.setIcon 'tag', "fa fa-fw fa-tag" # this should be generated automatically in the future @@ -44,6 +45,7 @@ angular.module('mc.core.ui.bs.catalogue', ['mc.core.catalogue']).config ['catalo catalogueProvider.setInstanceOf 'model', 'catalogueElement' catalogueProvider.setInstanceOf 'dataElement', 'catalogueElement' catalogueProvider.setInstanceOf 'validationRule', 'catalogueElement' + catalogueProvider.setInstanceOf 'tag', 'catalogueElement' catalogueProvider.setInstanceOf 'enumeratedType', 'dataType' catalogueProvider.setInstanceOf 'referenceType', 'dataType' @@ -145,6 +147,14 @@ angular.module('mc.core.ui.bs.catalogue', ['mc.core.catalogue']).config ['catalo return 0.5 if list.base.indexOf("/asset") >= 0 + return 0 + ] + catalogueProvider.addContainsCandidateTest ['list', 'element', 'extra', (list, newElement, extra) -> + return 0 unless list + return 0 unless list.base + + return 0.5 if list.base.indexOf("/tag/forDataModel") >= 0 and newElement.isInstanceOf('dataElement') + return 0 ] ] diff --git a/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/bs/catalogueElementProperties.coffee b/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/bs/catalogueElementProperties.coffee index 8846602c4b..a40ac67680 100644 --- a/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/bs/catalogueElementProperties.coffee +++ b/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/bs/catalogueElementProperties.coffee @@ -53,6 +53,7 @@ angular.module('mc.core.ui.bs.catalogueElementProperties', []).config ['catalogu catalogueElementPropertiesProvider.configureProperty 'ext', label: 'Metadata' catalogueElementPropertiesProvider.configureProperty 'contextFor', label: 'Rules' catalogueElementPropertiesProvider.configureProperty 'involvedIn', label: 'Rules' + catalogueElementPropertiesProvider.configureProperty 'tags', label: 'Data Elements' catalogueElementPropertiesProvider.configureProperty 'childOf', label: 'Parents', columns: nameAndIdent() catalogueElementPropertiesProvider.configureProperty 'isContextFor', label: 'Data Classes', columns: nameAndIdent() catalogueElementPropertiesProvider.configureProperty 'containedIn', label: 'Data Classes', columns: nameAndIdAndMetadata() @@ -240,6 +241,7 @@ angular.module('mc.core.ui.bs.catalogueElementProperties', []).config ['catalogu catalogueElementPropertiesProvider.configureProperty 'originalDataModels', hidden: true catalogueElementPropertiesProvider.configureProperty 'internalModelCatalogueId', hidden: true catalogueElementPropertiesProvider.configureProperty 'versionNumber', hidden: true + catalogueElementPropertiesProvider.configureProperty 'isTaggedBy', hidden: true catalogueElementPropertiesProvider.configureProperty '$$relationship', tabDefinition: [ '$element', '$name', ($element, $name) -> diff --git a/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/bs/columns.coffee b/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/bs/columns.coffee index e35030b535..7d15bb4899 100644 --- a/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/bs/columns.coffee +++ b/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/bs/columns.coffee @@ -90,6 +90,7 @@ angular.module('mc.core.ui.bs.columns', ['mc.util.names']).config ['columnsProvi columnsProvider.registerColumns 'org.modelcatalogue.core.DataClass', modelIdNameAndDescriptionColumns() columnsProvider.registerColumns 'org.modelcatalogue.core.DataElement', modelIdNameAndDescriptionColumns() columnsProvider.registerColumns 'org.modelcatalogue.core.ValidationRule', modelIdNameAndDescriptionColumns() + columnsProvider.registerColumns 'org.modelcatalogue.core.Tags', modelIdNameAndDescriptionColumns() # special diff --git a/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/bs/detailSections.coffee b/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/bs/detailSections.coffee index 13210489f2..2dc2b1f292 100644 --- a/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/bs/detailSections.coffee +++ b/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/bs/detailSections.coffee @@ -470,4 +470,59 @@ x in ['apple', 'banana', 'cherry'] ] } } + + detailSectionsProvider.register { + title: 'Tags' + position: 70 + types: [ + 'dataElement' + ] + keys: [] + template: '/mc/core/ui/detail-sections/tableData.html' + actions: [ + { + label: 'Add Tag' + name: 'add' + icon: 'fa fa-plus-circle text-success' + action: (messages, element) -> + messages.prompt('Add Tag', '', + { + type: 'create-new-relationship' + element: element + relationshipTypeName: 'tag' + direction: "destinationToSource" + } + ) + } + ] + + getList: (element) -> + return @result if @result + + @result = + base: element.isTaggedBy.base + itemType: element.isTaggedBy.itemType + + element.isTaggedBy(null, max: LIST_MAX).then (list) => + @result = list + return @result + reorder: reorderInDetail('isTaggedBy') + data: { + columns: + [ + { + header: 'Name' + value: "ext.get('name') || ext.get('Name') || relation.name " + classes: 'col-md-6' + href: 'relation.href()' + } + { + header: 'Description' + value: "relation.description" + classes: 'col-md-6' + textEllipsis: true + } + ] + } + } ] diff --git a/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/bs/index.coffee b/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/bs/index.coffee index d8a33d0402..c28b9bed38 100644 --- a/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/bs/index.coffee +++ b/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/bs/index.coffee @@ -58,6 +58,7 @@ angular.module('mc.core.ui.bs', [ 'mc.core.ui.bs.modalPromptBasicEdit' 'mc.core.ui.bs.modalPromptMeasurementUnitEdit' 'mc.core.ui.bs.modalPromptEnumeratedTypeEdit' + 'mc.core.ui.bs.modalPromptTagEdit' 'mc.core.ui.bs.modalPromptActionParametersEdit' 'mc.core.ui.bs.modalPromptModel' 'mc.core.ui.bs.modalPromptRelationshipTypeEdit' diff --git a/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/bs/modals/modalPromptTagEdit.coffee b/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/bs/modals/modalPromptTagEdit.coffee new file mode 100644 index 0000000000..cffa5869f1 --- /dev/null +++ b/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/bs/modals/modalPromptTagEdit.coffee @@ -0,0 +1,67 @@ +angular.module('mc.core.ui.bs.modalPromptTagEdit', ['mc.util.messages', 'mc.core.ui.bs.withClassificationCtrlMixin']).config ['messagesProvider', (messagesProvider)-> + factory = [ '$uibModal', '$q', 'messages', ($uibModal, $q, messages) -> + (title, body, args) -> + if not args?.element? and not args?.create? + messages.error('Cannot create relationship dialog.', 'The element to be edited is missing.') + return $q.reject('Missing element argument!') + + dialog = $uibModal.open { + windowClass: 'basic-edit-modal-prompt' + size: 'lg' + template: ''' + + + + ''' + controller: ['$scope', 'messages', '$controller', '$uibModalInstance', ($scope, messages, $controller, $uibModalInstance) -> + $scope.pending = {dataModel: null} + $scope.newEntity = -> {dataModels: $scope.copy?.dataModels ? []} + $scope.copy = angular.copy(args.element ? $scope.newEntity()) + $scope.original = args.element ? {} + $scope.messages = messages.createNewMessages() + $scope.create = args.create + $scope.currentDataModel = args.currentDataModel + + angular.extend(this, $controller('withClassificationCtrlMixin', {$scope: $scope})) + angular.extend(this, $controller('saveAndCreateAnotherCtrlMixin', {$scope: $scope, $uibModalInstance: $uibModalInstance})) + + $scope.hasChanged = -> + $scope.copy.name != $scope.original.name\ + or $scope.copy.description != $scope.original.description\ + or $scope.copy.modelCatalogueId != $scope.original.modelCatalogueId + + ] + + } + + dialog.result + ] + + messagesProvider.setPromptFactory 'edit-tag', factory +] diff --git a/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/catalogueElementView.coffee b/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/catalogueElementView.coffee index e7cb1415e2..70c4593677 100644 --- a/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/catalogueElementView.coffee +++ b/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/catalogueElementView.coffee @@ -235,6 +235,7 @@ angular.module('mc.core.ui.catalogueElementView', ['mc.core.catalogueElementEnha or $scope.element?.isInstanceOf('measurementUnit')\ or $scope.element?.isInstanceOf('dataElement')\ or $scope.element?.isInstanceOf('validationRule')\ + or $scope.element?.isInstanceOf('tag')\ )\ and ($scope.element?.status == 'DRAFT' or security.hasRole('SUPERVISOR')) diff --git a/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/metadataEditor.coffee b/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/metadataEditor.coffee index 425b663f4d..ad84ce82de 100644 --- a/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/metadataEditor.coffee +++ b/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/metadataEditor.coffee @@ -59,12 +59,13 @@ angular.module('mc.core.ui.metadataEditor', ['mc.core.ui.metadataEditors']).dire $scope.handledKeys = [] onObjectChanged = (object) -> - if object and not isOrderedMap(object) - $log.error "Object", object, "is not ordered map" - return + if object + unless isOrderedMap(object) + $log.error "Object", object, "is not ordered map" + return - object.clearIfOnlyContainsPlaceholder() - object.addPlaceholderIfEmpty() + object.clearIfOnlyContainsPlaceholder() + object.addPlaceholderIfEmpty() onObjectChanged($scope.object) diff --git a/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/states/controllers/DataModelTreeCtrl.coffee b/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/states/controllers/DataModelTreeCtrl.coffee index 1ebaa8fe28..f91a0c1db0 100644 --- a/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/states/controllers/DataModelTreeCtrl.coffee +++ b/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/states/controllers/DataModelTreeCtrl.coffee @@ -12,6 +12,12 @@ angular.module('mc.core.ui.states.controllers.DataModelTreeCtrl', ['ui.router', if element.resource if element.getDataModelId() == currentDataModel?.id + if element.tagId + if element.tagId == 'none' + $state.go 'mc.resource.list', dataModelId: currentDataModel?.id, resource: 'dataElement', status: 'active', tag: 'none' + return + $state.go 'mc.resource.show.property', dataModelId: currentDataModel?.id, resource: 'tag', id: element.tagId, property: 'tags' + return if element.resource == 'catalogueElement' && element.name == 'Deprecated Items' $state.go 'mc.resource.list', dataModelId: currentDataModel?.id, resource: element.resource, status: 'deprecated' return diff --git a/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/states/mc.resource.list.state.coffee b/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/states/mc.resource.list.state.coffee index fcc40af37a..484ff92edf 100644 --- a/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/states/mc.resource.list.state.coffee +++ b/ModelCatalogueCorePluginTestApp/grails-app/assets/javascripts/modelcatalogue/core/ui/states/mc.resource.list.state.coffee @@ -5,7 +5,7 @@ angular.module('mc.core.ui.states.mc.resource.list', ['mc.core.ui.states.control DEFAULT_ITEMS_PER_PAGE = 25 $stateProvider.state 'mc.resource.list', { - url: '/all?page&order&sort&status&q&max&classification&display' + url: '/all?page&order&sort&status&q&max&classification&display&tag' views: "": @@ -31,6 +31,7 @@ angular.module('mc.core.ui.states.mc.resource.list', ['mc.core.ui.states.control params.status = $stateParams.status params.max = $stateParams.max ? DEFAULT_ITEMS_PER_PAGE params.classification = $stateParams.classification ? undefined + params.tag = $stateParams.tag ? undefined if $stateParams.dataModelId and $stateParams.dataModelId != 'catalogue' params.dataModel = $stateParams.dataModelId @@ -43,4 +44,4 @@ angular.module('mc.core.ui.states.mc.resource.list', ['mc.core.ui.states.control } -]) \ No newline at end of file +]) diff --git a/ModelCatalogueCorePluginTestApp/grails-app/assets/other/schema/2.1/metadataregistry.xsd b/ModelCatalogueCorePluginTestApp/grails-app/assets/other/schema/2.1/metadataregistry.xsd index 9f0b4c044e..e8cffafb81 100644 --- a/ModelCatalogueCorePluginTestApp/grails-app/assets/other/schema/2.1/metadataregistry.xsd +++ b/ModelCatalogueCorePluginTestApp/grails-app/assets/other/schema/2.1/metadataregistry.xsd @@ -1,8 +1,8 @@ diff --git a/ModelCatalogueCorePluginTestApp/grails-app/assets/other/schema/2.2/metadataregistry.xsd b/ModelCatalogueCorePluginTestApp/grails-app/assets/other/schema/2.2/metadataregistry.xsd new file mode 100644 index 0000000000..a98dcfebbc --- /dev/null +++ b/ModelCatalogueCorePluginTestApp/grails-app/assets/other/schema/2.2/metadataregistry.xsd @@ -0,0 +1,396 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The Reference can must always contain at least "ref" attribute or "name". If the "dataModel" is + provided the name will be searched only within this data model. Also if element of this type + is used inside element of type "DataModel" it is assumed that the element should be searched by name + within the surrounding data model. This does not apply on elements having the "ref" attribute + provided. In that case the element is resolved by the ID. The type of the catalogue element can + be provided to distinguish between elements having same name and data model but different types + (this is quite common for value domains and it's data types) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CatalogueElement is either a in-lined definition of the element or a reference to the existing element. + If "ref" attribute is set, any other attributes or nested elements are ignored. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ModelCatalogueCorePluginTestApp/grails-app/assets/other/schema/2.2/metadataregistry_asset.xsd b/ModelCatalogueCorePluginTestApp/grails-app/assets/other/schema/2.2/metadataregistry_asset.xsd new file mode 100644 index 0000000000..ed1205736d --- /dev/null +++ b/ModelCatalogueCorePluginTestApp/grails-app/assets/other/schema/2.2/metadataregistry_asset.xsd @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ModelCatalogueCorePluginTestApp/grails-app/assets/other/schema/2.2/metadataregistry_validator.xsd b/ModelCatalogueCorePluginTestApp/grails-app/assets/other/schema/2.2/metadataregistry_validator.xsd new file mode 100644 index 0000000000..49276bfe5a --- /dev/null +++ b/ModelCatalogueCorePluginTestApp/grails-app/assets/other/schema/2.2/metadataregistry_validator.xsd @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + diff --git a/ModelCatalogueCorePluginTestApp/grails-app/assets/other/schema/2.2/metadataregistry_violation.xsd b/ModelCatalogueCorePluginTestApp/grails-app/assets/other/schema/2.2/metadataregistry_violation.xsd new file mode 100644 index 0000000000..c375c8ae0d --- /dev/null +++ b/ModelCatalogueCorePluginTestApp/grails-app/assets/other/schema/2.2/metadataregistry_violation.xsd @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + diff --git a/ModelCatalogueCorePluginTestApp/grails-app/assets/other/xsl/transform2CatalogueSchema.xsl b/ModelCatalogueCorePluginTestApp/grails-app/assets/other/xsl/transform2CatalogueSchema.xsl index 99a645438e..08187541fe 100644 --- a/ModelCatalogueCorePluginTestApp/grails-app/assets/other/xsl/transform2CatalogueSchema.xsl +++ b/ModelCatalogueCorePluginTestApp/grails-app/assets/other/xsl/transform2CatalogueSchema.xsl @@ -1,7 +1,7 @@ diff --git a/ModelCatalogueCorePluginTestApp/grails-app/conf/BootStrap.groovy b/ModelCatalogueCorePluginTestApp/grails-app/conf/BootStrap.groovy index 997fbe1341..3b0cd604d3 100644 --- a/ModelCatalogueCorePluginTestApp/grails-app/conf/BootStrap.groovy +++ b/ModelCatalogueCorePluginTestApp/grails-app/conf/BootStrap.groovy @@ -50,7 +50,7 @@ class BootStrap { if (Environment.current in [Environment.DEVELOPMENT, Environment.TEST] && !System.getenv('MC_BLANK_DEV')) { TestDataHelper.initFreshDb(sessionFactory, 'initTestDatabase.sql') { initCatalogueService.initCatalogue(true) - initDataModelPolicies() + initPoliciesAndTags() initSecurity(false) setupStuff() } @@ -59,7 +59,7 @@ class BootStrap { } } else { initCatalogueService.initDefaultRelationshipTypes() - initDataModelPolicies() + initPoliciesAndTags() initSecurity(!System.getenv('MC_BLANK_DEV')) } @@ -417,7 +417,7 @@ class BootStrap { // createRequestmapIfMissing('/api/modelCatalogue/core/relationshipTypes/**', 'ROLE_ADMIN') } - def initDataModelPolicies() { + def initPoliciesAndTags() { catalogueBuilder.build { dataModelPolicy(name: 'Unique of Kind') { check dataClass property 'name' is 'unique' @@ -439,6 +439,19 @@ class BootStrap { check dataType property 'name' is 'unique' otherwise 'Data type\'s name is not unique for {2}' check dataType property 'name' apply regex: /[^_ -]+/ otherwise 'Name of {2} contains illegal characters ("_", "-" or " ")' } + dataModel(name: 'Clinical Tags') { + tag(name: 'Registration, consent and demographic data essential for the management of the participant') + tag(name: 'Sample tracking data essential for processing and tracking the sample from collection through to sequencing') + tag(name: 'Clinical data essential for diagnostics purposes') + tag(name: 'Clinical data essential for research') + tag(name: 'Clinical data for research') + tag(name: 'Highly Sensitive PI data') + tag(name: 'Sensitive PI data') + tag(name: 'Highly Sensitive data') + tag(name: 'Sensitive data') + tag(name: 'Internal data') + tag(name: 'External data') + } } } diff --git a/ModelCatalogueCorePluginTestApp/grails-app/conf/BuildConfig.groovy b/ModelCatalogueCorePluginTestApp/grails-app/conf/BuildConfig.groovy index 42172244ed..201e6e49ff 100644 --- a/ModelCatalogueCorePluginTestApp/grails-app/conf/BuildConfig.groovy +++ b/ModelCatalogueCorePluginTestApp/grails-app/conf/BuildConfig.groovy @@ -68,7 +68,7 @@ grails.project.dependency.resolution = { // compile 'io.reactivex:rxgroovy:1.0.3' - String mcToolkitVersion = '2.1.0.2' + String mcToolkitVersion = '2.2.0' compile "org.modelcatalogue:mc-core-api:$mcToolkitVersion" compile "org.modelcatalogue:mc-builder-api:$mcToolkitVersion" compile "org.modelcatalogue:mc-datatype-validation:$mcToolkitVersion" diff --git a/ModelCatalogueCorePluginTestApp/grails-app/conf/Config.groovy b/ModelCatalogueCorePluginTestApp/grails-app/conf/Config.groovy index 0952d17a5c..5306c0c780 100644 --- a/ModelCatalogueCorePluginTestApp/grails-app/conf/Config.groovy +++ b/ModelCatalogueCorePluginTestApp/grails-app/conf/Config.groovy @@ -4,6 +4,7 @@ import org.modelcatalogue.core.CatalogueElement import org.modelcatalogue.core.DataClass import org.modelcatalogue.core.DataElement import org.modelcatalogue.core.DataModel +import org.modelcatalogue.core.Tag import org.modelcatalogue.core.ValidationRule import org.modelcatalogue.core.security.User @@ -244,10 +245,10 @@ log4j.main = { // debug 'org.springframework.security' // debug 'org.grails.plugins.elasticsearch' - //if (Environment.current == Environment.DEVELOPMENT || Environment.current == Environment.CUSTOM) { - // trace 'org.hibernate.type' - // trace 'org.hibernate.stat' - // debug 'org.hibernate.SQL' +// if (Environment.current == Environment.DEVELOPMENT || Environment.current == Environment.CUSTOM) { +// trace 'org.hibernate.type' +// trace 'org.hibernate.stat' +// debug 'org.hibernate.SQL' // } info 'org.modelcatalogue' @@ -434,4 +435,5 @@ modelcatalogue.defaults.relationshiptypes = [ [name: "classificationFilter", sourceToDestination: "used as filter by", destinationToSource: "filtered by", sourceClass: DataModel, destinationClass: User, system: true, sourceToDestinationDescription: "Classification can be used as filter by multiple users. This is done using the classification filter in bottom left corner.", destinationToSourceDescription: "User can filter by multiple classifications. To use exclusion filter instead of inclusion, set metadata \$exclude to any non-null value."], [name: "ruleContext", destinationToSource: "provides context for", sourceToDestination: "applied within context", sourceClass: ValidationRule, destinationClass: DataClass, versionSpecific: true, destinationToSourceDescription: "Data class can provide context for multiple validation rules", sourceToDestinationDescription: "Validation rule is applied within context of data class."], [name: "involvedness", destinationToSource: "is involved in", sourceToDestination: "involves", sourceClass: ValidationRule, destinationClass: DataElement, versionSpecific: true, destinationToSourceDescription: "Data element can be involved in multiple validation rules", sourceToDestinationDescription: "Validation rule can involve multiple data elements"], + [name: "tag", sourceToDestination: "tags", destinationToSource: "is tagged by", sourceClass: Tag, destinationClass: DataElement, versionSpecific: false, sourceToDestinationDescription: "Applies Tag on particular Data Element", destinationToSourceDescription: "Data Elements can be tagged by multiple Tags"], ] diff --git a/ModelCatalogueCorePluginTestApp/grails-app/conf/DataSource.groovy b/ModelCatalogueCorePluginTestApp/grails-app/conf/DataSource.groovy index d410ae3a64..c173767275 100644 --- a/ModelCatalogueCorePluginTestApp/grails-app/conf/DataSource.groovy +++ b/ModelCatalogueCorePluginTestApp/grails-app/conf/DataSource.groovy @@ -14,9 +14,28 @@ environments { driverClassName = "org.h2.Driver" username = "sa" password = "" - dbCreate = "create-drop" // one of 'create', 'create-drop', 'update', 'validate', '' - url = "jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE" + dbCreate = "update" // one of 'create', 'create-drop', 'update', 'validate', '' + url = "jdbc:h2:mem:testDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE" } + /**dataSource { + driverClassName = "com.mysql.jdbc.Driver" + dialect='org.hibernate.dialect.MySQL5InnoDBDialect' + url = "jdbc:mysql://localhost:3306/basic?autoReconnect=true&useUnicode=yes" + username = 'metadata' + password = 'metadata' + dbCreate = "update" + properties { + maxActive = -1 + minEvictableIdleTimeMillis=1800000 + timeBetweenEvictionRunsMillis=1800000 + numTestsPerEvictionRun=3 + testOnBorrow=true + testWhileIdle=true + testOnReturn=false + validationQuery="SELECT 1" + jdbcInterceptors="ConnectionState" + } + }**/ } test { if (System.getenv('TRAVIS') && System.getenv('TEST_SUITE') == 'functional') { diff --git a/ModelCatalogueCorePluginTestApp/grails-app/conf/ModelCatalogueCorePluginUrlMappings.groovy b/ModelCatalogueCorePluginTestApp/grails-app/conf/ModelCatalogueCorePluginUrlMappings.groovy index 8d4f138e00..154fe28776 100644 --- a/ModelCatalogueCorePluginTestApp/grails-app/conf/ModelCatalogueCorePluginUrlMappings.groovy +++ b/ModelCatalogueCorePluginTestApp/grails-app/conf/ModelCatalogueCorePluginUrlMappings.groovy @@ -22,7 +22,7 @@ class ModelCatalogueCorePluginUrlMappings { def legacyElements = [model: 'dataClass', classification: 'dataModel'] def resources = ['batch', 'relationshipType', 'csvTransformation', 'dataModelPolicy' ] - def catalogueElements = ['asset', 'dataElement', 'dataClass', 'catalogueElement', 'dataType', 'enumeratedType', 'referenceType', 'primitiveType', 'measurementUnit', 'user', 'dataModel', 'classification', 'model', 'validationRule'] + def catalogueElements = ['asset', 'dataElement', 'dataClass', 'catalogueElement', 'dataType', 'enumeratedType', 'referenceType', 'primitiveType', 'measurementUnit', 'user', 'dataModel', 'classification', 'model', 'validationRule', 'tag'] def allElements = catalogueElements + resources for (String elementName in allElements) { @@ -30,6 +30,11 @@ class ModelCatalogueCorePluginUrlMappings { if (elementName in legacyElements.keySet()) { controllerName = legacyElements[elementName] } + + if (controllerName == 'tag') { + "/api/modelCatalogue/core/$elementName/forDataModel/$dataModelId"(controller: controllerName, action: 'forDataModel', method: HttpMethod.GET) + } + "/api/modelCatalogue/core/$elementName" (controller: controllerName, action: 'index', method: HttpMethod.GET) "/api/modelCatalogue/core/$elementName" (controller: controllerName, action: 'save', method: HttpMethod.POST) diff --git a/ModelCatalogueCorePluginTestApp/grails-app/conf/spring/resources.groovy b/ModelCatalogueCorePluginTestApp/grails-app/conf/spring/resources.groovy index b51b82daaa..ecadb0e9f1 100644 --- a/ModelCatalogueCorePluginTestApp/grails-app/conf/spring/resources.groovy +++ b/ModelCatalogueCorePluginTestApp/grails-app/conf/spring/resources.groovy @@ -41,6 +41,7 @@ import org.modelcatalogue.core.util.marshalling.ReferenceTypeMarshaller import org.modelcatalogue.core.util.marshalling.RelationshipMarshallers import org.modelcatalogue.core.util.marshalling.RelationshipTypeMarshaller import org.modelcatalogue.core.util.marshalling.RelationshipsMarshaller +import org.modelcatalogue.core.util.marshalling.TagMarshaller import org.modelcatalogue.core.util.marshalling.UserMarshaller import org.modelcatalogue.core.util.marshalling.ValidationRuleMarshaller import org.modelcatalogue.core.xml.render.RelationshipsXmlRenderer @@ -112,7 +113,8 @@ beans = { new ChangeMarshaller(), new ValidationRuleMarshaller(), new ProgressMonitorMarshaller(), - new DataModelPolicyMarshaller() + new DataModelPolicyMarshaller(), + new TagMarshaller() ] } diff --git a/ModelCatalogueCorePluginTestApp/grails-app/controllers/org/modelcatalogue/core/DataElementController.groovy b/ModelCatalogueCorePluginTestApp/grails-app/controllers/org/modelcatalogue/core/DataElementController.groovy index 6365052712..5b3b6e59ac 100644 --- a/ModelCatalogueCorePluginTestApp/grails-app/controllers/org/modelcatalogue/core/DataElementController.groovy +++ b/ModelCatalogueCorePluginTestApp/grails-app/controllers/org/modelcatalogue/core/DataElementController.groovy @@ -2,6 +2,7 @@ package org.modelcatalogue.core import grails.util.Environment import org.hibernate.SessionFactory +import org.modelcatalogue.core.util.DataModelFilter import org.modelcatalogue.core.util.lists.ListWithTotalAndType import org.modelcatalogue.core.util.lists.ListWrapper import org.modelcatalogue.core.util.lists.Lists @@ -33,13 +34,53 @@ class DataElementController extends AbstractCatalogueElementController getAllEffectiveItems(Integer max) { - if (!params.long("dataModel") || sessionFactory.currentSession.connection().metaData.databaseProductName != 'MySQL') { + if (isDatabaseFallback()) { return super.getAllEffectiveItems(max) } return Lists.wrap(params, "/${resourceName}/", dataElementService.findAllDataElementsInModel(params, DataModel.get(params.long('dataModel')))) } + private boolean isDatabaseFallback() { + !params.long("dataModel") || sessionFactory.currentSession.connection().metaData.databaseProductName != 'MySQL' + } + + @Override + protected Closure buildAdditionalIndexCriteria() { + if (!hasAdditionalIndexCriteria()) { + return super.buildAdditionalIndexCriteria() + } + + if (params.tag in ['none', 'null', 'undefined']) { + // TODO: this is far to be optimal solution + return { + not { + inList 'id', Relationship.where { relationshipType == RelationshipType.tagType }.distinct('destination').list()*.id + } + } + } + + Long tagID = params.long('tag') + + Tag tag = Tag.get(tagID) + + if (!tag) { + return super.buildAdditionalIndexCriteria() + } + + return { + incomingRelationships { + eq 'source', tag + eq 'relationshipType', RelationshipType.tagType + } + } + } } diff --git a/ModelCatalogueCorePluginTestApp/grails-app/controllers/org/modelcatalogue/core/DataModelController.groovy b/ModelCatalogueCorePluginTestApp/grails-app/controllers/org/modelcatalogue/core/DataModelController.groovy index 7df50f8574..9d09ddc634 100644 --- a/ModelCatalogueCorePluginTestApp/grails-app/controllers/org/modelcatalogue/core/DataModelController.groovy +++ b/ModelCatalogueCorePluginTestApp/grails-app/controllers/org/modelcatalogue/core/DataModelController.groovy @@ -110,11 +110,12 @@ class DataModelController extends AbstractCatalogueElementController List contentDescriptors = [] contentDescriptors << createContentDescriptor(dataModel, 'Data Classes', DataClass, dataClasses.total) - contentDescriptors << createContentDescriptor(dataModel, 'Data Elements', DataElement, Integer.MAX_VALUE) + contentDescriptors << createDataElementsByTagDescriptor(dataModel) contentDescriptors << createContentDescriptor(dataModel, 'Data Types', DataType, Integer.MAX_VALUE) contentDescriptors << createContentDescriptor(dataModel, 'Measurement Units', MeasurementUnit, stats["totalMeasurementUnitCount"]) contentDescriptors << createContentDescriptor(dataModel, 'Business Rules', ValidationRule, stats["totalValidationRuleCount"]) contentDescriptors << createContentDescriptor(dataModel, 'Assets', Asset, stats["totalAssetCount"]) + contentDescriptors << createContentDescriptor(dataModel, 'Tags', Tag, stats["totalTagCount"]) if (dataModel.status != ElementStatus.DEPRECATED) { Map deprecatedItems = createContentDescriptor(dataModel, 'Deprecated Items', CatalogueElement, stats["deprecatedCatalogueElementCount"]) @@ -146,6 +147,19 @@ class DataModelController extends AbstractCatalogueElementController respond dataModelService.findDependents(dataModel) } + private static Map createDataElementsByTagDescriptor(DataModel dataModel) { + String link = "/tag/forDataModel/${dataModel.getId()}?status=${dataModel.status != ElementStatus.DEPRECATED ? 'active' : ''}" + Map ret = [:] + ret.id = 'forDataModel' + ret.dataModels = [CatalogueElementMarshaller.minimalCatalogueElementJSON(dataModel)] + ret.elementType = DataElement.name + ret.name = 'Data Elements' + ret.content = [count: DataModelService.allTags(dataModel).size() + 2, itemType: Tag.name, link: link] + ret.link = link + ret.resource = GrailsNameUtils.getPropertyName(DataElement) + ret.status = dataModel.status.toString() + ret + } private static Map createContentDescriptor(DataModel dataModel, String name, Class clazz, long count) { String link = "/${GrailsNameUtils.getPropertyName(clazz)}?toplevel=true&dataModel=${dataModel.getId()}&status=${dataModel.status != ElementStatus.DEPRECATED ? 'active' : ''}" diff --git a/ModelCatalogueCorePluginTestApp/grails-app/controllers/org/modelcatalogue/core/MeasurementUnitController.groovy b/ModelCatalogueCorePluginTestApp/grails-app/controllers/org/modelcatalogue/core/MeasurementUnitController.groovy index 79c4f647ab..816ccbfaa3 100644 --- a/ModelCatalogueCorePluginTestApp/grails-app/controllers/org/modelcatalogue/core/MeasurementUnitController.groovy +++ b/ModelCatalogueCorePluginTestApp/grails-app/controllers/org/modelcatalogue/core/MeasurementUnitController.groovy @@ -34,5 +34,4 @@ class MeasurementUnitController extends AbstractCatalogueElementController { + + SessionFactory sessionFactory + + TagController() { + super(Tag, false) + } + + @Override + protected boolean hasUniqueName() { + true + } + + + def forDataModel() { + final Long dataModelId = params.long('dataModelId') + + if (!dataModelId) { + notFound() + return + } + + final DataModel dataModel = DataModel.get(dataModelId) + + if (!dataModel) { + notFound() + return + } + + respond Lists.wrap(params, "/${resourceName}/forDataModel/${dataModelId}", Lists.lazy([:], Map, { + DataModel model = DataModel.get(dataModelId) + List tags = sessionFactory.currentSession.connection().metaData.databaseProductName != 'MySQL' ? DataModelService.allTags(model) : dataModelService.allTagsMySQL(model) + + List> ret = [createAllDataElementsDescriptor(model), createUntaggedDescriptor(model)] + + for (tag in tags) { + ret << createTagContentDescriptor(tag, model) + } + + return ret + })) + } + + private static Map createUntaggedDescriptor(DataModel dataModel) { + String link = "/dataElement?tag=none&dataModel=${dataModel.getId()}&status=${dataModel.status != ElementStatus.DEPRECATED ? 'active' : ''}" + Map ret = [:] + ret.id = 'notags' + ret.dataModels = [CatalogueElementMarshaller.minimalCatalogueElementJSON(dataModel)] + ret.elementType = Tag.name + ret.name = 'No tags' + ret.content = [count: Integer.MAX_VALUE, itemType: DataElement.name, link: link] + ret.link = link + ret.resource = GrailsNameUtils.getPropertyName(Tag) + ret.status = dataModel.status.toString() + ret.tagId = 'none' + ret + } + + private static Map createAllDataElementsDescriptor(DataModel dataModel) { + String link = "/dataElement?deep=true&dataModel=${dataModel.getId()}&status=${dataModel.status != ElementStatus.DEPRECATED ? 'active' : ''}" + Map ret = [:] + ret.id = 'all' + ret.dataModels = [CatalogueElementMarshaller.minimalCatalogueElementJSON(dataModel)] + ret.elementType = Tag.name + ret.name = 'All (including imports)' + ret.content = [count: Integer.MAX_VALUE, itemType: DataElement.name, link: link] + ret.link = link + ret.resource = GrailsNameUtils.getPropertyName(Tag) + ret.status = dataModel.status.toString() + ret.tagId = 'all' + ret + } + + private static Map createTagContentDescriptor(CatalogueElement tag, DataModel dataModel) { + String link = "/dataElement?tag=${tag.getId()}&dataModel=${dataModel.getId()}&status=${dataModel.status != ElementStatus.DEPRECATED ? 'active' : ''}" + Map ret = [:] + ret.id = 'tag-' + tag.id + ret.dataModels = [CatalogueElementMarshaller.minimalCatalogueElementJSON(dataModel)] + ret.elementType = Tag.name + ret.name = tag?.name ?: 'No Tag' + ret.content = [count: Integer.MAX_VALUE, itemType: DataElement.name, link: link] + ret.link = link + ret.resource = GrailsNameUtils.getPropertyName(Tag) + ret.status = dataModel.status.toString() + ret.tagId = tag.id + ret + } + +} diff --git a/ModelCatalogueCorePluginTestApp/grails-app/domain/org/modelcatalogue/core/DataElement.groovy b/ModelCatalogueCorePluginTestApp/grails-app/domain/org/modelcatalogue/core/DataElement.groovy index 765b2c9c46..63cf4e8dfd 100644 --- a/ModelCatalogueCorePluginTestApp/grails-app/domain/org/modelcatalogue/core/DataElement.groovy +++ b/ModelCatalogueCorePluginTestApp/grails-app/domain/org/modelcatalogue/core/DataElement.groovy @@ -21,7 +21,7 @@ class DataElement extends CatalogueElement { } static relationships = [ - incoming: [containment: 'containedIn', involvedness: 'involvedIn'] + incoming: [containment: 'containedIn', involvedness: 'involvedIn', tag: 'isTaggedBy'] ] static fetchMode = [dataType: 'eager'] diff --git a/ModelCatalogueCorePluginTestApp/grails-app/domain/org/modelcatalogue/core/RelationshipType.groovy b/ModelCatalogueCorePluginTestApp/grails-app/domain/org/modelcatalogue/core/RelationshipType.groovy index 7ec7ed3f5f..a538000233 100644 --- a/ModelCatalogueCorePluginTestApp/grails-app/domain/org/modelcatalogue/core/RelationshipType.groovy +++ b/ModelCatalogueCorePluginTestApp/grails-app/domain/org/modelcatalogue/core/RelationshipType.groovy @@ -228,6 +228,11 @@ class RelationshipType implements org.modelcatalogue.core.api.RelationshipType { readByName("import") } + + static RelationshipType getTagType() { + readByName("tag") + } + static RelationshipType readByName(String name) { // TODO: temporary give warning if 'classification' type is requested if (name == 'classification') { diff --git a/ModelCatalogueCorePluginTestApp/grails-app/domain/org/modelcatalogue/core/Tag.groovy b/ModelCatalogueCorePluginTestApp/grails-app/domain/org/modelcatalogue/core/Tag.groovy new file mode 100644 index 0000000000..1a240591f8 --- /dev/null +++ b/ModelCatalogueCorePluginTestApp/grails-app/domain/org/modelcatalogue/core/Tag.groovy @@ -0,0 +1,17 @@ +package org.modelcatalogue.core + +class Tag extends CatalogueElement { + + static relationships = [ + outgoing: [tag: 'tags'] + ] + + static constraints = { + name unique: 'versionNumber' + } + + @Override + Map manualDeleteRelationships(DataModel toBeDeleted) { + return [:] + } +} diff --git a/ModelCatalogueCorePluginTestApp/grails-app/migrations/changelog_024_tag.groovy b/ModelCatalogueCorePluginTestApp/grails-app/migrations/changelog_024_tag.groovy new file mode 100644 index 0000000000..847af73efa --- /dev/null +++ b/ModelCatalogueCorePluginTestApp/grails-app/migrations/changelog_024_tag.groovy @@ -0,0 +1,18 @@ +databaseChangeLog = { + + changeSet(author: "Vladimir Orany", id: "1412847979999-01") { + preConditions (onFail: 'MARK_RAN') { + not { + tableExists tableName: "tag" + } + } + createTable(tableName: "tag") { + column(autoIncrement: "true", name: "id", type: "BIGINT") { + constraints(nullable: "false", primaryKey: "true") + } + + } + addForeignKeyConstraint(baseColumnNames: "id", baseTableName: "tag", constraintName: "FK_TAG_CE", deferrable: "false", initiallyDeferred: "false", onDelete: "NO ACTION", onUpdate: "NO ACTION", referencedColumnNames: "id", referencedTableName: "catalogue_element", referencesUniqueColumn: "false") + } + +} diff --git a/ModelCatalogueCorePluginTestApp/grails-app/services/org/modelcatalogue/core/DataElementService.groovy b/ModelCatalogueCorePluginTestApp/grails-app/services/org/modelcatalogue/core/DataElementService.groovy index e0224d59c1..737ce6b5d3 100644 --- a/ModelCatalogueCorePluginTestApp/grails-app/services/org/modelcatalogue/core/DataElementService.groovy +++ b/ModelCatalogueCorePluginTestApp/grails-app/services/org/modelcatalogue/core/DataElementService.groovy @@ -1,5 +1,6 @@ package org.modelcatalogue.core +import org.hibernate.SQLQuery import org.modelcatalogue.core.util.lists.ListWithTotalAndType import org.modelcatalogue.core.util.lists.Lists @@ -14,17 +15,70 @@ class DataElementService { long modelId = model.id long hierarchyType = RelationshipType.hierarchyType.id long containmentType = RelationshipType.containmentType.id + long tagTypeId = RelationshipType.tagType.id + + def tagId = params.tag + + // if tagId is null, run the same query as it is at the moment + // if tagId in ['none', 'null', 'undefined'] then search for every data element not destination of tag relationship + // if tagId search for every data element which has relationship with given tag (given tag is a source, data element is destination) + + if (!tagId) { + return buildDataElementsList(params, """ + SELECT DISTINCT ce.*, de.data_type_id FROM catalogue_element ce + JOIN data_element de on ce.id = de.id + LEFT JOIN catalogue_element dm on ce.data_model_id = dm.id + WHERE + ce.data_model_id = :modelId + or find_in_set(de.id, GetAllDestinations(GetTopLevelDataClasses(:modelId, :hierarchytypeId), :hierarchytypeId, :containmentTypeId)) + ORDER BY ce.name; + """) { + setLong('modelId', modelId) + setLong('hierarchytypeId', hierarchyType) + setLong('containmentTypeId', containmentType) + } + } + + if (tagId in ['none', 'null', 'undefined']) { + return buildDataElementsList(params, """ + SELECT DISTINCT ce.*, de.data_type_id FROM catalogue_element ce + JOIN data_element de on ce.id = de.id + LEFT JOIN catalogue_element dm on ce.data_model_id = dm.id + LEFT JOIN relationship rel on rel.destination_id = de.id and rel.relationship_type_id = :tagTypeId + WHERE + (ce.data_model_id = :modelId + or find_in_set(de.id, GetAllDestinations(GetTopLevelDataClasses(:modelId, :hierarchytypeId), :hierarchytypeId, :containmentTypeId))) + AND rel.id is null + ORDER BY ce.name; + """) { + setLong('modelId', modelId) + setLong('hierarchytypeId', hierarchyType) + setLong('containmentTypeId', containmentType) + setLong('tagTypeId', tagTypeId) + } + } + + + buildDataElementsList(params, """ + SELECT DISTINCT ce.*, de.data_type_id FROM catalogue_element ce + JOIN data_element de on ce.id = de.id + LEFT JOIN catalogue_element dm on ce.data_model_id = dm.id + WHERE + (ce.data_model_id = :modelId + or find_in_set(de.id, GetAllDestinations(GetTopLevelDataClasses(:modelId, :hierarchytypeId), :hierarchytypeId, :containmentTypeId))) + AND de.id in (select destination_id from relationship where relationship_type_id = :tagTypeId and source_id = :tagId) + ORDER BY ce.name; + """) { + setLong('modelId', modelId) + setLong('hierarchytypeId', hierarchyType) + setLong('containmentTypeId', containmentType) + setLong('tagTypeId', tagTypeId) + setLong('tagId', tagId as Long) + } + } - + private ListWithTotalAndType buildDataElementsList(Map params, String query, @DelegatesTo(SQLQuery) Closure closure) { Lists.lazy(params, DataElement, { - String query = """SELECT DISTINCT ce.*, de.data_type_id FROM catalogue_element ce - JOIN data_element de on ce.id = de.id - LEFT JOIN catalogue_element dm on ce.data_model_id = dm.id - WHERE - ce.data_model_id = :modelId - or find_in_set(de.id, GetAllDestinations(GetTopLevelDataClasses(:modelId, :hierarchytypeId), :hierarchytypeId, :containmentTypeId)) - ORDER BY ce.name;""" - final session = sessionFactory.currentSession // Create native SQL query. @@ -32,27 +86,14 @@ class DataElementService { // Use Groovy with() method to invoke multiple methods // on the sqlQuery object. - final results = sqlQuery.with { - // Set domain class as entity. - // Properties in domain class id, name, level will - // be automatically filled. - addEntity(DataElement) - - // Set value for parameter startId. - setLong('modelId', modelId) - setLong('hierarchytypeId', hierarchyType) - setLong('containmentTypeId', containmentType) - - // Get all results. - list() - } - - results - }) - + sqlQuery.addEntity(DataElement) + sqlQuery.with closure + // Get all results. + sqlQuery.list() + }) + } - } } diff --git a/ModelCatalogueCorePluginTestApp/grails-app/services/org/modelcatalogue/core/DataModelService.groovy b/ModelCatalogueCorePluginTestApp/grails-app/services/org/modelcatalogue/core/DataModelService.groovy index f82fd576e2..41b6d4c3fb 100644 --- a/ModelCatalogueCorePluginTestApp/grails-app/services/org/modelcatalogue/core/DataModelService.groovy +++ b/ModelCatalogueCorePluginTestApp/grails-app/services/org/modelcatalogue/core/DataModelService.groovy @@ -13,6 +13,7 @@ import org.modelcatalogue.core.util.lists.DetachedListWithTotalAndType import org.modelcatalogue.core.util.lists.ListWithTotalAndType import org.modelcatalogue.core.util.lists.ListWithTotalAndTypeWrapper import org.modelcatalogue.core.util.lists.ListWrapper +import org.modelcatalogue.core.util.lists.Lists import javax.annotation.PostConstruct @@ -22,6 +23,7 @@ class DataModelService { def modelCatalogueSecurityService def grailsApplication + def sessionFactory private boolean legacyDataModels @@ -33,7 +35,7 @@ class DataModelService { public Map getStatistics(DataModelFilter filter) { def model = [:] - List displayed = [CatalogueElement, DataModel, DataClass, DataElement, DataType, MeasurementUnit, Asset, ValidationRule] + List displayed = [CatalogueElement, DataModel, DataClass, DataElement, DataType, MeasurementUnit, Asset, ValidationRule, Tag] for (Class type in displayed) { DetachedCriteria criteria = classified(type, filter) @@ -180,4 +182,49 @@ class DataModelService { dependents } + + static List allTags(DataModel dataModel) { + Relationship.where { relationshipType == RelationshipType.tagType && destination.dataModel == dataModel }.distinct('source').list().sort { a, b -> a.name <=> b.name } + } + + List allTagsMySQL(DataModel model){ + + long modelId = model.id + long hierarchyType = RelationshipType.hierarchyType.id + long containmentType = RelationshipType.containmentType.id + long tagTypeId = RelationshipType.tagType.id + + String query = """SELECT DISTINCT ce.* from catalogue_element ce + join tag t on t.id = ce.id + join relationship rel on t.id = rel.source_id and rel.relationship_type_id = :tagTypeId + join catalogue_element de on rel.destination_id = de.id + WHERE + de.data_model_id = :modelId + or find_in_set(de.id, GetAllDestinations(GetTopLevelDataClasses(:modelId, :hierarchytypeId), :hierarchytypeId, :containmentTypeId)) + ORDER BY ce.name;""" + + final session = sessionFactory.currentSession + + // Create native SQL query. + final sqlQuery = session.createSQLQuery(query) + + // Use Groovy with() method to invoke multiple methods + // on the sqlQuery object. + sqlQuery.with { + // Set domain class as entity. + // Properties in domain class id, name, level will + // be automatically filled. + addEntity(Tag) + + // Set value for parameter startId. + setLong('modelId', modelId) + setLong('hierarchytypeId', hierarchyType) + setLong('containmentTypeId', containmentType) + setLong('tagTypeId', tagTypeId) + + // Get all results. + list() + } + } + } diff --git a/ModelCatalogueCorePluginTestApp/grails-app/services/org/modelcatalogue/core/ModelCatalogueSearchService.groovy b/ModelCatalogueCorePluginTestApp/grails-app/services/org/modelcatalogue/core/ModelCatalogueSearchService.groovy index dac4e4f9e3..213702d351 100644 --- a/ModelCatalogueCorePluginTestApp/grails-app/services/org/modelcatalogue/core/ModelCatalogueSearchService.groovy +++ b/ModelCatalogueCorePluginTestApp/grails-app/services/org/modelcatalogue/core/ModelCatalogueSearchService.groovy @@ -63,7 +63,7 @@ class ModelCatalogueSearchService implements SearchCatalogue { String query = "%$params.search%" - if (DataModel.isAssignableFrom(resource) || MeasurementUnit.isAssignableFrom(resource)) { + if (DataModel.isAssignableFrom(resource) || MeasurementUnit.isAssignableFrom(resource) || Tag.isAssignableFrom(resource)) { DetachedCriteria criteria = new DetachedCriteria(resource) criteria.or { ilike('name', query) diff --git a/ModelCatalogueCorePluginTestApp/src/groovy/NHIC.mc.xml b/ModelCatalogueCorePluginTestApp/src/groovy/NHIC.mc.xml index 4f8cf798d2..8d2d655e9d 100644 --- a/ModelCatalogueCorePluginTestApp/src/groovy/NHIC.mc.xml +++ b/ModelCatalogueCorePluginTestApp/src/groovy/NHIC.mc.xml @@ -1,4 +1,4 @@ - + NHIC conceptual domain i.e. value domains used the NHIC project diff --git a/ModelCatalogueCorePluginTestApp/src/groovy/org/modelcatalogue/core/util/builder/DefaultCatalogueBuilder.groovy b/ModelCatalogueCorePluginTestApp/src/groovy/org/modelcatalogue/core/util/builder/DefaultCatalogueBuilder.groovy index 403272b96f..fffd0288a3 100644 --- a/ModelCatalogueCorePluginTestApp/src/groovy/org/modelcatalogue/core/util/builder/DefaultCatalogueBuilder.groovy +++ b/ModelCatalogueCorePluginTestApp/src/groovy/org/modelcatalogue/core/util/builder/DefaultCatalogueBuilder.groovy @@ -226,6 +226,26 @@ import org.modelcatalogue.core.api.CatalogueElement as ApiCatalogueElement validationRule } + /** + * Creates new tag, reuses the latest draft or creates new draft unless the exactly same tag + * already exists in the catalogue. Accepts any bindable parameters which tag instances does. + * + * @param parameters map of parameters such as name or id + * @param c DSL definition closure + */ + void tag(Map parameters, @DelegatesTo(CatalogueBuilder) Closure c = {}) { + CatalogueElementProxy tag = createProxy(Tag, parameters, null, isUnderControlIfSameClassification(parameters)) + + context.withNewContext tag, c + + + context.withContextElement(DataElement) { ignored, Closure relConf -> + rel 'tag' from tag, relConf + } + + tag + } + /** * Creates new data type, reuses the latest draft or creates new draft unless the exactly same data type * already exists in the catalogue. Accepts any bindable parameters which DataType instances does. diff --git a/ModelCatalogueCorePluginTestApp/src/groovy/org/modelcatalogue/core/util/builder/DefaultCatalogueElementProxy.groovy b/ModelCatalogueCorePluginTestApp/src/groovy/org/modelcatalogue/core/util/builder/DefaultCatalogueElementProxy.groovy index 40709e9ce3..b258510600 100644 --- a/ModelCatalogueCorePluginTestApp/src/groovy/org/modelcatalogue/core/util/builder/DefaultCatalogueElementProxy.groovy +++ b/ModelCatalogueCorePluginTestApp/src/groovy/org/modelcatalogue/core/util/builder/DefaultCatalogueElementProxy.groovy @@ -15,7 +15,7 @@ import static org.modelcatalogue.core.util.HibernateHelper.getEntityClass @GrailsCompileStatic @Log4j class DefaultCatalogueElementProxy implements CatalogueElementProxy, org.modelcatalogue.core.api.CatalogueElement { - static final List KNOWN_DOMAIN_CLASSES = [Asset, CatalogueElement, DataModel, DataElement, DataType, EnumeratedType, ReferenceType, MeasurementUnit, DataClass, PrimitiveType, ValidationRule] + static final List KNOWN_DOMAIN_CLASSES = [Asset, CatalogueElement, DataModel, DataElement, DataType, EnumeratedType, ReferenceType, MeasurementUnit, DataClass, PrimitiveType, ValidationRule, Tag] static final String CHANGE_NEW = "Does Not Exist Yet" static final String CHANGE_TYPE = "Type Changed" diff --git a/ModelCatalogueCorePluginTestApp/src/groovy/org/modelcatalogue/core/util/marshalling/TagMarshaller.groovy b/ModelCatalogueCorePluginTestApp/src/groovy/org/modelcatalogue/core/util/marshalling/TagMarshaller.groovy new file mode 100644 index 0000000000..a46932e360 --- /dev/null +++ b/ModelCatalogueCorePluginTestApp/src/groovy/org/modelcatalogue/core/util/marshalling/TagMarshaller.groovy @@ -0,0 +1,17 @@ +package org.modelcatalogue.core.util.marshalling + +import grails.util.GrailsNameUtils +import org.modelcatalogue.core.Relationship +import org.modelcatalogue.core.Tag + +class TagMarshaller extends CatalogueElementMarshaller { + + TagMarshaller() { + super(Tag) + } + +} + + + + diff --git a/ModelCatalogueCorePluginTestApp/src/groovy/org/modelcatalogue/core/util/test/TestData.groovy b/ModelCatalogueCorePluginTestApp/src/groovy/org/modelcatalogue/core/util/test/TestData.groovy index 3b68d176a8..cf3929656d 100644 --- a/ModelCatalogueCorePluginTestApp/src/groovy/org/modelcatalogue/core/util/test/TestData.groovy +++ b/ModelCatalogueCorePluginTestApp/src/groovy/org/modelcatalogue/core/util/test/TestData.groovy @@ -15,6 +15,7 @@ import org.modelcatalogue.core.MeasurementUnit import org.modelcatalogue.core.PrimitiveType import org.modelcatalogue.core.ReferenceType import org.modelcatalogue.core.RelationshipType +import org.modelcatalogue.core.Tag import org.modelcatalogue.core.ValidationRule import org.modelcatalogue.core.actions.Action import org.modelcatalogue.core.actions.ActionParameter @@ -199,6 +200,10 @@ import org.modelcatalogue.core.security.User User U_John = new User(name: "John", username: "John", password: "password", status: ElementStatus.FINALIZED).save(failOnError: true) User U_Kris = new User(name: "Kris", username: "Kris", password: "password", status: ElementStatus.FINALIZED).save(failOnError: true) User U_Lily = new User(name: "Lily", username: "Lily", password: "password", status: ElementStatus.FINALIZED).save(failOnError: true) + + 12.times { + new Tag(name: "Tag #${it}").save(failOnError: true) + } } } diff --git a/ModelCatalogueCorePluginTestApp/src/groovy/org/modelcatalogue/core/xml/CatalogueElementPrintHelper.groovy b/ModelCatalogueCorePluginTestApp/src/groovy/org/modelcatalogue/core/xml/CatalogueElementPrintHelper.groovy index 863b35dbb4..76c799530e 100644 --- a/ModelCatalogueCorePluginTestApp/src/groovy/org/modelcatalogue/core/xml/CatalogueElementPrintHelper.groovy +++ b/ModelCatalogueCorePluginTestApp/src/groovy/org/modelcatalogue/core/xml/CatalogueElementPrintHelper.groovy @@ -146,7 +146,7 @@ abstract class CatalogueElementPrintHelper { } protected void printBasedOn(theMkp, Relationship rel, PrintContext context) { - theMkp.basedOn(ref(rel.source, context)) { + theMkp.basedOn(ref(rel.destination, context)) { processRelationshipMetadata(theMkp, context, rel) } } diff --git a/ModelCatalogueCorePluginTestApp/src/groovy/org/modelcatalogue/core/xml/CatalogueXmlPrinter.groovy b/ModelCatalogueCorePluginTestApp/src/groovy/org/modelcatalogue/core/xml/CatalogueXmlPrinter.groovy index 2cf45bf5f9..6482c17a97 100644 --- a/ModelCatalogueCorePluginTestApp/src/groovy/org/modelcatalogue/core/xml/CatalogueXmlPrinter.groovy +++ b/ModelCatalogueCorePluginTestApp/src/groovy/org/modelcatalogue/core/xml/CatalogueXmlPrinter.groovy @@ -13,7 +13,7 @@ import org.modelcatalogue.core.policy.Conventions class CatalogueXmlPrinter { - static final String NAMESPACE_URL = 'http://www.metadataregistry.org.uk/assets/schema/2.1/metadataregistry.xsd' + static final String NAMESPACE_URL = 'http://www.metadataregistry.org.uk/assets/schema/2.2/metadataregistry.xsd' static final String ASSETS_NAMESPACE_URL = 'http://www.metadataregistry.org.uk/assets/schema/2.0/metadataregistry_asset.xsd' DataModelService dataModelService diff --git a/ModelCatalogueCorePluginTestApp/src/groovy/org/modelcatalogue/core/xml/DataTypePrintHelper.groovy b/ModelCatalogueCorePluginTestApp/src/groovy/org/modelcatalogue/core/xml/DataTypePrintHelper.groovy index 666abb5828..c9c11e3f29 100644 --- a/ModelCatalogueCorePluginTestApp/src/groovy/org/modelcatalogue/core/xml/DataTypePrintHelper.groovy +++ b/ModelCatalogueCorePluginTestApp/src/groovy/org/modelcatalogue/core/xml/DataTypePrintHelper.groovy @@ -55,6 +55,6 @@ class DataTypePrintHelper extends CatalogueElementPrintHelper { @Override protected void printBasedOn(Object mkp, Relationship rel, PrintContext context) { - printElement(mkp, rel.source, context, rel) + printElement(mkp, rel.destination, context, rel) } } diff --git a/ModelCatalogueCorePluginTestApp/src/groovy/org/modelcatalogue/integration/xml/CatalogueXmlLoader.groovy b/ModelCatalogueCorePluginTestApp/src/groovy/org/modelcatalogue/integration/xml/CatalogueXmlLoader.groovy index 8650f90517..51be820ac5 100644 --- a/ModelCatalogueCorePluginTestApp/src/groovy/org/modelcatalogue/integration/xml/CatalogueXmlLoader.groovy +++ b/ModelCatalogueCorePluginTestApp/src/groovy/org/modelcatalogue/integration/xml/CatalogueXmlLoader.groovy @@ -21,6 +21,7 @@ class CatalogueXmlLoader { 'http://www.metadataregistry.org.uk/assets/schema/1.2/metadataregistry.xsd', // just for v2.0 compatibility 'http://www.metadataregistry.org.uk/assets/schema/2.0/metadataregistry.xsd', 'http://www.metadataregistry.org.uk/assets/schema/2.1/metadataregistry.xsd', + 'http://www.metadataregistry.org.uk/assets/schema/2.2/metadataregistry.xsd', ].asImmutable() private static final String CATALOGUE_NAMESPACE_PREFIX = "http://www.metadataregistry.org.uk/assets/schema/" @@ -127,6 +128,7 @@ class CatalogueXmlLoader { case 'dataType': handleDataType(element) ; break case 'valueDomain': handleValueDomain(element) ; break case 'validationRule': handleValidationRule(element) ; break + case 'tag': handleTag(element) ; break case 'description': handleDescription(element) ; break case 'revisionNotes': handleRevisionNotes(element) ; break case 'policy': handlePolicy(element) ; break @@ -308,6 +310,12 @@ class CatalogueXmlLoader { } } + private void handleTag(NodeChild element) { + builder.tag(parameters(element)) { + handleChildren(element) + } + } + private void handleDataType(NodeChild element) { Map parameters = parameters(element) diff --git a/ModelCatalogueCorePluginTestApp/test/functional/org/modelcatalogue/core/DataElementWizardSpec.groovy b/ModelCatalogueCorePluginTestApp/test/functional/org/modelcatalogue/core/DataElementWizardSpec.groovy index 1c9286bb47..84a1411260 100644 --- a/ModelCatalogueCorePluginTestApp/test/functional/org/modelcatalogue/core/DataElementWizardSpec.groovy +++ b/ModelCatalogueCorePluginTestApp/test/functional/org/modelcatalogue/core/DataElementWizardSpec.groovy @@ -13,7 +13,7 @@ class DataElementWizardSpec extends AbstractModelCatalogueGebSpec { def "login and select Data Element"() { login admin - select 'Test 1' select 'Data Elements' + select 'Test 1' open 'Data Elements' select 'No tags' expect: check rightSideTitle is 'Active Data Elements' diff --git a/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/ElementServiceIntegrationSpec.groovy b/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/ElementServiceIntegrationSpec.groovy index 9fdab533ba..c0cee37c22 100644 --- a/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/ElementServiceIntegrationSpec.groovy +++ b/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/ElementServiceIntegrationSpec.groovy @@ -35,9 +35,9 @@ class ElementServiceIntegrationSpec extends AbstractIntegrationSpec { def "can supply status as parameter"() { expect: - elementService.list(status: 'DRAFT').size() == 26 + elementService.list(status: 'DRAFT').size() == CatalogueElement.countByStatus(ElementStatus.DRAFT) elementService.list(status: 'DRAFT', max: 10).size() == 10 - elementService.list(status: ElementStatus.DRAFT).size() == 26 + elementService.list(status: ElementStatus.DRAFT).size() == CatalogueElement.countByStatus(ElementStatus.DRAFT) elementService.list(status: ElementStatus.DRAFT, max: 10).size() == 10 elementService.list(DataClass, status: 'DRAFT').size() == 7 elementService.list(DataClass, status: ElementStatus.DRAFT).size() == 7 @@ -45,8 +45,8 @@ class ElementServiceIntegrationSpec extends AbstractIntegrationSpec { elementService.list(DataElement, status: ElementStatus.DRAFT).size() == 5 elementService.list(Asset, status: 'DRAFT').size() == 5 elementService.list(Asset, status: ElementStatus.DRAFT).size() == 5 - elementService.count(status: 'DRAFT') == 26L - elementService.count(status: ElementStatus.DRAFT) == 26L + elementService.count(status: 'DRAFT') == CatalogueElement.countByStatus(ElementStatus.DRAFT) + elementService.count(status: ElementStatus.DRAFT) == CatalogueElement.countByStatus(ElementStatus.DRAFT) elementService.count(DataClass, status: 'DRAFT') == 7L elementService.count(DataClass, status: ElementStatus.DRAFT) == 7L elementService.count(DataElement, status: 'DRAFT') == 5L diff --git a/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/SearchISpec.groovy b/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/SearchISpec.groovy deleted file mode 100644 index 114d7f773d..0000000000 --- a/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/SearchISpec.groovy +++ /dev/null @@ -1,165 +0,0 @@ -package org.modelcatalogue.core - -import org.codehaus.groovy.grails.web.json.JSONElement -import org.modelcatalogue.core.util.DefaultResultRecorder -import org.modelcatalogue.core.util.ResultRecorder -import spock.lang.Shared -import spock.lang.Unroll - -class SearchISpec extends AbstractIntegrationSpec{ - - //runs ok in integration test (test-app :integration), fails as part of test-app (Grails Bug) - uncomment to run -//RE: http://jira.grails.org/browse/GRAILS-11047?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel - - RelationshipService relationshipService - def grailsApplication - - - def setup(){ - loadFixtures() - } - - @Unroll - def "#no - text search for #className "(){ - - ResultRecorder recorder = DefaultResultRecorder.create( - "../ModelCatalogueCorePlugin/test/js/modelcatalogue/core", - className[0].toLowerCase() + className.substring(1) - ) - - - expect: - def domain = grailsApplication.getArtefact("Domain", "org.modelcatalogue.core.${className}")?.getClazz() - def expectedResult = domain.findByName(expectedResultName) - - when: - controller.response.format = 'json' - controller.params.search = searchString - - if (status) { - controller.params.status = status - } - - controller.search(10) - String recordName = "searchElement${no}" - JSONElement json = controller.response.json - recorder.recordResult recordName, json - - - then: - assert json - assert json.total == total - assert !total || json.list.get(0).id == expectedResult.id - assert !total || json.list.get(0).name == expectedResult.name - - where: - - no| className | controller | searchString | response | expectedResultName | total | status - 1 | "DataType" | new DataTypeController() | "boolean" | "json" | "boolean" | 1 | null - 2 | "DataType" | new DataTypeController() | "xdfxdf" | "json" | "boolean" | 1 | null - 5 | "DataElement" | new DataElementController() | "de_author1" | "json" | "DE_author1" | 1 | null - 9 | "EnumeratedType" | new EnumeratedTypeController() | "sub1" | "json" | "sub1" | 1 | null - 11 | "MeasurementUnit" | new MeasurementUnitController() | "°C" | "json" | "Degrees Celsius" | 1 | null - 13 | "DataClass" | new DataClassController() | "Jabberwocky" | "json" | "chapter1" | 1 | null - 14 | "DataClass" | new DataClassController() | "Jabberwocky" | "json" | "chapter1" | 0 | 'deprecated' - 17 | "RelationshipType" | new RelationshipTypeController() | "declaration" | "json" | "declaration" | 1 | null - 18 | "RelationshipType" | new RelationshipTypeController() | "declaration" | "json" | "declaration" | 1 | null - } - - @Unroll - def "#no - search model catalogue - paginate results"(){ - - def controller = new SearchController() - ResultRecorder recorder = DefaultResultRecorder.create( - "../ModelCatalogueCorePlugin/test/js/modelcatalogue/core", - "search" - ) - - when: - controller.response.format = "json" - controller.params.max = max - controller.params.offset = offset - controller.params.search = searchString - controller.params.sort = sort - controller.params.order = order - controller.index() - JSONElement json = controller.response.json - String list = "list${no}" - recorder.recordResult list, json - - then: - json.success - json.total == total - json.offset == offset - json.page == max - json.list - json.list.size() == size - json.next == next - json.previous == previous - - where: - [no, size, max, offset, total, next, previous, searchString, sort, order] << getPaginationParameters() - - - } - - - - protected static getPaginationParameters() { - [ - // no, size, max, offset, total, next, previous, searchString, sort, order - [1, 10, 10, 0, 77, "/search/?search=a&max=10&offset=10", "", "a"], - [2, 5, 5, 0, 77, "/search/?search=a&max=5&sort=name&order=ASC&offset=5", "", "a", "name", "ASC"], - [3, 2, 2, 6, 77, "/search/?search=a&max=2&sort=name&order=ASC&offset=8", "/search/?search=a&max=2&sort=name&order=ASC&offset=4", "a", "name", "ASC"], - [4, 4, 4, 1, 77, "/search/?search=a&max=4&sort=name&order=ASC&offset=5", "", "a", "name", "ASC"], - [5, 2, 2, 2, 77, "/search/?search=a&max=2&sort=name&order=ASC&offset=4", "/search/?search=a&max=2&sort=name&order=ASC&offset=0", "a", "name", "ASC"], - [6, 2, 2, 4, 77, "/search/?search=a&max=2&sort=name&offset=6", "/search/?search=a&max=2&sort=name&offset=2", "a", "name", ""], - [7, 2, 2, 4, 77, "/search/?search=a&max=2&offset=6", "/search/?search=a&max=2&offset=2", "a", null, null] - ] - } - -@Unroll - def "#no - bad search params"(){ - - def controller = new SearchController() - ResultRecorder recorder = DefaultResultRecorder.create( - "../ModelCatalogueCorePlugin/test/js/modelcatalogue/core", - "badSearch" - ) - - when: - controller.response.format = "json" - controller.params.max = max - controller.params.offset = offset - controller.params.search = searchString - controller.params.sort = sort - controller.params.order = order - - controller.index() - JSONElement json = controller.response.json - - String list = "list${no}" - - recorder.recordResult list, json - - then: - - json.errors == error - - where: - [no, size, max, offset, total, searchString, sort, order, error] << getBadParameters() - - - - - } - - protected static getBadParameters() { - [ - // no,size, max , off. tot. next, previous, searchstring , previous - [2, 2, 2, 4, 7, "", "name","", "No query string to search on"] - ] - } - - -} diff --git a/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/TagControllerIntegrationSpec.groovy b/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/TagControllerIntegrationSpec.groovy new file mode 100644 index 0000000000..4e9fd0973b --- /dev/null +++ b/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/TagControllerIntegrationSpec.groovy @@ -0,0 +1,49 @@ +package org.modelcatalogue.core + +import grails.util.GrailsNameUtils + +class TagControllerIntegrationSpec extends AbstractCatalogueElementControllerIntegrationSpec { + + + @Override + Map getPropertiesToEdit(){ + [name: "Tag #13", description: "edited description ", symbol: "R", dataModel: dataModelForSpec] + } + + @Override + Map getNewInstance(){ + [symbol: "Tag #14", name: "Something", description: "blah blah blah", dataModel: dataModelForSpec] + } + + @Override + Map getBadInstance(){ + [name: "t"*300, description: "asdf", dataModel: dataModelForSpec] + } + + + @Override + Class getResource() { + Tag + } + + @Override + AbstractCatalogueElementController getController() { + new TagController() + } + + @Override + String getResourceName() { + GrailsNameUtils.getLogicalPropertyName(getClass().getSimpleName(), "ControllerIntegrationSpec") + } + + @Override + Tag getLoadItem() { + Tag.findByName("Tag #1") + } + + @Override + Tag getAnotherLoadItem() { + Tag.findByName("Tag #2") + } + +} diff --git a/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/diff/TestDataModelV1.xml b/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/diff/TestDataModelV1.xml index 3497b746a0..e15cac44e4 100644 --- a/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/diff/TestDataModelV1.xml +++ b/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/diff/TestDataModelV1.xml @@ -1,4 +1,4 @@ - + NHIC data model i.e. data classes used the NHIC project diff --git a/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/diff/TestDataModelV2.xml b/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/diff/TestDataModelV2.xml index 2c31263ac4..1825069e99 100644 --- a/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/diff/TestDataModelV2.xml +++ b/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/diff/TestDataModelV2.xml @@ -1,4 +1,4 @@ - + test data model i.e. data classes used the test project diff --git a/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/export/inventory/TestDataModelV1.xml b/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/export/inventory/TestDataModelV1.xml index 6cef5f4fdb..4d7e0fb9b9 100644 --- a/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/export/inventory/TestDataModelV1.xml +++ b/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/export/inventory/TestDataModelV1.xml @@ -1,4 +1,4 @@ - + NHIC conceptual domain i.e. value domains used the NHIC project diff --git a/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/export/inventory/TestDataModelV2.xml b/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/export/inventory/TestDataModelV2.xml index 7a3908d799..79e2262442 100644 --- a/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/export/inventory/TestDataModelV2.xml +++ b/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/export/inventory/TestDataModelV2.xml @@ -1,4 +1,4 @@ - + NHIC conceptual domain i.e. value domains used the NHIC project diff --git a/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/util/CatalogueBuilderIntegrationSpec.groovy b/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/util/CatalogueBuilderIntegrationSpec.groovy index 732b3c4741..326bb78f6d 100644 --- a/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/util/CatalogueBuilderIntegrationSpec.groovy +++ b/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/util/CatalogueBuilderIntegrationSpec.groovy @@ -26,6 +26,9 @@ class CatalogueBuilderIntegrationSpec extends AbstractIntegrationSpec { public static final String MODEL_TOM_NAME = 'Test Other Model' public static final String DATA_TYPE_TOM_ID = "http://example.com/tom/string" public static final String ELEMENT_MEF_2_NAME = 'Data Element from MEF 2' + public static final String DATA_MODEL_FOR_TAG_TESTING_NAME = 'Data Model for tag testing' + public static final String DATA_ELEMENT_FOR_TAG_TESTING_NAME = 'Data Element for tag testing' + public static final String TAG_FOR_TESTING_NAME = 'Tag 1' def dataModelService def elementService @@ -1359,4 +1362,27 @@ class CatalogueBuilderIntegrationSpec extends AbstractIntegrationSpec { } + + + def "add tags to data element"() { + given: + build { + dataModel(name: DATA_MODEL_FOR_TAG_TESTING_NAME) { + dataElement(name: DATA_ELEMENT_FOR_TAG_TESTING_NAME) { + tag(name: TAG_FOR_TESTING_NAME) + } + } + } + when: + DataModel dataModel = DataModel.findByName(DATA_MODEL_FOR_TAG_TESTING_NAME) + DataElement dataElement = DataElement.findByName(DATA_ELEMENT_FOR_TAG_TESTING_NAME) + Tag tag = Tag.findByName(TAG_FOR_TESTING_NAME) + then: + dataModel + dataElement + tag + tag in dataElement.isTaggedBy + dataElement in tag.tags + tag in DataModelService.allTags(dataModel) + } } diff --git a/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/xml/CatalogueXmlPrinterSpec.groovy b/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/xml/CatalogueXmlPrinterSpec.groovy index d17ec80a52..36fd0f0046 100644 --- a/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/xml/CatalogueXmlPrinterSpec.groovy +++ b/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/xml/CatalogueXmlPrinterSpec.groovy @@ -34,7 +34,7 @@ class CatalogueXmlPrinterSpec extends AbstractIntegrationSpec { StringWriter writer = new StringWriter() writable.writeTo(writer) expect: - writer.toString() == ''' + writer.toString() == ''' diagnosis.ƒ‚ƒ‚ƒ‚'‚“ e @@ -244,12 +244,17 @@ class CatalogueXmlPrinterSpec extends AbstractIntegrationSpec { private DataType getInteger() { decimal - build { + DataType dataType = build { dataType(name: "Integer", id: "http://www.example.com/types/Integer") { basedOn 'Decimal' description "A number with no fractional part." } } + + assert dataType.isBasedOn + assert dataType.isBasedOn.any { it.name == 'Decimal'} + + dataType } private DataType getGender() { diff --git a/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/xml/grand_child.mc.xml b/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/xml/grand_child.mc.xml index 7427bee37e..5f20950728 100644 --- a/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/xml/grand_child.mc.xml +++ b/ModelCatalogueCorePluginTestApp/test/integration/org/modelcatalogue/core/xml/grand_child.mc.xml @@ -1,4 +1,4 @@ - + diff --git a/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/adhesion.catalogue.xml b/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/adhesion.catalogue.xml index 322f0d862a..e34105f745 100644 --- a/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/adhesion.catalogue.xml +++ b/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/adhesion.catalogue.xml @@ -1,8 +1,12 @@ - + A force is a push or pull upon an object resulting from the object's interaction with another object. - + + A number that uses a decimal point followed by digits that show a value smaller than one. + \d+ The newton (symbol: N) is the International System of Units (SI) derived unit of force. diff --git a/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/force.catalogue.xml b/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/force.catalogue.xml index 00edbf0aa0..b9878bb052 100644 --- a/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/force.catalogue.xml +++ b/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/force.catalogue.xml @@ -1,7 +1,10 @@ - + + A force is a push or pull upon an object resulting from the object's interaction with another object. - + + A number that uses a decimal point followed by digits that show a value smaller than one. + Derived From diff --git a/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/gender.catalogue.xml b/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/gender.catalogue.xml index fe8f5ea423..223d610911 100644 --- a/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/gender.catalogue.xml +++ b/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/gender.catalogue.xml @@ -1,5 +1,5 @@ - + The state of being male or female (typically used with reference to social and cultural differences rather than biological ones) diff --git a/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/integer.catalogue.xml b/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/integer.catalogue.xml index 90d0dc9b73..a8b2c32f8c 100644 --- a/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/integer.catalogue.xml +++ b/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/integer.catalogue.xml @@ -1,7 +1,8 @@ - + + A number with no fractional part. - + diff --git a/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/locomotive.catalogue.xml b/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/locomotive.catalogue.xml index 247d0de624..97f2f24c20 100644 --- a/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/locomotive.catalogue.xml +++ b/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/locomotive.catalogue.xml @@ -1,9 +1,13 @@ - + A force is a push or pull upon an object resulting from the object's interaction with another object. - + + A number that uses a decimal point followed by digits that show a value smaller than one. + \d+ The newton (symbol: N) is the International System of Units (SI) derived unit of force. diff --git a/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/newton.catalogue.xml b/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/newton.catalogue.xml index ab72e14bd2..ab2e417e95 100644 --- a/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/newton.catalogue.xml +++ b/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/newton.catalogue.xml @@ -1,5 +1,5 @@ - + The newton (symbol: N) is the International System of Units (SI) derived unit of force. diff --git a/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/transportation.catalogue.xml b/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/transportation.catalogue.xml index fb9d524c93..8434c1fb1c 100644 --- a/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/transportation.catalogue.xml +++ b/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/transportation.catalogue.xml @@ -1,11 +1,15 @@ - + CD Policy A force is a push or pull upon an object resulting from the object's interaction with another object. - + + A number that uses a decimal point followed by digits that show a value smaller than one. + \d+ The newton (symbol: N) is the International System of Units (SI) derived unit of force. @@ -19,9 +23,6 @@ - - A number that uses a decimal point followed by digits that show a value smaller than one. - diff --git a/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/user.catalogue.xml b/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/user.catalogue.xml index ab466dd1e2..e88d629ad6 100644 --- a/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/user.catalogue.xml +++ b/ModelCatalogueCorePluginTestApp/test/integration/resources/xml/user.catalogue.xml @@ -1,5 +1,5 @@ - + Reference to the user diff --git a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/excel/test.catalogue.xml b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/excel/test.catalogue.xml index 6122e6dbfe..a0ae3e0f36 100644 --- a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/excel/test.catalogue.xml +++ b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/excel/test.catalogue.xml @@ -1,5 +1,5 @@ - + true dataType diff --git a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/mc/test.catalogue.xml b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/mc/test.catalogue.xml index 123b075a17..6c6ccc61ae 100644 --- a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/mc/test.catalogue.xml +++ b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/mc/test.catalogue.xml @@ -1,5 +1,5 @@ - + diff --git a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/obo/hpo.catalogue.xml b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/obo/hpo.catalogue.xml index 5ecdbf2e08..adc6639b4a 100644 --- a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/obo/hpo.catalogue.xml +++ b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/obo/hpo.catalogue.xml @@ -1,5 +1,5 @@ - + The presence of any abnormality of the genitourinary system. diff --git a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/obo/test.catalogue.xml b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/obo/test.catalogue.xml index 4ad9e8eb8b..adc09daa9c 100644 --- a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/obo/test.catalogue.xml +++ b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/obo/test.catalogue.xml @@ -1,5 +1,5 @@ - + Root of all terms in the Human Phenotype Ontology. diff --git a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/adhesion.catalogue.xml b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/adhesion.catalogue.xml index 0abc5ae13c..fecc31dd67 100644 --- a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/adhesion.catalogue.xml +++ b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/adhesion.catalogue.xml @@ -1,4 +1,4 @@ - + A force is a push or pull upon an object resulting from the object's interaction with another object. diff --git a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/adhesion.reference.catalogue.xml b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/adhesion.reference.catalogue.xml index b4b5266bc9..b61c820b38 100644 --- a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/adhesion.reference.catalogue.xml +++ b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/adhesion.reference.catalogue.xml @@ -1,5 +1,5 @@ - + A force is a push or pull upon an object resulting from the object's interaction with another object. diff --git a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/force.catalogue.xml b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/force.catalogue.xml index c111e2ba7d..25d4fc4632 100644 --- a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/force.catalogue.xml +++ b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/force.catalogue.xml @@ -1,5 +1,5 @@ - + A force is a push or pull upon an object resulting from the object's interaction with another object. diff --git a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/force.reference.catalogue.xml b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/force.reference.catalogue.xml index aca021adf3..6b73780990 100644 --- a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/force.reference.catalogue.xml +++ b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/force.reference.catalogue.xml @@ -1,5 +1,5 @@ - + A force is a push or pull upon an object resulting from the object's interaction with another object. \d+ diff --git a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/gender.catalogue.xml b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/gender.catalogue.xml index a9a5ccb6e0..fd484af1e9 100644 --- a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/gender.catalogue.xml +++ b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/gender.catalogue.xml @@ -1,5 +1,5 @@ - + The state of being male or female (typically used with reference to social and cultural differences rather than biological ones) diff --git a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/gender.reference.catalogue.xml b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/gender.reference.catalogue.xml index a9a5ccb6e0..fd484af1e9 100644 --- a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/gender.reference.catalogue.xml +++ b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/gender.reference.catalogue.xml @@ -1,5 +1,5 @@ - + The state of being male or female (typically used with reference to social and cultural differences rather than biological ones) diff --git a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/integer.catalogue.xml b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/integer.catalogue.xml index ac8931c2f7..0265a9922b 100644 --- a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/integer.catalogue.xml +++ b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/integer.catalogue.xml @@ -1,5 +1,5 @@ - + A number with no fractional part. diff --git a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/integer.reference.catalogue.xml b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/integer.reference.catalogue.xml index a033a359e8..0def07cab9 100644 --- a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/integer.reference.catalogue.xml +++ b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/integer.reference.catalogue.xml @@ -1,5 +1,5 @@ - + A number with no fractional part. diff --git a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/locomotive.catalogue.xml b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/locomotive.catalogue.xml index d93dac4e95..045e3c7bc5 100644 --- a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/locomotive.catalogue.xml +++ b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/locomotive.catalogue.xml @@ -1,4 +1,4 @@ - + diff --git a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/locomotive.reference.catalogue.xml b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/locomotive.reference.catalogue.xml index 33113f778a..b0ba8b498a 100644 --- a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/locomotive.reference.catalogue.xml +++ b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/locomotive.reference.catalogue.xml @@ -1,5 +1,5 @@ - + diff --git a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/newton.catalogue.xml b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/newton.catalogue.xml index 85a0cb448f..c967abb5d8 100644 --- a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/newton.catalogue.xml +++ b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/newton.catalogue.xml @@ -1,5 +1,5 @@ - + The newton (symbol: N) is the International System of Units (SI) derived unit of force. diff --git a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/newton.reference.catalogue.xml b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/newton.reference.catalogue.xml index d87352a933..a4304f694f 100644 --- a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/newton.reference.catalogue.xml +++ b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/newton.reference.catalogue.xml @@ -1,5 +1,5 @@ - + The newton (symbol: N) is the International System of Units (SI) derived unit of force. diff --git a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/newton2.reference.catalogue.xml b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/newton2.reference.catalogue.xml index 884e4fe72f..325ac54c05 100644 --- a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/newton2.reference.catalogue.xml +++ b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/newton2.reference.catalogue.xml @@ -1,5 +1,5 @@ - + The newton (symbol: N) is the International System of Units (SI) derived unit of force. diff --git a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/transportation.catalogue.xml b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/transportation.catalogue.xml index 7033792925..3727c2282f 100644 --- a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/transportation.catalogue.xml +++ b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/transportation.catalogue.xml @@ -1,5 +1,5 @@ - + This is a new model CD Policy diff --git a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/transportation.reference.catalogue.xml b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/transportation.reference.catalogue.xml index b26f0711bb..67772f7acf 100644 --- a/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/transportation.reference.catalogue.xml +++ b/ModelCatalogueCorePluginTestApp/test/unit/org/modelcatalogue/integration/xml/transportation.reference.catalogue.xml @@ -1,5 +1,5 @@ - + This is a new model CD Policy