Changeset 1233 for trunk/grails-app/domain
- Timestamp:
- Dec 2, 2010, 6:03:36 PM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/grails-app/domain/dbnp/studycapturing/Study.groovy
r1222 r1233 12 12 */ 13 13 class Study extends TemplateEntity { 14 14 static searchable = true 15 15 16 16 SecUser owner // The owner of the study. A new study is automatically owned by its creator. 17 String title 18 String code 17 String title // The title of the study 18 String code // currently used as the external study ID, e.g. to reference a study in a SAM module 19 19 Date dateCreated 20 20 Date lastUpdated … … 27 27 List assays 28 28 boolean published = false // Determines whether a study is private (only accessable by the owner and writers) or published (also visible to readers) 29 30 31 static hasMany = [ 29 boolean publicstudy = false // Determines whether anonymous users are allowed to see this study. This has only effect when published = true 30 31 static hasMany = [ 32 32 subjects: Subject, 33 33 samplingEvents: SamplingEvent, … … 38 38 persons: StudyPerson, 39 39 publications: Publication, 40 41 40 readers: SecUser, 41 writers: SecUser 42 42 ] 43 43 44 44 static constraints = { 45 45 owner(nullable: true, blank: true) 46 code(nullable: false, blank:true,unique:true)46 code(nullable: false, blank: true, unique: true) 47 47 48 48 // TODO: add custom validator for 'published' to assess whether the study meets all quality criteria for publication … … 60 60 // The external identifier (studyToken) is currently the code of the study. 61 61 // It is used from within dbNP submodules to refer to particular study in this GSCF instance. 62 62 63 def getToken() { code } 63 64 … … 76 77 name: 'code', 77 78 type: TemplateFieldType.STRING, 78 preferredIdentifier: true,79 preferredIdentifier: true, 79 80 comment: 'Fill out the code by which many people will recognize your study', 80 81 required: true), … … 102 103 */ 103 104 def List<Event> getOrphanEvents() { 104 def orphans = 105 105 def orphans = events.findAll { event -> !event.belongsToGroup(eventGroups) } + 106 samplingEvents.findAll { event -> !event.belongsToGroup(eventGroups) } 106 107 107 108 return orphans … … 129 130 */ 130 131 List<Template> giveAllAssayTemplates() { 131 TemplateEntity.giveTemplates(( (assays) ? assays : []))132 TemplateEntity.giveTemplates(((assays) ? assays : [])) 132 133 } 133 134 … … 147 148 // gives trouble when asking .size() to the result 148 149 // So we also use giveTemplates here 149 TemplateEntity.giveTemplates( ((events) ? events : []) + ((samplingEvents) ? samplingEvents : []) ) 150 } 151 150 TemplateEntity.giveTemplates(((events) ? events : []) + ((samplingEvents) ? samplingEvents : [])) 151 } 152 152 153 153 /** … … 200 200 } 201 201 202 203 202 /** 204 203 * Delete a specific subject from this study, including all its relations 205 204 * @param subject The subject to be deleted 206 * @return A String which contains a (user-readable) message describing the changes to the database 207 */ 208 String deleteSubject(Subject subject) { 209 String msg = "Subject ${subject.name} was deleted" 210 205 * @void 206 */ 207 void deleteSubject(Subject subject) { 211 208 // Delete the subject from the event groups it was referenced in 212 209 this.eventGroups.each { 213 210 if (it.subjects.contains(subject)) { 214 211 it.removeFromSubjects(subject) 215 msg += ", deleted from event group '${it.name}'"216 212 } 217 213 } … … 219 215 // Delete the samples that have this subject as parent 220 216 this.samples.findAll { it.parentSubject.equals(subject) }.each { 221 // This should remove the sample itself too, because of the cascading belongsTo relation 222 this.removeFromSamples(it) 223 // But apparently it needs an explicit delete() too 224 it.delete() 225 msg += ", sample '${it.name}' was deleted" 217 this.deleteSample(it) 226 218 } 227 219 228 220 // This should remove the subject itself too, because of the cascading belongsTo relation 229 221 this.removeFromSubjects(subject) 222 230 223 // But apparently it needs an explicit delete() too 231 224 subject.delete() 232 233 return msg234 225 } 235 226 … … 257 248 * Delete an event from the study, including all its relations 258 249 * @param Event 259 * @return String 260 */ 261 String deleteEvent(Event event) { 262 String msg = "Event ${event} was deleted" 263 250 * @void 251 */ 252 void deleteEvent(Event event) { 264 253 // remove event from the study 265 254 this.removeFromEvents(event) … … 269 258 eventGroup.removeFromEvents(event) 270 259 } 271 272 return msg 260 } 261 262 /** 263 * Delete a sample from the study, including all its relations 264 * @param Event 265 * @void 266 */ 267 void deleteSample(Sample sample) { 268 // remove the sample from the study 269 this.removeFromSamples(sample) 270 271 // remove the sample from any sampling events it belongs to 272 this.samplingEvents.findAll { it.samples.any { it == sample }}.each { 273 it.removeFromSamples(sample) 274 } 275 276 // remove the sample from any assays it belongs to 277 this.assays.findAll { it.samples.any { it == sample }}.each { 278 it.removeFromSamples(sample) 279 } 280 281 // Also here, contrary to documentation, an extra delete() is needed 282 // otherwise date is not properly deleted! 283 sample.delete() 273 284 } 274 285 … … 276 287 * Delete a samplingEvent from the study, including all its relations 277 288 * @param SamplingEvent 278 * @return String 279 */ 280 String deleteSamplingEvent(SamplingEvent samplingEvent) { 281 String msg = "SamplingEvent ${samplingEvent} was deleted" 282 289 * @void 290 */ 291 void deleteSamplingEvent(SamplingEvent samplingEvent) { 283 292 // remove event from eventGroups 284 293 this.eventGroups.each() { eventGroup -> … … 289 298 this.samples.findAll { it.parentEvent.equals(samplingEvent) }.each { 290 299 // This should remove the sample itself too, because of the cascading belongsTo relation 291 this.removeFromSamples(it) 292 // But apparently it needs an explicit delete() too 293 it.delete() 294 msg += ", sample '${it.name}' was deleted" 300 this.deleteSample(it) 295 301 } 296 302 … … 302 308 // (Which can be verified by outcommenting this line, then SampleTests.testDeleteViaParentSamplingEvent fails 303 309 samplingEvent.delete() 304 305 return msg 306 } 307 310 } 311 308 312 /** 309 313 * Delete an eventGroup from the study, including all its relations 310 314 * @param EventGroup 311 * @return String 312 */ 313 String deleteEventGroup(EventGroup eventGroup) { 314 String msg = "EventGroup ${eventGroup} was deleted" 315 315 * @void 316 */ 317 void deleteEventGroup(EventGroup eventGroup) { 316 318 // If the event group contains sampling events 317 319 if (eventGroup.samplingEvents) { … … 328 330 this.samples.findAll { sample -> 329 331 ( 330 331 332 332 (eventGroup.subjects.findAll { 333 it.equals(sample.parentSubject) 334 }) 333 335 && 334 336 (eventGroup.samplingEvents.findAll { 335 337 ( 336 (it.id && sample.parentEvent.id && it.id==sample.parentEvent.id)338 (it.id && sample.parentEvent.id && it.id == sample.parentEvent.id) 337 339 || 338 340 (it.getIdentifier() == sample.parentEvent.getIdentifier()) … … 344 346 }.each() { sample -> 345 347 // remove sample from study 346 347 // ------- 348 // NOTE, the right samples are found, but the don't 349 // get deleted from the database! 350 // ------- 351 352 println ".removing sample '${sample.name}' from study '${this.title}'" 353 msg += ", sample '${sample.name}' was deleted" 354 this.removeFromSamples( sample ) 355 356 // remove the sample from any sampling events it belongs to 357 this.samplingEvents.findAll { it.samples.any { it == sample }} .each { 358 println ".removed sample ${sample.name} from sampling event ${it} at ${it.getStartTimeString()}" 359 it.removeFromSamples(sample) 360 } 361 362 // remove the sample from any assays it belongs to 363 this.assays.findAll { it.samples.any { it == sample }} .each { 364 println ".removed sample ${sample.name} from assay ${it.name}" 365 it.removeFromSamples(sample) 366 } 367 368 // Also here, contrary to documentation, an extra delete() is needed 369 // otherwise date is not properly deleted! 370 sample.delete() 348 this.deleteSample(sample) 371 349 } 372 350 } 373 351 374 352 // remove all samplingEvents from this eventGroup 375 eventGroup.samplingEvents.findAll {}.each() {353 eventGroup.samplingEvents.findAll {}.each() { 376 354 eventGroup.removeFromSamplingEvents(it) 377 println ".removed samplingEvent '${it.name}' from eventGroup '${eventGroup.name}'"378 msg += ", samplingEvent '${it.name}' was removed from eventGroup '${eventGroup.name}'"379 355 } 380 356 } … … 383 359 if (eventGroup.subjects) { 384 360 // remove all subject from this eventGroup 385 eventGroup.subjects.findAll {}.each() {361 eventGroup.subjects.findAll {}.each() { 386 362 eventGroup.removeFromSubjects(it) 387 println ".removed subject '${it.name}' from eventGroup '${eventGroup.name}'"388 msg += ", subject '${it.name}' was removed from eventGroup '${eventGroup.name}'"389 363 } 390 364 } 391 365 392 366 // remove the eventGroup from the study 393 println ".remove eventGroup '${eventGroup.name}' from study '${this.title}'"394 367 this.removeFromEventGroups(eventGroup) 395 368 … … 397 370 // otherwise cascaded deletes are not properly performed 398 371 eventGroup.delete() 399 400 return msg 401 } 402 403 /** 404 * Returns true if the given user is allowed to read this study 405 */ 406 public boolean canRead(SecUser loggedInUser) { 407 // Anonymous readers are only given access when published and public 408 if( loggedInUser == null ) { 409 return this.publicstudy && this.published; 410 } 372 } 373 374 /** 375 * Returns true if the given user is allowed to read this study 376 */ 377 public boolean canRead(SecUser loggedInUser) { 378 // Anonymous readers are only given access when published and public 379 if (loggedInUser == null) { 380 return this.publicstudy && this.published; 381 } 411 382 412 383 // Administrators are allowed to read every study 413 if ( loggedInUser.hasAdminRights()) {384 if (loggedInUser.hasAdminRights()) { 414 385 return true; 415 386 } 416 387 417 418 if( this.owner == loggedInUser || this.writers.contains(loggedInUser)) {419 420 421 422 423 if( this.readers.contains(loggedInUser) && this.published) {424 425 426 427 428 429 430 431 432 433 434 if( loggedInUser == null) {435 436 388 // Owners and writers are allowed to read this study 389 if (this.owner == loggedInUser || this.writers.contains(loggedInUser)) { 390 return true 391 } 392 393 // Readers are allowed to read this study when it is published 394 if (this.readers.contains(loggedInUser) && this.published) { 395 return true 396 } 397 398 return false 399 } 400 401 /** 402 * Returns true if the given user is allowed to write this study 403 */ 404 public boolean canWrite(SecUser loggedInUser) { 405 if (loggedInUser == null) { 406 return false; 407 } 437 408 438 409 // Administrators are allowed to write every study 439 if ( loggedInUser.hasAdminRights()) {410 if (loggedInUser.hasAdminRights()) { 440 411 return true; 441 412 } 442 413 443 444 445 446 447 448 449 450 if( loggedInUser == null) {451 452 453 454 414 return this.owner == loggedInUser || this.writers.contains(loggedInUser) 415 } 416 417 /** 418 * Returns true if the given user is the owner of this study 419 */ 420 public boolean isOwner(SecUser loggedInUser) { 421 if (loggedInUser == null) { 422 return false; 423 } 424 return this.owner == loggedInUser 425 } 455 426 456 427 /** … … 459 430 public static giveWritableStudies(SecUser user, int max) { 460 431 // User that are not logged in, are not allowed to write to a study 461 if ( user == null)462 463 432 if (user == null) 433 return []; 434 464 435 def c = Study.createCriteria() 465 436 466 437 // Administrators are allowed to read everything 467 if ( user.hasAdminRights()) {438 if (user.hasAdminRights()) { 468 439 return c.list { 469 440 maxResults(max) … … 474 445 maxResults(max) 475 446 or { 476 eq( "owner", user)447 eq("owner", user) 477 448 writers { 478 eq( "id", user.id)449 eq("id", user.id) 479 450 } 480 451 } … … 488 459 def c = Study.createCriteria() 489 460 490 491 if ( user == null) {492 461 // Administrators are allowed to read everything 462 if (user == null) { 463 return c.list { 493 464 maxResults(max) 494 495 eq( "published", true)496 eq( "publicstudy", true)497 498 499 } else if( user.hasAdminRights()) {500 465 and { 466 eq("published", true) 467 eq("publicstudy", true) 468 } 469 } 470 } else if (user.hasAdminRights()) { 471 return c.list { 501 472 maxResults(max) 502 473 } 503 } else 504 474 } else { 475 return c.list { 505 476 maxResults(max) 506 507 eq( "owner", user)508 509 eq( "id", user.id)510 511 512 513 eq( "id", user.id)514 515 eq( "published", true)516 517 518 519 477 or { 478 eq("owner", user) 479 writers { 480 eq("id", user.id) 481 } 482 and { 483 readers { 484 eq("id", user.id) 485 } 486 eq("published", true) 487 } 488 } 489 } 490 } 520 491 } 521 492 }
Note: See TracChangeset
for help on using the changeset viewer.