root/trunk/grails-app/controllers/RestController.groovy @ 976

Revision 976, 10.0 KB (checked in by robert@…, 3 years ago)

Authentication and authorization for studies is added, according to ticket 118

  • Property svn:keywords set to Author Date Rev
Line 
1/**
2 * RestController
3 *
4 * This controler provides a REST service.
5 * The names of the RESET resources are the same as the names of this
6 * controller's actions. E.g., the resources called getStudies simply
7 * corresponds to the action getStudies. Some of the resources are parameterized.
8 * The parameters are passed as parameters in the url and are available in the
9 * params respecting Grails' conventions. In this file, we adher to the javadoc 
10 * convention for describing parameters ("@param"), but actually we mean
11 * key-value pairs in the params object of each Grails action we comment on.
12 *
13 * @author      Jahn-Takeshi Saito
14 * @since       20100601
15 *
16 */
17
18import dbnp.studycapturing.Study
19import dbnp.studycapturing.Assay
20import dbnp.authentication.SecUser
21import grails.converters.*
22import nl.metabolomicscentre.dsp.http.BasicAuthentication
23
24
25class RestController {
26
27       /**************************************************/
28      /** Rest resources for Simple Assay Module (SAM) **/
29     /**************************************************/
30
31        def AuthenticationService       
32        def beforeInterceptor = [action:this.&auth,except:["isUser"]]
33        def credentials
34        def requestUser // = SecUser.findByName( "user" )
35
36        /**
37         * Authorization closure, which is run before executing any of the REST resource actions
38         * It fetches a username/password combination from basic HTTP authentication and checks whether
39         * that is an active (SecuritySpring) account
40         * @return
41         */
42        private def auth() {
43            credentials = BasicAuthentication.credentialsFromRequest(request)           
44        requestUser = AuthenticationService.authenticateUser(credentials.u, credentials.p)
45               
46                if(!requestUser) {
47                    response.sendError(403)
48                return false
49            }
50                else {
51                        return true
52                }
53        }
54
55        /**
56        * REST resource for data modules.
57        * Username and password should be supplied via HTTP Basic Authentication.
58        * Determines whether the given user/password combination is a valid GSCF account.
59        *
60        * @return bool {"authenticated":true} when user/password is a valid GSCF account, {"authenticated":false} otherwise.
61        */
62        def isUser= {
63                boolean isUser
64                credentials = BasicAuthentication.credentialsFromRequest(request)
65                def reqUser = AuthenticationService.authenticateUser(credentials.u, credentials.p)
66                isUser = reqUser ? true : false
67                def reply = ['authenticated':isUser]
68                render reply as JSON
69        }
70
71
72        /**
73        * REST resource for data modules.
74        * Username and password should be supplied via HTTP Basic Authentication.
75        * Provide a list of all studies owned by the supplied user.
76        *
77        * @return JSON object list containing 'studyToken', and 'name' (title) for each study
78        */
79        def getStudies = {
80                List studies = []
81                def user = params.user
82                Study.findAllByOwner(requestUser).each { study ->
83                        studies.push( [ 'title':study.title, 'studyToken':study.getToken()] )
84                }
85                render studies as JSON
86        }
87
88
89        /**
90        * REST resource for data modules.
91        * Username and password should be supplied via HTTP Basic Authentication.
92        * Provide a list of all subjects belonging to a study.
93        *
94        * @param studyToken String The external study id (code) of the target GSCF Study object
95        * @return JSON object list of subject names
96        */
97        def getSubjects = {
98                List subjects = []
99                if( params.studyToken ) {
100                        def id = params.studyToken
101                        def study = Study.find( "from Study as s where s.code=?", [id])
102                        if(study) study.subjects.each { subjects.push it.name }
103                }
104                render subjects as JSON
105        }
106
107
108        /**
109        * REST resource for data modules.
110        * Username and password should be supplied via HTTP Basic Authentication.
111        * Provide a list of all assays for a given study
112        *
113        * Example call of the getAssays REST resource:
114        * http://localhost:8080/gscf/rest/getAssays?studyToken=PPSH&moduleURL=http://localhost:8182/sam
115        *
116        * @param stuyToken String The external study id (code) of the target GSCF Study object
117        * @param moduleURL String The base URL of the calling dbNP module
118        * @return list of assays in the study as JSON object list, filtered to only contain assays
119        *         for the specified module, with 'assayToken' and 'name' for each assay
120        */
121        def getAssays = {
122                List assays = []
123                if( params.studyToken ) {
124                        def id = params.studyToken
125                        def study = Study.find( "from Study as s where s.code=?", [id] )
126                        if(study && study.owner == requestUser) study.assays.each{ assay ->
127                                if (assay.module.url.equals(params.moduleURL)) {
128                                def map = ['name':assay.name, 'assayToken':assay.getToken()]
129                                        assays.push( map )
130                                }
131                        }
132                }
133                render assays as JSON
134        }
135
136
137        /**
138        * REST resource for data modules.
139        * Username and password should be supplied via HTTP Basic Authentication.
140        * Provide all samples of a given Assay. The result is an enriched list with additional information for each sample.
141        *
142        * @param assayToken String (assayToken of some Assay in GSCF)
143        * @return As a JSON object list, for each sample in that assay:
144        * @return 'name' (Sample name, which is unique)
145        * @return 'material' (Sample material)
146        * @return 'subject' (The name of the subject from which the sample was taken)
147        * @return 'event' (the name of the template of the SamplingEvent describing the sampling)
148        * @return 'startTime' (the time the sample was taken relative to the start of the study, as a string)
149        */
150        def getSamples = {
151                def items = []
152                if( params.assayToken ) {
153                        def assay = Assay.find( "from Assay as a where externalAssayID=?",[params.assayToken])
154                        if( assay )  {
155                                assay.getSamples().each { sample ->
156                                        def item = [
157                                                'sampleToken' : sample.name,
158                                                'material'        : sample.material?.name,
159                                                'subject'         : sample.parentSubject?.name,
160                                                'event'           : sample.parentEvent?.template?.name,
161                                                'startTime'       : sample.parentEvent?.getStartTimeString()
162                                        ]
163                                        items.push item
164                                }
165                        }
166                }
167                render items as JSON
168        }
169
170
171        /**
172        * REST resource for dbNP modules.
173        *
174        * @param studyToken String, the external identifier of the study
175        * @return List of all fields of this study
176        * @return
177        *
178        * Example REST call (without authentication):
179    * http://localhost:8080/gscf/rest/getStudy/study?studyToken=PPSH
180    *
181        * Returns the JSON object:
182        * {"title":"NuGO PPS human study","studyToken":"PPSH","startDate":"2008-01-13T23:00:00Z",
183        * "Description":"Human study performed at RRI; centres involved: RRI, IFR, TUM, Maastricht U.",
184        * "Objectives":null,"Consortium":null,"Cohort name":null,"Lab id":null,"Institute":null,
185        * "Study protocol":null}
186        */
187        def getStudy = {
188                def items = [:]
189                if( params.studyToken ) {
190                        def study = Study.find( "from Study as s where code=?",[params.studyToken])
191                        if(study) {
192                                study.giveFields().each { field ->
193                                        def name = field.name
194                                        def value = study.getFieldValue( name )
195                                        items[name] = value
196                                }
197                        }
198        }
199                render items as JSON
200        }
201
202
203
204        /**
205        * REST resource for dbNP modules.
206        *
207        * @param assayToken String, the external identifier of the study
208        * @return List of all fields of this assay
209        *
210        * Example REST call (without authentication):
211    * http://localhost:8080/gscf/rest/getAssay/assay?assayToken=PPS3_SAM
212    *
213        * Returns the JSON object: {"name":"Lipid profiling","module":{"class":"dbnp.studycapturing.AssayModule","id":1,
214        * "name":"SAM module for clinical data","platform":"clinical measurements","url":"http://sam.nmcdsp.org"},
215        * "assayToken":"PPS3_SAM","parentStudyToken":"PPS","Description":null}
216        */
217        def getAssay = {
218                def items = [:]
219                if( params.assayToken ) {
220                        def assay = Assay.find( "from Assay as a where externalAssayID=?",[params.assayToken])
221                        if(assay) {
222                                assay.giveFields().each { field ->
223                                        def name = field.name
224                                        def value = assay.getFieldValue( name )
225                                        items[name] = value
226                                }
227                                items["parentStudyToken"] = assay.parent.getToken()
228                        }
229        }
230                render items as JSON
231        }
232
233
234
235        /**
236        * REST resource for data modules.
237        * Username and password should be supplied via HTTP Basic Authentication.
238        * One specific sample of a given Assay.
239        *
240        * @param assayToken String (id of some Assay in GSCF)
241        * @return As a JSON object list, for each sample in that assay:
242        * @return 'name' (Sample name, which is unique)
243        * @return 'material' (Sample material)
244        * @return 'subject' (The name of the subject from which the sample was taken)
245        * @return 'event' (the name of the template of the SamplingEvent describing the sampling)
246        * @return 'startTime' (the time the sample was taken relative to the start of the study, as a string)
247        *
248        * Example REST call (without authentication):
249    * http://localhost:8080/gscf/rest/getSample/sam?assayToken=PPS3_SAM&sampleToken=A30_B
250    *
251        * Returns the JSON object:
252        * {"subject":"A30","event":"Liver extraction","startTime":"1 week, 1 hour",
253        * "sampleToken":"A30_B","material":{"class":"dbnp.data.Term","id":6,"accession":"BTO:0000131",
254        * "name":"blood plasma","ontology":{"class":"Ontology","id":2}},"Remarks":null,
255        * "Text on vial":"T70.91709057820039","Sample measured volume":null}
256        */
257        def getSample = {
258                def items = [:]
259                if( params.assayToken && params.sampleToken ) {
260                        def assay = Assay.find( "from Assay as a where externalAssayID=?",[params.assayToken])
261                        if(assay) {
262                                assay.getSamples().each { sample ->
263                                        if( sample.name == params.sampleToken ) {
264                                                        items = [
265                                                        'subject'             : sample.parentSubject.name,
266                                                        'event'               : sample.parentEvent.template.name,
267                                                        'startTime'           : sample.parentEvent.getStartTimeString()
268                                                        ]
269                                                        sample.giveFields().each { field ->
270                                                        def name = field.name
271                                                        def value = sample.getFieldValue( name )
272                                                        items[name] = value
273                                }
274                                        }
275                                }
276                        }
277                }
278                render items as JSON
279        }
280
281        def getAuthorizationLevel = {
282                // in future the users authorization level will be based on authorization model         
283                if( params.studyToken ) {
284                        def id = params.studyToken
285                        def study = Study.find( "from Study as s where s.code=?", [id])
286                        if(study) study.subjects.each { subjects.push it.name }
287                }
288
289                def perm = study.getPermissions(requestUser)
290               
291                render ('isOwner': study.isOwner(requestUser),
292                        'create': perm.create, 'read':perm.read,
293                        'update': perm.update, 'delete':perm.delete
294                        ) as JSON
295    }
296}
Note: See TracBrowser for help on using the browser.