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

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

Fixed only being able to export to tab delimited; fixed 'null' values in export; fixed extra period between filename and extension

  • Property svn:keywords set to Rev Author Date
File size: 11.6 KB
RevLine 
[697]1package dbnp.studycapturing
2
3class AssayController {
4
[1752]5        def assayService
6        def authenticationService
[1798]7        def fileService
[697]8
[1752]9        static allowedMethods = [save: "POST", update: "POST", delete: "POST"]
[697]10
[1752]11        def index = {
12                redirect(action: "list", params: params)
13        }
[697]14
[1752]15        def list = {
16                params.max = Math.min(params.max ? params.int('max') : 10, 100)
17                [assayInstanceList: Assay.list(params), assayInstanceTotal: Assay.count()]
18        }
[697]19
[1752]20        def create = {
21                def assayInstance = new Assay()
22                assayInstance.properties = params
23                return [assayInstance: assayInstance]
24        }
[697]25
[1752]26        def save = {
27                def assayInstance = new Assay(params)
[697]28
[1752]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)
[697]33
[1752]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        }
[697]42
[1752]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
[942]54        def showByToken = {
[1752]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                }
[942]63        }
64
[1752]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        }
[697]75
[1752]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) {
[697]82
[1752]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        }
[1261]102
[1752]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        }
[1633]121
[1790]122        def assayExportFlow = {
[1752]123                entry {
124                        action{
125                                def user            = authenticationService.getLoggedInUser()
126                                flow.userStudies    = Study.giveReadableStudies(user)
127                        }
128                        on("success").to "selectAssay"
129                }
[1633]130
[1752]131                selectAssay {
132                        on ("submit"){
133                                flow.assay = Assay.get(params.assayId)
[1633]134
[1752]135                                // check if assay exists
[1790]136                                if (!flow.assay) throw new Exception("No assay found with id: ${params.assayId}")
[1633]137
[1752]138                                // obtain fields for each category
139                                flow.fieldMap = assayService.collectAssayTemplateFields(flow.assay)
[1559]140
[1752]141                                flow.measurementTokens = flow.fieldMap.remove('Module Measurement Data')
142                        }.to "selectFields"
[1559]143
[1752]144                        on(Exception).to "handleError"
145                }
[1559]146
[1752]147                selectFields {
148                        on ("submit"){
149                                def fieldMapSelection = [:]
[1633]150
[1752]151                                flow.fieldMap.eachWithIndex { cat, cat_i ->
[1559]152
[1752]153                                        if (params."cat_$cat_i" == 'on') {
154                                                fieldMapSelection[cat.key] = []
[1261]155
[1752]156                                                cat.value.eachWithIndex { field, field_i ->
[1425]157
[1752]158                                                        if (params."cat_${cat_i}_${field_i}" == 'on')
159                                                                fieldMapSelection[cat.key] += field
160                                                }
[1632]161
[1752]162                                                if (fieldMapSelection[cat.key] == [])
163                                                        fieldMapSelection.remove(cat.key)
164                                        }
165                                }
[1632]166
[1752]167                                def measurementTokens = []
[1632]168
[1752]169                                if (params."cat_4" == 'on') {
170                                        measurementTokens = params.list( "measurementToken" )
171                                }
[1632]172
[1827]173                // collect the assay data according to user selecting
[1752]174                                def assayData           = assayService.collectAssayData(flow.assay, fieldMapSelection, measurementTokens)
175                                flow.rowData            = assayService.convertColumnToRowStructure(assayData)
[1559]176
[1827]177                // prepare the assay data preview
[1798]178                                def previewRows         = Math.min(flow.rowData.size()    as int, 5) - 1
179                                def previewCols         = Math.min(flow.rowData[0].size() as int, 5) - 1
[1790]180
181                                flow.assayDataPreview   = flow.rowData[0..previewRows].collect{ it[0..previewCols] as ArrayList }
182
[1827]183                // store the selected file type in the flow
184                flow.exportFileType = params.exportFileType
185
[1752]186                        }.to "compileExportData"
[1559]187
[1752]188                        on(Exception).to "handleError"
189                }
[1559]190
[1752]191                compileExportData {
[1827]192                        on ("ok"){
193                session.rowData = flow.rowData
194                session.exportFileType = flow.exportFileType
195            }.to "export"
[1752]196                        on ("cancel").to "selectAssay"
197                }
[1559]198
[1752]199                export {
200                        redirect(action: 'doExport')
201                }
[1559]202
[1752]203                handleError() {
204                        render(view: 'errorPage')
205                }
206        }
[1559]207
[1798]208        /**
209         * Export the row data in session.rowData to the outputStream of the http
210         * response.
211         */
[1752]212        def doExport = {
[1559]213
[1827]214        // make sure we're coming from the export flow, otherwise redirect there
215        if (!(session.rowData && session.exportFileType))
216            redirect(action: 'assayExportFlow')
217
218        // process requested output file type
219        def outputDelimiter, outputFileExtension
220
221        switch(session.exportFileType) {
[1828]222            case '2': // Comma delimited csv
[1827]223                outputDelimiter = ','
[1828]224                outputFileExtension = 'csv'
[1827]225                break
[1828]226            case '3': // Semicolon delimited csv
[1827]227                outputDelimiter = ';'
[1828]228                outputFileExtension = 'csv'
[1827]229                break
230            default: // Tab delimited with .txt extension
231                outputDelimiter = '\t'
[1828]232                outputFileExtension = 'txt'
[1827]233        }
234
235                def filename = "export.$outputFileExtension"
[1752]236                response.setHeader("Content-disposition", "attachment;filename=\"${filename}\"")
237                response.setContentType("application/octet-stream")
238                try {
[1559]239
[1827]240                        // assayService.exportRowWiseDataToExcelFile(session.rowData, response.outputStream)
241                        assayService.exportRowWiseDataToCSVFile(session.rowData, response.outputStream, outputDelimiter)
[1559]242
[1798]243                        // clear the data from the session
244                        session.removeAttribute('rowData')
[1827]245                        session.removeAttribute('exportFileType')
[1761]246
[1752]247                } catch (Exception e) {
[1716]248
[1752]249                        flash.errorMessage = e.message
250                        redirect action: 'errorPage'
[1559]251
[1752]252                }
253        }
[1559]254
[1752]255        /**
256         * Method to export one or more assays to excel in separate sheets.
257         *
258         * @param       params.ids              One or more assay IDs to export
259         * @param       params.format   "list" in order to export all assays in one big excel sheet
260         *                                                      "sheets" in order to export every assay on its own sheet (default)
261         */
262        def exportToExcel = {
263                def format = params.get( 'format', 'sheets' );
264                if( format == 'list' ) {
265                        exportToExcelAsList( params );
266                } else {
267                        exportToExcelAsSheets( params );
268                }
269        }
[1559]270
[1752]271        /**
272         * Method to export one or more assays to excel in separate sheets.
273         *
274         * @param       params.ids              One or more assay IDs to export
275         */
276        def exportToExcelAsSheets = {
[1798]277                def assays = getAssaysFromParams( params );
278               
279                if( !assays )
[1752]280                        return;
281
282                // Send headers to the browser so the user can download the file
283                def filename = 'export.xlsx'
284                response.setHeader("Content-disposition", "attachment;filename=\"${filename}\"")
285                response.setContentType("application/octet-stream")
286
287                try {
288                        // Loop through all assays to collect the data
289                        def rowWiseAssayData = [];
290
291                        assays.each { assay ->
292                                // Determine which fields should be exported for this assay
293                                def fieldMap = assayService.collectAssayTemplateFields(assay)
294                                def measurementTokens = fieldMap.remove('Module Measurement Data')
295
296                                // Retrieve row based data for this assay
297                                def assayData = assayService.collectAssayData( assay, fieldMap, measurementTokens );
298                                def rowData   = assayService.convertColumnToRowStructure(assayData)
299
300                                // Put each assay on another sheet
301                                rowWiseAssayData << rowData;
302                        }
303
304                        assayService.exportRowWiseDataForMultipleAssaysToExcelFile( rowWiseAssayData, response.getOutputStream() )
305
306                        response.outputStream.flush()
307
308                } catch (Exception e) {
309                        throw e;
310                }
311        }
312
313        /**
314         * Method to export one or more assays to excel.
315         *
316         * @param       params.ids              One or more assay IDs to export
317         */
318        def exportToExcelAsList = {
[1798]319                def assays = getAssaysFromParams( params );
320               
321                if( !assays )
[1752]322                        return;
323
324                // Send headers to the browser so the user can download the file
[1799]325                def filename = 'export.csv'
[1752]326                response.setHeader("Content-disposition", "attachment;filename=\"${filename}\"")
327                response.setContentType("application/octet-stream")
328
329                try {
330                        // Loop through all assays to collect the data
331                        def columnWiseAssayData = [];
332
333                        assays.each { assay ->
334                                // Determine which fields should be exported for this assay
335                                def fieldMap = assayService.collectAssayTemplateFields(assay)
336                                def measurementTokens = fieldMap.remove('Module Measurement Data')
337
338                                // Retrieve row based data for this assay
339                                def assayData = assayService.collectAssayData( assay, fieldMap, measurementTokens );
[1798]340
[1752]341                                // Prepend study and assay data to the list
342                                assayData = assayService.prependAssayData( assayData, assay, assay.samples?.size() )
343                                assayData = assayService.prependStudyData( assayData, assay, assay.samples?.size() )
[1798]344
[1752]345                                // Put each assay on another sheet
346                                columnWiseAssayData << assayData;
347                        }
[1798]348
[1752]349                        // Merge data from all assays
350                        def mergedColumnWiseData = assayService.mergeColumnWiseDataOfMultipleStudies( columnWiseAssayData );
351
352                        def rowData   = assayService.convertColumnToRowStructure(mergedColumnWiseData)
[1799]353                        assayService.exportRowWiseDataToCSVFile( rowData, response.getOutputStream() )
[1752]354
355                        response.outputStream.flush()
356
357                } catch (Exception e) {
358                        throw e;
359                }
360        }
361
[1798]362        def getAssaysFromParams( params ) {
363                def ids = params.list( 'ids' ).findAll { it.isLong() }.collect { Long.valueOf( it ) };
364                def tokens = params.list( 'tokens' );
[1752]365
[1798]366                if( !ids && !tokens ) {
367                        flash.errorMessage = "No assay ids given";
368                        redirect( action: "errorPage" );
369                        return [];
370                }
371
372                // Find all assays for the given ids
373                def assays = [];
374                ids.each { id ->
375                        def assay = Assay.get( id );
376                        if( assay )
377                                assays << assay;
378                }
379
380                // Also accept tokens for defining studies
381                tokens.each { token ->
382                        def assay = Assay.findByAssayUUID( token );
383                        if( assay )
384                                assays << assay;
385                }
386               
387                if( !assays ) {
388                        flash.errorMessage = "No assays found";
389                        redirect( action: "errorPage" );
390                        return [];
391                }
392               
393                return assays.unique();
394        }
395
[1752]396        def errorPage = {
[1790]397                render(view: 'assayExport/errorPage')
[1752]398        }
[697]399}
Note: See TracBrowser for help on using the repository browser.