Changeset 1233

Show
Ignore:
Timestamp:
02-12-10 18:03:36 (3 years ago)
Author:
work@…
Message:

- introduced deleteSample method to be sure a sample -and it's relations- are correctly deleted.
- hopefully this resolves #223

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • trunk/grails-app/domain/dbnp/studycapturing/Study.groovy

    r1222 r1233  
    1212 */ 
    1313class Study extends TemplateEntity { 
    14         static searchable = true 
     14        static searchable = true 
    1515 
    1616        SecUser owner           // The owner of the study. A new study is automatically owned by its creator. 
    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 
     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 
    1919        Date dateCreated 
    2020        Date lastUpdated 
     
    2727        List assays 
    2828        boolean published = false // Determines whether a study is private (only accessable by the owner and writers) or published (also visible to readers) 
    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 = [               
     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 = [ 
    3232                subjects: Subject, 
    3333                samplingEvents: SamplingEvent, 
     
    3838                persons: StudyPerson, 
    3939                publications: Publication, 
    40                 readers: SecUser, 
    41                 writers: SecUser 
     40                readers: SecUser, 
     41                writers: SecUser 
    4242        ] 
    4343 
    4444        static constraints = { 
    4545                owner(nullable: true, blank: true) 
    46                 code(nullable:false, blank:true,unique:true) 
     46                code(nullable: false, blank: true, unique: true) 
    4747 
    4848                // TODO: add custom validator for 'published' to assess whether the study meets all quality criteria for publication 
     
    6060        // The external identifier (studyToken) is currently the code of the study. 
    6161        // It is used from within dbNP submodules to refer to particular study in this GSCF instance. 
     62 
    6263        def getToken() { code } 
    6364 
     
    7677                        name: 'code', 
    7778                        type: TemplateFieldType.STRING, 
    78                         preferredIdentifier:true, 
     79                        preferredIdentifier: true, 
    7980                        comment: 'Fill out the code by which many people will recognize your study', 
    8081                        required: true), 
     
    102103         */ 
    103104        def List<Event> getOrphanEvents() { 
    104                 def orphans =   events.findAll { event -> !event.belongsToGroup(eventGroups) } + 
    105                                                 samplingEvents.findAll { event -> !event.belongsToGroup(eventGroups) } 
     105                def orphans = events.findAll { event -> !event.belongsToGroup(eventGroups) } + 
     106                        samplingEvents.findAll { event -> !event.belongsToGroup(eventGroups) } 
    106107 
    107108                return orphans 
     
    129130         */ 
    130131        List<Template> giveAllAssayTemplates() { 
    131                 TemplateEntity.giveTemplates(( (assays) ? assays : [] )) 
     132                TemplateEntity.giveTemplates(((assays) ? assays : [])) 
    132133        } 
    133134 
     
    147148                // gives trouble when asking .size() to the result 
    148149                // So we also use giveTemplates here 
    149                 TemplateEntity.giveTemplates( ((events) ? events : []) + ((samplingEvents) ? samplingEvents : []) ) 
    150         } 
    151  
     150                TemplateEntity.giveTemplates(((events) ? events : []) + ((samplingEvents) ? samplingEvents : [])) 
     151        } 
    152152 
    153153        /** 
     
    200200        } 
    201201 
    202  
    203202        /** 
    204203         * Delete a specific subject from this study, including all its relations 
    205204         * @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) { 
    211208                // Delete the subject from the event groups it was referenced in 
    212209                this.eventGroups.each { 
    213210                        if (it.subjects.contains(subject)) { 
    214211                                it.removeFromSubjects(subject) 
    215                                 msg += ", deleted from event group '${it.name}'" 
    216212                        } 
    217213                } 
     
    219215                // Delete the samples that have this subject as parent 
    220216                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) 
    226218                } 
    227219 
    228220                // This should remove the subject itself too, because of the cascading belongsTo relation 
    229221                this.removeFromSubjects(subject) 
     222 
    230223                // But apparently it needs an explicit delete() too 
    231224                subject.delete() 
    232  
    233                 return msg 
    234225        } 
    235226 
     
    257248         * Delete an event from the study, including all its relations 
    258249         * @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) { 
    264253                // remove event from the study 
    265254                this.removeFromEvents(event) 
     
    269258                        eventGroup.removeFromEvents(event) 
    270259                } 
    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() 
    273284        } 
    274285 
     
    276287         * Delete a samplingEvent from the study, including all its relations 
    277288         * @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) { 
    283292                // remove event from eventGroups 
    284293                this.eventGroups.each() { eventGroup -> 
     
    289298                this.samples.findAll { it.parentEvent.equals(samplingEvent) }.each { 
    290299                        // 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) 
    295301                } 
    296302 
     
    302308                // (Which can be verified by outcommenting this line, then SampleTests.testDeleteViaParentSamplingEvent fails 
    303309                samplingEvent.delete() 
    304  
    305                 return msg 
    306         } 
    307          
     310        } 
     311 
    308312        /** 
    309313         * Delete an eventGroup from the study, including all its relations 
    310314         * @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) { 
    316318                // If the event group contains sampling events 
    317319                if (eventGroup.samplingEvents) { 
     
    328330                                this.samples.findAll { sample -> 
    329331                                        ( 
    330                                                 (eventGroup.subjects.findAll { 
    331                                                         it.equals(sample.parentSubject) 
    332                                                 }) 
     332                                        (eventGroup.subjects.findAll { 
     333                                                it.equals(sample.parentSubject) 
     334                                        }) 
    333335                                                && 
    334336                                                (eventGroup.samplingEvents.findAll { 
    335337                                                        ( 
    336                                                                 (it.id && sample.parentEvent.id && it.id==sample.parentEvent.id) 
     338                                                        (it.id && sample.parentEvent.id && it.id == sample.parentEvent.id) 
    337339                                                                || 
    338340                                                                (it.getIdentifier() == sample.parentEvent.getIdentifier()) 
     
    344346                                }.each() { sample -> 
    345347                                        // 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) 
    371349                                } 
    372350                        } 
    373351 
    374352                        // remove all samplingEvents from this eventGroup 
    375                         eventGroup.samplingEvents.findAll{}.each() { 
     353                        eventGroup.samplingEvents.findAll {}.each() { 
    376354                                eventGroup.removeFromSamplingEvents(it) 
    377                                 println ".removed samplingEvent '${it.name}' from eventGroup '${eventGroup.name}'" 
    378                                 msg += ", samplingEvent '${it.name}' was removed from eventGroup '${eventGroup.name}'" 
    379355                        } 
    380356                } 
     
    383359                if (eventGroup.subjects) { 
    384360                        // remove all subject from this eventGroup 
    385                         eventGroup.subjects.findAll{}.each() { 
     361                        eventGroup.subjects.findAll {}.each() { 
    386362                                eventGroup.removeFromSubjects(it) 
    387                                 println ".removed subject '${it.name}' from eventGroup '${eventGroup.name}'" 
    388                                 msg += ", subject '${it.name}' was removed from eventGroup '${eventGroup.name}'" 
    389363                        } 
    390364                } 
    391365 
    392366                // remove the eventGroup from the study 
    393                 println ".remove eventGroup '${eventGroup.name}' from study '${this.title}'" 
    394367                this.removeFromEventGroups(eventGroup) 
    395368 
     
    397370                // otherwise cascaded deletes are not properly performed 
    398371                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                } 
    411382 
    412383                // Administrators are allowed to read every study 
    413                 if( loggedInUser.hasAdminRights() ) { 
     384                if (loggedInUser.hasAdminRights()) { 
    414385                        return true; 
    415386                } 
    416387 
    417         // Owners and writers are allowed to read this study 
    418         if( this.owner == loggedInUser || this.writers.contains(loggedInUser) ) { 
    419             return true 
    420         } 
    421              
    422         // Readers are allowed to read this study when it is published 
    423         if( this.readers.contains(loggedInUser) && this.published ) { 
    424             return true 
    425         } 
    426          
    427         return false 
    428     } 
    429  
    430     /** 
    431     * Returns true if the given user is allowed to write this study 
    432     */ 
    433     public boolean canWrite(SecUser loggedInUser) { 
    434         if( loggedInUser == null ) { 
    435             return false; 
    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                } 
    437408 
    438409                // Administrators are allowed to write every study 
    439                 if( loggedInUser.hasAdminRights() ) { 
     410                if (loggedInUser.hasAdminRights()) { 
    440411                        return true; 
    441412                } 
    442413 
    443         return this.owner == loggedInUser || this.writers.contains(loggedInUser) 
    444     } 
    445  
    446     /** 
    447     * Returns true if the given user is the owner of this study 
    448     */ 
    449     public boolean isOwner(SecUser loggedInUser) { 
    450         if( loggedInUser == null ) { 
    451             return false; 
    452         } 
    453         return this.owner == loggedInUser 
    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        } 
    455426 
    456427        /** 
     
    459430        public static giveWritableStudies(SecUser user, int max) { 
    460431                // User that are not logged in, are not allowed to write to a study 
    461                 if( user == null ) 
    462                         return []; 
    463                          
     432                if (user == null) 
     433                return []; 
     434 
    464435                def c = Study.createCriteria() 
    465436 
    466437                // Administrators are allowed to read everything 
    467                 if( user.hasAdminRights() ) { 
     438                if (user.hasAdminRights()) { 
    468439                        return c.list { 
    469440                                maxResults(max) 
     
    474445                        maxResults(max) 
    475446                        or { 
    476                                 eq( "owner", user ) 
     447                                eq("owner", user) 
    477448                                writers { 
    478                                         eq( "id", user.id ) 
     449                                        eq("id", user.id) 
    479450                                } 
    480451                        } 
     
    488459                def c = Study.createCriteria() 
    489460 
    490         // Administrators are allowed to read everything 
    491                 if( user == null ) { 
    492             return c.list { 
     461                // Administrators are allowed to read everything 
     462                if (user == null) { 
     463                        return c.list { 
    493464                                maxResults(max) 
    494                 and { 
    495                     eq( "published", true ) 
    496                     eq( "publicstudy", true ) 
    497                 } 
    498             } 
    499         } else if( user.hasAdminRights() ) { 
    500             return c.list { 
     465                                and { 
     466                                        eq("published", true) 
     467                                        eq("publicstudy", true) 
     468                                } 
     469                        } 
     470                } else if (user.hasAdminRights()) { 
     471                        return c.list { 
    501472                                maxResults(max) 
    502473                        } 
    503                 } else  { 
    504             return c.list { 
     474                } else { 
     475                        return c.list { 
    505476                                maxResults(max) 
    506                 or { 
    507                     eq( "owner", user ) 
    508                     writers { 
    509                         eq( "id", user.id ) 
    510                     } 
    511                     and { 
    512                         readers { 
    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                } 
    520491        } 
    521492}