Changeset 1864
- Timestamp:
- May 23, 2011, 4:36:00 PM (13 years ago)
- Location:
- trunk/grails-app
- Files:
-
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/grails-app/controllers/dbnp/studycapturing/AssayController.groovy
r1830 r1864 139 139 flow.fieldMap = assayService.collectAssayTemplateFields(flow.assay) 140 140 141 flash.errorMessage = flow.fieldMap.remove('ModuleError') 141 142 flow.measurementTokens = flow.fieldMap.remove('Module Measurement Data') 142 143 }.to "selectFields" … … 147 148 selectFields { 148 149 on ("submit"){ 150 149 151 def fieldMapSelection = [:] 150 152 … … 173 175 // collect the assay data according to user selecting 174 176 def assayData = assayService.collectAssayData(flow.assay, fieldMapSelection, measurementTokens) 177 178 flash.errorMessage = assayData.remove('ModuleError') 179 175 180 flow.rowData = assayService.convertColumnToRowStructure(assayData) 176 181 -
trunk/grails-app/controllers/dbnp/studycapturing/SimpleWizardController.groovy
r1838 r1864 37 37 */ 38 38 def index = { 39 // if( params.id )40 // redirect( action: "simpleWizard", id: params.id );41 // else42 // redirect( action: "simpleWizard" );43 39 redirect action: 'simpleWizard', params: params 44 40 } … … 50 46 if (!flow.study) retrievalError() 51 47 52 flow.inferDesign = params.inferDesign53 48 // Search for studies 54 49 flow.studies = Study.giveWritableStudies( authenticationService.getLoggedInUser(), 100 ) … … 824 819 def errors = []; 825 820 826 if (flow.inferDesign) { 827 828 println 'Entered infer design...' 829 830 // find the indices of the classes of interest in the records 831 def sampleIdx = table[0].findIndexOf{it.class.name == 'dbnp.studycapturing.Sample'} 832 def samplingEventIdx = table[0].findIndexOf{it.class.name == 'dbnp.studycapturing.SamplingEvent'} 833 def subjectIdx = table[0].findIndexOf{it.class.name == 'dbnp.studycapturing.Subject'} 834 835 // Check for duplicate samples 836 def samples = table.collect{it[sampleIdx]} 837 838 def uniques = [] as Set 839 def duplicates = [] as Set 840 841 // this approach separates the unique from the duplicate entries 842 samples*.name.each { 843 uniques.add(it) || duplicates.add(it) 844 } 845 846 duplicates.each{ duplicateName -> 847 samples.findAll{it.name == duplicateName}.each{ sample -> 848 numInvalidEntities++ 849 failedcells = addNonValidatingCells(failedcells, sample, flow) 850 errors += "(Sample) duplicate name: $duplicateName" 851 } 852 } 853 854 // A closure that returns a sub list of entities from a list that have 855 // unique values of a property indicated by propertyName 856 def uniqueEntitiesByProperty = { entities, propertyName -> 857 858 entities*."$propertyName".unique().collect { uniquePropertyValue -> 859 860 entities.find{ it."$propertyName" == uniquePropertyValue } 861 862 } 863 } 864 865 def addToCollectionIfNonexistent = { parent, collectionName, entity, propertyName -> 866 867 if (!parent[collectionName].find{it[propertyName] == entity[propertyName]}) 868 parent."addTo${collectionName.capitalize()}" entity 869 870 } 871 872 // collect unique subjects and sampling events from table 873 def uniqueSubjects = 874 uniqueEntitiesByProperty(table.collect{it[subjectIdx]}, 'name') 875 uniqueSubjects.each{ 876 addToCollectionIfNonexistent study, 'subjects', it, 'name' 877 it.species = Term.findByName('Homo sapiens') 878 } 879 880 def uniqueSamplingEvents = 881 uniqueEntitiesByProperty(table.collect{it[samplingEventIdx]}, 'startTime') 882 uniqueSamplingEvents.each{ 883 it.setFieldValue( 'sampleTemplate', flow.sampleForm.template.Sample.name ) 884 } 885 886 // create an event group for each unique sampling event (not much of a group, is it ...) 887 def eventGroups = uniqueSamplingEvents.collect{ 888 889 def eventGroupName = "Sampling_${it.sampleTemplate.name}_${new RelTime(it.startTime).toString()}" 890 891 def eventGroup = study.eventGroups.find{it.name == eventGroupName} ?: //EventGroup.findByParentAndName(study, eventGroupName) ?: 892 new EventGroup(name: eventGroupName) 893 894 eventGroup.addToSamplingEvents it 895 896 if (!study.eventGroups.find{it == eventGroup}) 897 study.addToEventGroups eventGroup 898 899 if (!it.parent) study.addToSamplingEvents it 900 901 println eventGroup.name 902 903 eventGroup 904 905 } 906 907 table.each{ record -> 908 909 Sample sample = record[sampleIdx] 910 911 // gather all sample related entities 912 def correspondingSamplingEvent = uniqueSamplingEvents.find {it.startTime == record[samplingEventIdx].startTime} 913 def correspondingSubject = uniqueSubjects.find{it.name == record[subjectIdx].name} 914 def correspondingEventGroup = eventGroups.find{correspondingSamplingEvent in it.samplingEvents} 915 916 addToCollectionIfNonexistent correspondingSamplingEvent, 'samples', sample, 'name' 917 918 sample.parentSubject = correspondingSubject 919 920 correspondingEventGroup.addToSamplingEvents correspondingSamplingEvent 921 922 if (!correspondingEventGroup.subjects.find{it.name == correspondingSubject.name}) 923 correspondingEventGroup.addToSubjects correspondingSubject 924 925 addToCollectionIfNonexistent study, 'samples', sample, 'name' 926 927 } 928 929 } else { 930 // Add all samples 931 table.each { record -> 932 record.each { entity -> 933 if( entity ) { 934 // Determine entity class and add a parent. Add the entity to the study 935 def preferredIdentifier = importerService.givePreferredIdentifier( entity.class ); 936 def equalClosure = { it.getIdentifier() == entity.getIdentifier() } 937 def entityName = entity.class.name[ entity.class.name.lastIndexOf( "." ) + 1 .. -1 ] 938 939 entity.parent = study 940 941 switch( entity.class ) { 942 case Sample: 943 if( !study.samples?.find( equalClosure ) ) { 944 study.addToSamples( entity ); 821 // Add all samples 822 table.each { record -> 823 record.each { entity -> 824 if( entity ) { 825 // Determine entity class and add a parent. Add the entity to the study 826 def preferredIdentifier = importerService.givePreferredIdentifier( entity.class ); 827 def equalClosure = { it.getIdentifier() == entity.getIdentifier() } 828 def entityName = entity.class.name[ entity.class.name.lastIndexOf( "." ) + 1 .. -1 ] 829 830 entity.parent = study 831 832 switch( entity.class ) { 833 case Sample: 834 if( !study.samples?.find( equalClosure ) ) { 835 study.addToSamples( entity ); 836 } 837 838 // If an eventgroup is created, add it to the study 839 // The eventgroup must have a unique name, but the user shouldn't be bothered with it 840 // Add 'group ' + samplename and it that is not unique, add a number to it 841 if( entity.parentEventGroup ) { 842 study.addToEventGroups( entity.parentEventGroup ) 843 844 entity.parentEventGroup.name = "Group " + entity.name 845 while( !entity.parentEventGroup.validate() ) { 846 //entity.parentEventGroup.getErrors().each { println it } 847 entity.parentEventGroup.name += "" + Math.floor( Math.random() * 100 ) 945 848 } 946 947 // If an eventgroup is created, add it to the study 948 // The eventgroup must have a unique name, but the user shouldn't be bothered with it 949 // Add 'group ' + samplename and it that is not unique, add a number to it 950 if( entity.parentEventGroup ) { 951 study.addToEventGroups( entity.parentEventGroup ) 952 953 entity.parentEventGroup.name = "Group " + entity.name 954 while( !entity.parentEventGroup.validate() ) { 955 //entity.parentEventGroup.getErrors().each { println it } 956 entity.parentEventGroup.name += "" + Math.floor( Math.random() * 100 ) 849 } 850 851 break; 852 case Subject: 853 if( !study.samples?.find( equalClosure ) ) { 854 855 if( preferredIdentifier ) { 856 // Subjects without a name should just be called 'subject' 857 if( !entity.getFieldValue( preferredIdentifier.name ) ) 858 entity.setFieldValue( preferredIdentifier.name, "Subject" ); 859 860 // Subjects should have unique names; if the user has entered the same name multiple times, 861 // the subject will be renamed 862 def baseName = entity.getFieldValue( preferredIdentifier.name ) 863 def counter = 2; 864 865 while( study.subjects?.find { it.getFieldValue( preferredIdentifier.name ) == entity.getFieldValue( preferredIdentifier.name ) } ) { 866 entity.setFieldValue( preferredIdentifier.name, baseName + " (" + counter++ + ")" ) 957 867 } 958 868 } 959 869 960 break; 961 case Subject: 962 if( !study.samples?.find( equalClosure ) ) { 963 964 if( preferredIdentifier ) { 965 // Subjects without a name should just be called 'subject' 966 if( !entity.getFieldValue( preferredIdentifier.name ) ) 967 entity.setFieldValue( preferredIdentifier.name, "Subject" ); 968 969 // Subjects should have unique names; if the user has entered the same name multiple times, 970 // the subject will be renamed 971 def baseName = entity.getFieldValue( preferredIdentifier.name ) 972 def counter = 2; 973 974 while( study.subjects?.find { it.getFieldValue( preferredIdentifier.name ) == entity.getFieldValue( preferredIdentifier.name ) } ) { 975 entity.setFieldValue( preferredIdentifier.name, baseName + " (" + counter++ + ")" ) 976 } 977 } 978 979 study.addToSubjects( entity ); 980 981 } 982 983 break; 984 case Event: 985 if( !study.events?.find( equalClosure ) ) { 986 study.addToEvents( entity ); 987 } 988 break; 989 case SamplingEvent: 990 // Sampling events have a 'sampleTemplate' value, which should be filled by the 991 // template that is chosen for samples. 992 if( !entity.getFieldValue( 'sampleTemplate' ) ) { 993 entity.setFieldValue( 'sampleTemplate', flow.sampleForm.template.Sample.name ) 994 } 995 996 if( !study.samplingEvents?.find( equalClosure ) ) { 997 study.addToSamplingEvents( entity ); 998 } 999 break; 1000 } 1001 1002 if (!entity.validate()) { 1003 numInvalidEntities++; 1004 1005 // Add this field to the list of failed cells, in order to give the user feedback 1006 failedcells = addNonValidatingCells( failedcells, entity, flow ) 1007 1008 // Also create a full list of errors 1009 def currentErrors = getHumanReadableErrors( entity ) 1010 if( currentErrors ) { 1011 currentErrors.each { 1012 errors += "(" + entityName + ") " + it.value; 1013 } 870 study.addToSubjects( entity ); 871 872 } 873 874 break; 875 case Event: 876 if( !study.events?.find( equalClosure ) ) { 877 study.addToEvents( entity ); 878 } 879 break; 880 case SamplingEvent: 881 // Sampling events have a 'sampleTemplate' value, which should be filled by the 882 // template that is chosen for samples. 883 if( !entity.getFieldValue( 'sampleTemplate' ) ) { 884 entity.setFieldValue( 'sampleTemplate', flow.sampleForm.template.Sample.name ) 885 } 886 887 if( !study.samplingEvents?.find( equalClosure ) ) { 888 study.addToSamplingEvents( entity ); 889 } 890 break; 891 } 892 893 if (!entity.validate()) { 894 numInvalidEntities++; 895 896 // Add this field to the list of failed cells, in order to give the user feedback 897 failedcells = addNonValidatingCells( failedcells, entity, flow ) 898 899 // Also create a full list of errors 900 def currentErrors = getHumanReadableErrors( entity ) 901 if( currentErrors ) { 902 currentErrors.each { 903 errors += "(" + entityName + ") " + it.value; 1014 904 } 1015 905 } -
trunk/grails-app/domain/dbnp/studycapturing/EventGroup.groovy
r1457 r1864 22 22 static constraints = { 23 23 // Ensure that the event group name is unique within the study 24 name(unique:['parent']) 24 name(unique:['parent']) 25 25 } 26 26 } -
trunk/grails-app/services/dbnp/modules/ModuleCommunicationService.groovy
r1852 r1864 15 15 package dbnp.modules 16 16 17 import dbnp.studycapturing.*18 import dbnp.authentication.*19 17 import grails.converters.* 20 18 import javax.servlet.http.HttpServletResponse … … 75 73 } 76 74 77 75 /** 78 76 * Calls a rest method on a module 79 77 * -
trunk/grails-app/services/dbnp/studycapturing/AssayService.groovy
r1853 r1864 50 50 } 51 51 52 def moduleError = '', moduleMeasurements = [] 53 54 try { 55 moduleMeasurements = requestModuleMeasurementNames(assay) 56 } catch (e) { 57 moduleError = e.message 58 } 59 52 60 def samples = assay.samples 53 61 [ 'Subject Data' : getUsedTemplateFields( samples*."parentSubject".unique() ), … … 55 63 'Sample Data' : getUsedTemplateFields( samples ), 56 64 'Event Group' : [[name: 'name', comment: 'Name of Event Group', displayName: 'name']], 57 58 // If module is not reachable, only the field 'module error' is returned, and is filled later on. 59 'Module Measurement Data': moduleCommunicationService.isModuleReachable(assay.module.url) ? requestModuleMeasurementNames(assay) : [ [ name: "Module error" ] ] 65 'Module Measurement Data': moduleMeasurements, 66 'ModuleError': moduleError 60 67 ] 61 68 … … 83 90 headerFields.inject([:]) { map, headerField -> 84 91 85 map + [(headerField.displayName): templateEntities.collect { 92 map + [(headerField.displayName): templateEntities.collect { entity -> 86 93 87 94 // default to an empty string 88 95 def val = '' 89 96 90 def field 91 try { 92 93 val = it.getFieldValue(headerField.name) 94 95 // Convert RelTime fields to human readable strings 96 field = it.getField(headerField.name) 97 if (field.type == TemplateFieldType.RELTIME) 98 val = new RelTime( val as long ) 99 100 } catch (NoSuchFieldException e) { /* pass */ } 97 if (entity) { 98 def field 99 try { 100 101 val = entity.getFieldValue(headerField.name) 102 103 // Convert RelTime fields to human readable strings 104 field = entity.getField(headerField.name) 105 if (field.type == TemplateFieldType.RELTIME) 106 val = new RelTime( val as long ) 107 108 } catch (NoSuchFieldException e) { /* pass */ } 109 } 101 110 102 111 (val instanceof Number) ? val : val.toString()}] … … 177 186 } 178 187 188 def moduleError = '', moduleMeasurementData = [:] 189 190 if (measurementTokens) { 191 192 try { 193 moduleMeasurementData = requestModuleMeasurements(assay, measurementTokens, samples) 194 } catch (e) { 195 moduleMeasurementData = ['error' : ['Module error, module not available or unknown assay'] * samples.size() ] 196 moduleError = e.message 197 } 198 199 } 200 179 201 [ 'Subject Data' : getFieldValues(samples, fieldMap['Subject Data'], 'parentSubject'), 180 202 'Sampling Event Data' : getFieldValues(samples, fieldMap['Sampling Event Data'], 'parentEvent'), 181 203 'Sample Data' : getFieldValues(samples, fieldMap['Sample Data']), 182 204 'Event Group' : eventFieldMap, 183 184 // If module is not reachable, only the message 'module not reachable' is given for each sample 185 'Module Measurement Data': moduleCommunicationService.isModuleReachable(assay.module.url) ? 186 ( measurementTokens ? requestModuleMeasurements(assay, measurementTokens, samples) : [:] ) : 187 [ "Module error": [ "Module not reachable" ] * samples.size() ] 205 'Module Measurement Data' : moduleMeasurementData, 206 'ModuleError' : moduleError 188 207 ] 189 208 } … … 249 268 250 269 def path = moduleUrl + "/rest/getMeasurements/query" 251 def query = "assayToken=$ assay.assayUUID"270 def query = "assayToken=${assay.giveUUID()}" 252 271 def jsonArray 253 272 … … 274 293 * @param assay Assay for which the module measurements should be retrieved 275 294 * @param measurementTokens List with the names of the fields to be retrieved. Format: [ 'measurementName1', 'measurementName2' ] 276 * @param samples Samples for which the module295 * @param samples Samples to collect measurements for 277 296 * @return 278 297 */ … … 329 348 measurements << null 330 349 } else { 331 measurements << ( moduleData[ valueIndex ] == JSONObject.NULL ? "" : moduleData[ valueIndex ].toDouble() ); 350 351 def val 352 def measurement = moduleData[ valueIndex ] 353 354 if (measurement == JSONObject.NULL) val = "" 355 else if (measurement instanceof Number) val = measurement 356 else if (measurement.isDouble()) val = measurement.toDouble() 357 else val = measurement.toString() 358 measurements << val 332 359 } 333 360 } else { … … 487 514 // transpose d into row wise data and combine with header rows 488 515 headers + d.transpose() 489 } 516 } else [] 490 517 491 518 } -
trunk/grails-app/taglib/dbnp/studycapturing/AssayExporterTagLib.groovy
r1583 r1864 21 21 def categorySelector = {attrs, body -> 22 22 23 def categoryName = attrs.remove('category') 24 attrs['class'] = 'category' 23 25 out << '<div class="element">' 24 out << g.checkBox( name: attrs.ref, value: true, class: 'category')25 out << attrs.category26 out << g.checkBox(attrs) 27 out << categoryName 26 28 out << '</div>' 27 29 -
trunk/grails-app/views/assay/assayExport/compileExportData.gsp
r1841 r1864 14 14 <body> 15 15 16 <h1>Below you see a preview of the resulting file, click OK to generate it</h1> 16 <h1>Below you see a preview of the resulting file, click OK to download</h1> 17 18 <g:if test="${errorMessage}"> 19 <div class="errormessage">${errorMessage}</div> 20 </g:if> 17 21 18 22 <table> -
trunk/grails-app/views/assay/assayExport/selectFields.gsp
r1841 r1864 40 40 <h1>Select the columns that you want to be included in the resulting file</h1> 41 41 42 <g:if test="${errorMessage}"> 43 <div class="errormessage">${errorMessage}</div> 44 </g:if> 45 42 46 In this step you can make a selection from the available fields stored in the database related to the samples, including measurement data from a module (if available). 43 47 … … 47 51 <g:each in="${fieldMap}" var="entry"> 48 52 49 <assayExporter:categorySelector category="${entry.key}" ref="cat_${catNum}"/>53 <assayExporter:categorySelector category="${entry.key}" name="cat_${catNum}" value="${true}" /> 50 54 51 55 <assayExporter:fieldSelectors ref="cat_${catNum}" fields="${entry.value}"/> … … 55 59 </g:each> 56 60 57 <assayExporter:categorySelector category="Measurements" ref="cat_${catNum}"/>61 <assayExporter:categorySelector category="Measurements" name="cat_${catNum}" value="${measurementTokens as Boolean}" /> 58 62 <g:select name="measurementToken" id="measurementToken" from="${measurementTokens}" value="${measurementTokens}" class="field" multiple="true" /> 59 63 <br /><br /> -
trunk/grails-app/views/common/_topnav.gsp
r1841 r1864 15 15 <ul class="subnav"> 16 16 <li><g:link controller="simpleWizard" action="index">A complete study with straightforward design</g:link></li> 17 <li><g:link controller="simpleWizard" action="index" params="[inferDesign: true]">A complete study with inferred design</g:link></li>17 %{--<li><g:link controller="simpleWizard" action="index" params="[inferDesign: true]">A complete study with inferred design</g:link></li>--}% 18 18 <li><g:link controller="gdtImporter" action="index">A part of the study design</g:link></li> 19 19 <li><g:link controller="gdtImporter" action="index">A list of studies (choose Study)</g:link></li>
Note: See TracChangeset
for help on using the changeset viewer.