Changeset 1419
- Timestamp:
- Jan 20, 2011, 4:28:45 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/grails-app/controllers/dbnp/importer/ImporterController.groovy
r1418 r1419 1 1 package dbnp.importer 2 2 3 import dbnp.studycapturing.Study 3 4 import dbnp.studycapturing.Subject … … 20 21 * Wizard Controller 21 22 * 22 * @author 23 * @since 23 * @author Jeroen Wesbeek 24 * @since 20101206 24 25 * 25 26 * Revision information: … … 30 31 @Secured(['IS_AUTHENTICATED_REMEMBERED']) 31 32 class ImporterController { 32 // the pluginManager is used to check if the Grom 33 // plugin is available so we can 'Grom' development 34 // notifications to the unified notifications daemon 35 // (see http://www.grails.org/plugin/grom) 36 def pluginManager 37 def AuthenticationService 38 def fileService 39 def ImporterService 40 def validationTagLib = new ValidationTagLib() 41 42 /** 43 * index method, redirect to the webflow 44 * @void 45 */ 46 def index = { 47 // Grom a development message 48 if (pluginManager.getGrailsPlugin('grom')) "redirecting into the webflow".grom() 49 50 51 // TODO --> move this logic to the application Bootstrapping as this 33 // the pluginManager is used to check if the Grom 34 // plugin is available so we can 'Grom' development 35 // notifications to the unified notifications daemon 36 // (see http://www.grails.org/plugin/grom) 37 def pluginManager 38 def AuthenticationService 39 def fileService 40 def ImporterService 41 def validationTagLib = new ValidationTagLib() 42 43 /** 44 * index method, redirect to the webflow 45 * @void 46 */ 47 def index = { 48 // Grom a development message 49 if (pluginManager.getGrailsPlugin('grom')) "redirecting into the webflow".grom() 50 51 // TODO --> move this logic to the application Bootstrapping as this 52 52 // does not need to run every time the importer is started 53 53 // 54 55 56 it.value.encrypted = 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 flow.studies = Study.findAllWhere(owner:AuthenticationService.getLoggedInUser())130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 } else 151 { 152 log.error ".importer wizard wrong permissions" 153 this.appendErrorMap(['error': "You don't have the right permissions"], flash.wizardErrors) 154 155 error() 156 } 157 else{158 if (fileImportPage(flow, params)) { 159 success() 160 } else { 161 log.error ".importer wizard not all fields are filled in" 162 this.appendErrorMap(['error': "Not all fields are filled in, please fill in or select all fields"], flash.wizardErrors)163 error() 164 165 } 166 167 // put your bussiness logic (if applicable) in here 168 }.to "pageTwo" 169 } 170 171 // Property to column assignment page 172 pageTwo { 173 render(view: "_page_two") 174 onRender { 175 log.info ".import wizard properties page" 176 // Grom a development message 177 if (pluginManager.getGrailsPlugin('grom')) ".rendering the partial: pages/_page_two.gsp".grom() 178 179 flow.page = 2 180 success() 181 } 182 on("next") {183 if (propertiesPage(flow, params)) { 184 success() 185 } else { 186 log.error ".import wizard, properties are set wrong" 187 error() 188 } 189 }.to "pageThree"190 on("previous").to "pageOne" 191 } 192 193 // Mapping page 194 pageThree { 195 render(view: "_page_three") 196 onRender { 197 log.info ".import wizard mapping page" 198 // Grom a development message 199 if (pluginManager.getGrailsPlugin('grom')) ".rendering the partial pages/_page_three.gsp".grom() 200 201 flow.page = 3 202 success() 203 } 204 on("refresh") { 205 success() 206 }.to "pageThree" 207 on("next") {208 if (mappingsPage(flow, flash, params)) { 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 success() 231 } else { 232 log.error ".import wizard imported error, something went wrong showing the imported entities" 233 error() 234 } 235 flow.page = 5 236 237 238 239 240 241 242 243 244 245 246 247 if (pluginManager.getGrailsPlugin('grom')) ".persisting instances to the database...".grom() 248 249 54 // encrypt the importable entities 55 grailsApplication.config.gscf.domain.importableEntities.each { 56 it.value.encrypted = 57 URLEncoder.encode(Blowfish.encryptBase64( 58 it.value.entity.toString().replaceAll(/^class /, ''), 59 grailsApplication.config.crypto.shared.secret 60 )) 61 } 62 63 /** 64 * Do you believe it in your head? 65 * I can go with the flow 66 * Don't say it doesn't matter (with the flow) matter anymore 67 * I can go with the flow (I can go) 68 * Do you believe it in your head? 69 */ 70 redirect(action: 'pages') 71 } 72 73 /** 74 * WebFlow definition 75 * @void 76 */ 77 def pagesFlow = { 78 // start the flow 79 onStart { 80 // Grom a development message 81 if (pluginManager.getGrailsPlugin('grom')) "entering the WebFlow".grom() 82 83 // define variables in the flow scope which is availabe 84 // throughout the complete webflow also have a look at 85 // the Flow Scopes section on http://www.grails.org/WebFlow 86 // 87 // The following flow scope variables are used to generate 88 // wizard tabs. Also see common/_tabs.gsp for more information 89 flow.page = 0 90 flow.pages = [ 91 [title: 'Import file'], 92 [title: 'Properties'], 93 [title: 'Mappings'], 94 //[title: 'Imported'], 95 [title: 'Persist'] 96 ] 97 flow.cancel = true; 98 flow.quickSave = true; 99 100 success() 101 } 102 103 // render the main wizard page which immediately 104 // triggers the 'next' action (hence, the main 105 // page dynamically renders the study template 106 // and makes the flow jump to the study logic) 107 mainPage { 108 render(view: "/importer/index") 109 onRender { 110 // Grom a development message 111 if (pluginManager.getGrailsPlugin('grom')) "rendering the main Ajaxflow page (index.gsp)".grom() 112 113 // let the view know we're in page 1 114 flow.page = 1 115 success() 116 } 117 on("next").to "pageOne" 118 } 119 120 // File import and entitie template selection page 121 pageOne { 122 render(view: "_page_one") 123 onRender { 124 log.info ".entering import wizard" 125 // Grom a development message 126 if (pluginManager.getGrailsPlugin('grom')) ".rendering the partial: pages/_page_one.gsp".grom() 127 128 flow.page = 1 129 flow.studies = Study.findAllWhere(owner: AuthenticationService.getLoggedInUser()) 130 flow.importer_importableentities = grailsApplication.config.gscf.domain.importableEntities 131 132 success() 133 } 134 on("next") { 135 flash.wizardErrors = [:] 136 137 // Study selected? 138 flow.importer_study = (params.study) ? Study.get(params.study.id.toInteger()) : null 139 140 // Trying to import data into an existing study? 141 if (flow.importer_study) 142 if (flow.importer_study.canWrite(AuthenticationService.getLoggedInUser())) { 143 if (fileImportPage(flow, params)) { 144 success() 145 } else { 146 log.error ".importer wizard not all fields are filled in" 147 this.appendErrorMap(['error': "Not all fields are filled in, please fill in or select all fields"], flash.wizardErrors) 148 error() 149 } 150 } else { 151 log.error ".importer wizard wrong permissions" 152 this.appendErrorMap(['error': "You don't have the right permissions"], flash.wizardErrors) 153 154 error() 155 } 156 else { 157 if (fileImportPage(flow, params)) { 158 success() 159 } else { 160 log.error ".importer wizard not all fields are filled in" 161 this.appendErrorMap(['error': "Not all fields are filled in, please fill in or select all fields"], flash.wizardErrors) 162 error() 163 } 164 } 165 166 // put your bussiness logic (if applicable) in here 167 }.to "pageTwo" 168 } 169 170 // Property to column assignment page 171 pageTwo { 172 render(view: "_page_two") 173 onRender { 174 log.info ".import wizard properties page" 175 // Grom a development message 176 if (pluginManager.getGrailsPlugin('grom')) ".rendering the partial: pages/_page_two.gsp".grom() 177 178 flow.page = 2 179 success() 180 } 181 on("next") { 182 if (propertiesPage(flow, params)) { 183 success() 184 } else { 185 log.error ".import wizard, properties are set wrong" 186 error() 187 } 188 }.to "pageThree" 189 on("previous").to "pageOne" 190 } 191 192 // Mapping page 193 pageThree { 194 render(view: "_page_three") 195 onRender { 196 log.info ".import wizard mapping page" 197 // Grom a development message 198 if (pluginManager.getGrailsPlugin('grom')) ".rendering the partial pages/_page_three.gsp".grom() 199 200 flow.page = 3 201 success() 202 } 203 on("refresh") { 204 success() 205 }.to "pageThree" 206 on("next") { 207 if (mappingsPage(flow, flash, params)) { 208 flow.page = 4 209 success() 210 } else { 211 log.error ".import wizard mapping error, could not validate all entities" 212 error() 213 } 214 }.to "save" 215 on("previous").to "pageTwo" 216 } 217 218 // Imported data overview page 219 pageFour { 220 render(view: "_page_four") 221 onRender { 222 // Grom a development message 223 if (pluginManager.getGrailsPlugin('grom')) ".rendering the partial pages/_page_four.gsp".grom() 224 225 flow.page = 4 226 success() 227 } 228 on("next") { 229 if (importedPage(flow, params)) { 230 flow.page = 4 231 success() 232 } else { 233 log.error ".import wizard imported error, something went wrong showing the imported entities" 234 error() 235 } 236 }.to "save" 237 on("previous").to "pageThree" 238 } 239 240 // Save the imported data 241 save { 242 action { 243 // here you can validate and save the 244 // instances you have created in the 245 // ajax flow. 246 // Grom a development message 247 if (pluginManager.getGrailsPlugin('grom')) ".persisting instances to the database...".grom() 248 249 if (saveEntities(flow, params)) { 250 250 //if (ImporterService.saveDatamatrix(flow.importer_study, flow.importer_importeddata)) { 251 log.error ".import wizard succesfully persisted all entities" 252 253 254 255 } else { 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 finalPage { 284 285 286 287 288 289 290 291 292 293 294 251 log.error ".import wizard succesfully persisted all entities" 252 //def session = sessionFactory.getCurrentSession() 253 //session.clear() 254 success() 255 } else { 256 log.error ".import wizard, could not save entities:\n" + e.dump() 257 flow.page = 4 258 error() 259 } 260 } 261 on("error").to "error" 262 on(Exception).to "error" 263 on("success").to "finalPage" 264 } 265 266 // render errors 267 error { 268 render(view: "_error") 269 onRender { 270 271 // Grom a development message 272 if (pluginManager.getGrailsPlugin('grom')) ".rendering the partial pages/_error.gsp".grom() 273 274 // set page to 4 so that the navigation 275 // works (it is disabled on the final page) 276 flow.page = 4 277 } 278 on("next").to "save" 279 on("previous").to "pageFour" 280 } 281 282 // last wizard page 283 finalPage { 284 render(view: "_final_page") 285 onRender { 286 println "EEN" 287 // Grom a development message 288 if (pluginManager.getGrailsPlugin('grom')) ".rendering the partial pages/_final_page.gsp".grom() 289 println "TWEE" 290 291 success() 292 println "DRIE" 293 } 294 onEnd { 295 295 // clean flow scope 296 296 flow.clear() 297 297 } 298 299 300 301 302 303 304 305 306 307 def ajaxGetTemplatesByEntity = { 308 def entityName = Blowfish.decryptBase64( 309 310 311 312 313 314 315 316 317 318 319 // render as JSON320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 //flow.importer_workbook = wb // workbook object must be serialized for this to work 349 350 351 flow.importer_sheetindex = params.sheetindex.toInteger() -1 // 0 == first sheet352 flow.importer_datamatrix_start = params.datamatrix_start.toInteger() -1 // 0 == first row353 354 355 356 357 358 359 360 361 362 363 364 selectedentities.add([name:entityName, columnindex:it.key.toInteger()])365 366 367 flow.importer_selectedentities = selectedentities 368 369 370 371 372 373 374 375 376 flow.importer_allfieldtypes = "true" 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 boolean propertiesPage(flow, params) {394 395 396 397 398 399 400 401 def entityObj = entityClass.newInstance(template:template)402 403 404 405 406 407 408 409 410 flow.importer_header[columnindex.toInteger()].dontimport = (property=="dontimport") ? true : false411 412 413 414 (it.preferredIdentifier && (it.name==property)) ? flow.importer_header[columnindex.toInteger()].identifier = true : false415 416 417 418 419 420 421 422 423 424 425 flow.importer_importeddata = table 426 427 428 429 430 431 432 433 434 435 436 437 438 439 flow.importer_invalidentities = 0 440 441 442 table.each { entity -> 443 444 445 446 entity.giveFields().each { field -> 447 448 449 450 451 452 453 454 455 456 entity.setFieldValue(field.toString(), params["entity_" + entity.getIdentifier() + "_" + field.escapedName()])457 458 459 entity.setFieldValue(field.toString(), params["entity_" + entity.getIdentifier() + "_" + field.escapedName()])460 461 462 463 464 case [Subject, Sample, Event]:entity.parent = flow.importer_study465 466 467 468 469 470 471 // add errors to map 472 this.appendErrors(entity, flash.wizardErrors, "entity_"+entity.getIdentifier() + "_")473 298 } 299 } 300 301 /** 302 * Return templates which belong to a certain entity type 303 * 304 * @param entity entity name string (Sample, Subject, Study et cetera) 305 * @return JSON object containing the found templates 306 */ 307 def ajaxGetTemplatesByEntity = { 308 def entityName = Blowfish.decryptBase64( 309 URLDecoder.decode(params.entity), 310 grailsApplication.config.crypto.shared.secret 311 ) 312 313 //def entityClass = grailsApplication.config.gscf.domain.importableEntities.get(params.entity).entity 314 def entityClass = entityName 315 316 // fetch all templates for a specific entity 317 def templates = Template.findAllByEntity(Class.forName(entityClass, true, this.getClass().getClassLoader())) 318 319 // render as JSON 320 render templates as JSON 321 } 322 323 /** 324 * Handle the file import page. 325 * 326 * @param Map LocalAttributeMap (the flow scope) 327 * @param Map GrailsParameterMap (the flow parameters = form data) 328 * @returns boolean true if correctly validated, otherwise false 329 */ 330 boolean fileImportPage(flow, params) { 331 def importedfile = fileService.get(params['importfile']) 332 //fileService.delete(YourFile) 333 334 if (params.entity && params.template_id && importedfile.exists()) { 335 // create a workbook instance of the file 336 session.importer_workbook = ImporterService.getWorkbook(new FileInputStream(importedfile)) 337 338 def selectedentities = [] 339 340 def entityName = Blowfish.decryptBase64( 341 URLDecoder.decode(params.entity), 342 grailsApplication.config.crypto.shared.secret 343 ) 344 345 def entityClass = Class.forName(entityName, true, this.getClass().getClassLoader()) 346 347 // Initialize some session variables 348 //flow.importer_workbook = wb // workbook object must be serialized for this to work 349 350 flow.importer_template_id = params.template_id 351 flow.importer_sheetindex = params.sheetindex.toInteger() - 1 // 0 == first sheet 352 flow.importer_datamatrix_start = params.datamatrix_start.toInteger() - 1 // 0 == first row 353 flow.importer_headerrow = params.headerrow.toInteger() 354 355 // Get the header from the Excel file using the arguments given in the first step of the wizard 356 flow.importer_header = ImporterService.getHeader(session.importer_workbook, 357 flow.importer_sheetindex, 358 flow.importer_headerrow, 359 flow.importer_datamatrix_start, 360 entityClass) 361 362 // Initialize 'selected entities', used to show entities above the columns 363 flow.importer_header.each { 364 selectedentities.add([name: entityName, columnindex: it.key.toInteger()]) 365 } 366 367 flow.importer_selectedentities = selectedentities 368 369 session.importer_datamatrix = ImporterService.getDatamatrix( 370 session.importer_workbook, flow.importer_header, 371 flow.importer_sheetindex, 372 flow.importer_datamatrix_start, 373 5) 374 375 flow.importer_templates = Template.get(flow.importer_template_id) 376 flow.importer_allfieldtypes = "true" 377 /*else { 378 render (template:"common/error", 379 model:[error:"Wrong permissions: you are not allowed to write to the study you selected (${flow.importer_study})."]) 380 }*/ 381 382 return true 383 } 384 } 385 386 /** 387 * Handle the property mapping page. 388 * 389 * @param Map LocalAttributeMap (the flow scope) 390 * @param Map GrailsParameterMap (the flow parameters = form data) 391 * @returns boolean true if correctly validated, otherwise false 392 */ 393 boolean propertiesPage(flow, params) { 394 // Find actual Template object from the chosen template name 395 def template = Template.get(flow.importer_template_id) 396 397 params.columnproperty.index.each { columnindex, property -> 398 // Create an actual class instance of the selected entity with the selected template 399 // This should be inside the closure because in some cases in the advanced importer, the fields can have different target entities 400 def entityClass = Class.forName(flow.importer_header[columnindex.toInteger()].entity.getName(), true, this.getClass().getClassLoader()) 401 def entityObj = entityClass.newInstance(template: template) 402 403 // Store the selected property for this column into the column map for the ImporterService 404 flow.importer_header[columnindex.toInteger()].property = property 405 406 // Look up the template field type of the target TemplateField and store it also in the map 407 flow.importer_header[columnindex.toInteger()].templatefieldtype = entityObj.giveFieldType(property) 408 409 // Is a "Don't import" property assigned to the column? 410 flow.importer_header[columnindex.toInteger()].dontimport = (property == "dontimport") ? true : false 411 412 //if it's an identifier set the mapping column true or false 413 entityObj.giveFields().each { 414 (it.preferredIdentifier && (it.name == property)) ? flow.importer_header[columnindex.toInteger()].identifier = true : false 415 } 416 } 417 418 // Import the workbook and store the table with entity records and store the failed cells 419 def (table, failedcells) = ImporterService.importData(flow.importer_template_id, 420 session.importer_workbook, 421 flow.importer_sheetindex, 422 flow.importer_datamatrix_start, 423 flow.importer_header) 424 425 flow.importer_importeddata = table 426 flow.importer_failedcells = failedcells 427 return true 428 } 429 430 /** 431 * Handle the mapping page. 432 * 433 * @param Map LocalAttributeMap (the flow scope) 434 * @param Map GrailsParameterMap (the flow parameters = form data) 435 * @returns boolean true if correctly validated, otherwise false 436 */ 437 boolean mappingsPage(flow, flash, params) { 438 flash.wizardErrors = [:] 439 flow.importer_invalidentities = 0 440 441 flow.importer_importeddata.each { table -> 442 table.each { entity -> 443 def invalidontologies = 0 444 445 // Set the fields for this entity by retrieving values from the params 446 entity.giveFields().each { field -> 447 // field of type ontology and value "#invalidterm"? 448 if (field.type == dbnp.studycapturing.TemplateFieldType.ONTOLOGYTERM && 449 params["entity_" + entity.getIdentifier() + "_" + field.escapedName()] == "#invalidterm" 450 ) { 451 invalidontologies++ 452 } else 453 if (field.type == dbnp.studycapturing.TemplateFieldType.ONTOLOGYTERM && 454 params["entity_" + entity.getIdentifier() + "_" + field.escapedName()] != "#invalidterm") { 455 removeFailedCell(flow.importer_failedcells, entity) 456 entity.setFieldValue(field.toString(), params["entity_" + entity.getIdentifier() + "_" + field.escapedName()]) 457 } 458 else 459 entity.setFieldValue(field.toString(), params["entity_" + entity.getIdentifier() + "_" + field.escapedName()]) 460 } 461 462 // Determine entity class and add a parent (defined as Study in first step of wizard) 463 switch (entity.getClass()) { 464 case [Subject, Sample, Event]: entity.parent = flow.importer_study 465 } 466 467 // Try to validate the entity now all fields have been set 468 if (!entity.validate() || invalidontologies) { 469 flow.importer_invalidentities++ 470 471 // add errors to map 472 this.appendErrors(entity, flash.wizardErrors, "entity_" + entity.getIdentifier() + "_") 473 474 474 entity.errors.getAllErrors().each() { 475 475 log.error ".import wizard imported validation error:" + it 476 476 } 477 } else { 478 479 480 481 482 483 484 485 486 487 488 489 490 491 def removeFailedCell(failedcells, entity) { 492 493 494 495 496 record.importcells.each { cell -> 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 boolean saveEntities(flow, params) { 521 522 523 524 525 526 477 } else { 478 removeFailedCell(flow.importer_failedcells, entity) 479 } // end else if 480 481 } // end of record 482 } // end of table 483 484 return (flow.importer_invalidentities == 0) ? true : false 485 } // end of method 486 487 /** 488 * @param failedcell failed ontology cells 489 * @param entity entity to remove from the failedcells list 490 */ 491 def removeFailedCell(failedcells, entity) { 492 // Valid entity, remove it from failedcells 493 failedcells.each { record -> 494 def tempimportcells = [] 495 496 record.importcells.each { cell -> 497 // remove the cell from the failed cells session 498 if (cell.entityidentifier != entity.getIdentifier()) { 499 //record.removeFromImportcells(cell) 500 tempimportcells.add(cell) 501 } 502 } 503 504 record.importcells = tempimportcells 505 // } // end of importcells 506 } // end of failedcells 507 } 508 509 /** 510 * Handle the imported entities page. 511 * 512 * @param Map LocalAttributeMap (the flow scope) 513 * @param Map GrailsParameterMap (the flow parameters = form data) 514 * @returns boolean true if correctly validated, otherwise false 515 */ 516 boolean importedPage(flow, params) { 517 return true 518 } 519 520 boolean saveEntities(flow, params) { 521 //def (validatedSuccesfully, updatedEntities, failedToPersist) = 522 //try { 523 ImporterService.saveDatamatrix(flow.importer_study, flow.importer_importeddata) 524 525 //} 526 //catch (Exception e) { 527 527 // log.error ".import wizard saveEntities error\n" + e.dump() 528 528 // } 529 530 531 532 533 534 //flow.importer_referer = "" 535 536 537 538 539 529 530 //flow.importer_validatedsuccesfully = validatedSuccesfully 531 //flow.importer_failedtopersist = failedToPersist 532 //flow.imported_updatedentities = updatedEntities 533 //flow.importer_totalrows = flow.importer_importeddata.size 534 //flow.importer_referer = "" 535 536 return true 537 } 538 539 /** 540 540 * append errors of a particular object to a map 541 541 * @param object … … 545 545 def appendErrors(object, map) { 546 546 this.appendErrorMap(getHumanReadableErrors(object), map) 547 547 } 548 548 549 549 def appendErrors(object, map, prepend) { … … 551 551 } 552 552 553 553 /** 554 554 * append errors of one map to another map 555 555 * @param map linkedHashMap … … 559 559 def appendErrorMap(map, mapToExtend) { 560 560 map.each() {key, value -> 561 mapToExtend[key] = ['key': key, 'value': value, 'dynamic': false] 561 mapToExtend[key] = ['key': key, 'value': value, 'dynamic': false] 562 562 } 563 563 } … … 569 569 } 570 570 571 571 /** 572 572 * transform domain class validation errors into a human readable 573 573 * linked hash map … … 586 586 // validationTagLib instead so it is always 587 587 // available to us 588 errors[ error.getArguments()[0]] = validationTagLib.message(error: error)588 errors[error.getArguments()[0]] = validationTagLib.message(error: error) 589 589 } 590 590
Note: See TracChangeset
for help on using the changeset viewer.