source: trunk/grails-app/controllers/dbnp/studycapturing/AssayController.groovy @ 1864

Last change on this file since 1864 was 1864, checked in by s.h.sikkema@…, 9 years ago

in exporter: module error display improvements (ie. display on screen but still able to export); removed changes to simplewizard; removed unnecessary imports; should handle 'null' parent subject from samples correctly; should handle non number values from modules correctly; deselects module measurements in case of module error/no measurements; removed obsolete entry in topnav

  • Property svn:keywords set to Rev Author Date
File size: 11.8 KB
Line 
1package dbnp.studycapturing
2
3class AssayController {
4
5        def assayService
6        def authenticationService
7        def fileService
8
9        static allowedMethods = [save: "POST", update: "POST", delete: "POST"]
10
11        def index = {
12                redirect(action: "list", params: params)
13        }
14
15        def list = {
16                params.max = Math.min(params.max ? params.int('max') : 10, 100)
17                [assayInstanceList: Assay.list(params), assayInstanceTotal: Assay.count()]
18        }
19
20        def create = {
21                def assayInstance = new Assay()
22                assayInstance.properties = params
23                return [assayInstance: assayInstance]
24        }
25
26        def save = {
27                def assayInstance = new Assay(params)
28
29                // The following lines deviate from the generate-all generated code.
30                // See http://jira.codehaus.org/browse/GRAILS-3783 for why we have this shameful workaround...
31                def study = assayInstance.parent
32                study.addToAssays(assayInstance)
33
34                if (assayInstance.save(flush: true)) {
35                        flash.message = "${message(code: 'default.created.message', args: [message(code: 'assay.label', default: 'Assay'), assayInstance.id])}"
36                        redirect(action: "show", id: assayInstance.id)
37                }
38                else {
39                        render(view: "create", model: [assayInstance: assayInstance])
40                }
41        }
42
43        def show = {
44                def assayInstance = Assay.get(params.id)
45                if (!assayInstance) {
46                        flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'assay.label', default: 'Assay'), params.id])}"
47                        redirect(action: "list")
48                }
49                else {
50                        [assayInstance: assayInstance]
51                }
52        }
53
54        def showByToken = {
55                def assayInstance = Assay.findByAssayUUID(params.id)
56                if (!assayInstance) {
57                        flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'assay.label', default: 'Assay'), params.id])}"
58                        redirect(action: "list")
59                }
60                else {
61                        redirect(action: "show", id: assayInstance.id)
62                }
63        }
64
65        def edit = {
66                def assayInstance = Assay.get(params.id)
67                if (!assayInstance) {
68                        flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'assay.label', default: 'Assay'), params.id])}"
69                        redirect(action: "list")
70                }
71                else {
72                        return [assayInstance: assayInstance]
73                }
74        }
75
76        def update = {
77                def assayInstance = Assay.get(params.id)
78                if (assayInstance) {
79                        if (params.version) {
80                                def version = params.version.toLong()
81                                if (assayInstance.version > version) {
82
83                                        assayInstance.errors.rejectValue("version", "default.optimistic.locking.failure", [message(code: 'assay.label', default: 'Assay')] as Object[], "Another user has updated this Assay while you were editing")
84                                        render(view: "edit", model: [assayInstance: assayInstance])
85                                        return
86                                }
87                        }
88                        assayInstance.properties = params
89                        if (!assayInstance.hasErrors() && assayInstance.save(flush: true)) {
90                                flash.message = "${message(code: 'default.updated.message', args: [message(code: 'assay.label', default: 'Assay'), assayInstance.id])}"
91                                redirect(action: "show", id: assayInstance.id)
92                        }
93                        else {
94                                render(view: "edit", model: [assayInstance: assayInstance])
95                        }
96                }
97                else {
98                        flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'assay.label', default: 'Assay'), params.id])}"
99                        redirect(action: "list")
100                }
101        }
102
103        def delete = {
104                def assayInstance = Assay.get(params.id)
105                if (assayInstance) {
106                        try {
107                                assayInstance.delete(flush: true)
108                                flash.message = "${message(code: 'default.deleted.message', args: [message(code: 'assay.label', default: 'Assay'), params.id])}"
109                                redirect(action: "list")
110                        }
111                        catch (org.springframework.dao.DataIntegrityViolationException e) {
112                                flash.message = "${message(code: 'default.not.deleted.message', args: [message(code: 'assay.label', default: 'Assay'), params.id])}"
113                                redirect(action: "show", id: params.id)
114                        }
115                }
116                else {
117                        flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'assay.label', default: 'Assay'), params.id])}"
118                        redirect(action: "list")
119                }
120        }
121
122        def assayExportFlow = {
123                entry {
124                        action{
125                                def user            = authenticationService.getLoggedInUser()
126                                flow.userStudies    = Study.giveReadableStudies(user)
127                        }
128                        on("success").to "selectAssay"
129                }
130
131                selectAssay {
132                        on ("submit"){
133                                flow.assay = Assay.get(params.assayId)
134
135                                // check if assay exists
136                                if (!flow.assay) throw new Exception("No assay found with id: ${params.assayId}")
137
138                                // obtain fields for each category
139                                flow.fieldMap = assayService.collectAssayTemplateFields(flow.assay)
140
141                flash.errorMessage = flow.fieldMap.remove('ModuleError')
142                                flow.measurementTokens = flow.fieldMap.remove('Module Measurement Data')
143                        }.to "selectFields"
144
145                        on(Exception).to "handleError"
146                }
147
148                selectFields {
149                        on ("submit"){
150               
151                                def fieldMapSelection = [:]
152
153                                flow.fieldMap.eachWithIndex { cat, cat_i ->
154
155                                        if (params."cat_$cat_i" == 'on') {
156                                                fieldMapSelection[cat.key] = []
157
158                                                cat.value.eachWithIndex { field, field_i ->
159
160                                                        if (params."cat_${cat_i}_${field_i}" == 'on')
161                                                                fieldMapSelection[cat.key] += field
162                                                }
163
164                                                if (fieldMapSelection[cat.key] == [])
165                                                        fieldMapSelection.remove(cat.key)
166                                        }
167                                }
168
169                                def measurementTokens = []
170
171                                if (params."cat_4" == 'on') {
172                                        measurementTokens = params.list( "measurementToken" )
173                                }
174
175                // collect the assay data according to user selecting
176                                def assayData           = assayService.collectAssayData(flow.assay, fieldMapSelection, measurementTokens)
177
178                flash.errorMessage      = assayData.remove('ModuleError')
179
180                                flow.rowData            = assayService.convertColumnToRowStructure(assayData)
181
182                // prepare the assay data preview
183                                def previewRows         = Math.min(flow.rowData.size()    as int, 5) - 1
184                                def previewCols         = Math.min(flow.rowData[0].size() as int, 5) - 1
185
186                                flow.assayDataPreview   = flow.rowData[0..previewRows].collect{ it[0..previewCols] as ArrayList }
187
188                // store the selected file type in the flow
189                flow.exportFileType = params.exportFileType
190
191                        }.to "compileExportData"
192
193                        on(Exception).to "handleError"
194                }
195
196                compileExportData {
197                        on ("ok"){
198                session.rowData = flow.rowData
199                session.exportFileType = flow.exportFileType
200            }.to "export"
201                        on ("cancel").to "selectAssay"
202                }
203
204                export {
205                        redirect(action: 'doExport')
206                }
207
208                handleError() {
209                        render(view: 'errorPage')
210                }
211        }
212
213        /**
214         * Export the row data in session.rowData to the outputStream of the http
215         * response.
216         */
217        def doExport = {
218
219        // make sure we're coming from the export flow, otherwise redirect there
220        if (!(session.rowData && session.exportFileType))
221            redirect(action: 'assayExportFlow')
222
223        // process requested output file type
224        def outputDelimiter, outputFileExtension, locale = java.util.Locale.US
225
226        switch(session.exportFileType) {
227            case '2': // Comma delimited csv
228                outputDelimiter = ','
229                outputFileExtension = 'csv'
230                break
231            case '3': // Semicolon delimited csv
232                outputDelimiter = ';'
233                outputFileExtension = 'csv'
234                locale = java.util.Locale.GERMAN // force use of comma as decimal separator
235                break
236            default: // Tab delimited with .txt extension
237                outputDelimiter = '\t'
238                outputFileExtension = 'txt'
239        }
240
241                def filename = "export.$outputFileExtension"
242                response.setHeader("Content-disposition", "attachment;filename=\"${filename}\"")
243                response.setContentType("application/octet-stream")
244                try {
245
246                        assayService.exportRowWiseDataToCSVFile(session.rowData, response.outputStream, outputDelimiter, locale)
247
248                        // clear the data from the session
249                        session.removeAttribute('rowData')
250                        session.removeAttribute('exportFileType')
251
252                } catch (Exception e) {
253
254                        flash.errorMessage = e.message
255                        redirect action: 'errorPage'
256
257                }
258        }
259
260        /**
261         * Method to export one or more assays to excel in separate sheets.
262         *
263         * @param       params.ids              One or more assay IDs to export
264         * @param       params.format   "list" in order to export all assays in one big excel sheet
265         *                                                      "sheets" in order to export every assay on its own sheet (default)
266         */
267        def exportToExcel = {
268                def format = params.get( 'format', 'sheets' );
269                if( format == 'list' ) {
270                        exportToExcelAsList( params );
271                } else {
272                        exportToExcelAsSheets( params );
273                }
274        }
275
276        /**
277         * Method to export one or more assays to excel in separate sheets.
278         *
279         * @param       params.ids              One or more assay IDs to export
280         */
281        def exportToExcelAsSheets = {
282                def assays = getAssaysFromParams( params );
283               
284                if( !assays )
285                        return;
286
287                // Send headers to the browser so the user can download the file
288                def filename = 'export.xlsx'
289                response.setHeader("Content-disposition", "attachment;filename=\"${filename}\"")
290                response.setContentType("application/octet-stream")
291
292                try {
293                        // Loop through all assays to collect the data
294                        def rowWiseAssayData = [];
295
296                        assays.each { assay ->
297                                // Determine which fields should be exported for this assay
298                                def fieldMap = assayService.collectAssayTemplateFields(assay)
299                                def measurementTokens = fieldMap.remove('Module Measurement Data')
300
301                                // Retrieve row based data for this assay
302                                def assayData = assayService.collectAssayData( assay, fieldMap, measurementTokens );
303                                def rowData   = assayService.convertColumnToRowStructure(assayData)
304
305                                // Put each assay on another sheet
306                                rowWiseAssayData << rowData;
307                        }
308
309                        assayService.exportRowWiseDataForMultipleAssaysToExcelFile( rowWiseAssayData, response.getOutputStream() )
310
311                        response.outputStream.flush()
312
313                } catch (Exception e) {
314                        throw e;
315                }
316        }
317
318        /**
319         * Method to export one or more assays to excel.
320         *
321         * @param       params.ids              One or more assay IDs to export
322         */
323        def exportToExcelAsList = {
324                def assays = getAssaysFromParams( params );
325               
326                if( !assays )
327                        return;
328
329                // Send headers to the browser so the user can download the file
330                def filename = 'export.csv'
331                response.setHeader("Content-disposition", "attachment;filename=\"${filename}\"")
332                response.setContentType("application/octet-stream")
333
334                try {
335                        // Loop through all assays to collect the data
336                        def columnWiseAssayData = [];
337
338                        assays.each { assay ->
339                                // Determine which fields should be exported for this assay
340                                def fieldMap = assayService.collectAssayTemplateFields(assay)
341                                def measurementTokens = fieldMap.remove('Module Measurement Data')
342
343                                // Retrieve row based data for this assay
344                                def assayData = assayService.collectAssayData( assay, fieldMap, measurementTokens );
345
346                                // Prepend study and assay data to the list
347                                assayData = assayService.prependAssayData( assayData, assay, assay.samples?.size() )
348                                assayData = assayService.prependStudyData( assayData, assay, assay.samples?.size() )
349
350                                // Put each assay on another sheet
351                                columnWiseAssayData << assayData;
352                        }
353
354                        // Merge data from all assays
355                        def mergedColumnWiseData = assayService.mergeColumnWiseDataOfMultipleStudies( columnWiseAssayData );
356
357                        def rowData   = assayService.convertColumnToRowStructure(mergedColumnWiseData)
358                        assayService.exportRowWiseDataToCSVFile( rowData, response.getOutputStream() )
359
360                        response.outputStream.flush()
361
362                } catch (Exception e) {
363                        throw e;
364                }
365        }
366
367        def getAssaysFromParams( params ) {
368                def ids = params.list( 'ids' ).findAll { it.isLong() }.collect { Long.valueOf( it ) };
369                def tokens = params.list( 'tokens' );
370
371                if( !ids && !tokens ) {
372                        flash.errorMessage = "No assay ids given";
373                        redirect( action: "errorPage" );
374                        return [];
375                }
376
377                // Find all assays for the given ids
378                def assays = [];
379                ids.each { id ->
380                        def assay = Assay.get( id );
381                        if( assay )
382                                assays << assay;
383                }
384
385                // Also accept tokens for defining studies
386                tokens.each { token ->
387                        def assay = Assay.findByAssayUUID( token );
388                        if( assay )
389                                assays << assay;
390                }
391               
392                if( !assays ) {
393                        flash.errorMessage = "No assays found";
394                        redirect( action: "errorPage" );
395                        return [];
396                }
397               
398                return assays.unique();
399        }
400
401        def errorPage = {
402                render(view: 'assayExport/errorPage')
403        }
404}
Note: See TracBrowser for help on using the repository browser.