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

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