Mercurial > hg > AnnotationManagerN4J
annotate src/main/java/de/mpiwg/itgroup/annotations/restlet/AnnotatorAnnotations.java @ 105:7417f5915181 default tip
check admin permission before changing permissions.
Enum for typesafe actions.
author | casties |
---|---|
date | Fri, 10 Feb 2017 15:45:35 +0100 |
parents | 9140017e8962 |
children |
rev | line source |
---|---|
3 | 1 package de.mpiwg.itgroup.annotations.restlet; |
2 | |
70 | 3 /* |
4 * #%L | |
5 * AnnotationManager | |
6 * %% | |
7 * Copyright (C) 2012 - 2014 MPIWG Berlin | |
8 * %% | |
9 * This program is free software: you can redistribute it and/or modify | |
10 * it under the terms of the GNU Lesser General Public License as | |
11 * published by the Free Software Foundation, either version 3 of the | |
12 * License, or (at your option) any later version. | |
13 * | |
14 * This program is distributed in the hope that it will be useful, | |
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 * GNU General Lesser Public License for more details. | |
18 * | |
19 * You should have received a copy of the GNU General Lesser Public | |
20 * License along with this program. If not, see | |
21 * <http://www.gnu.org/licenses/lgpl-3.0.html>. | |
22 * #L% | |
23 */ | |
24 | |
3 | 25 import java.io.IOException; |
65 | 26 import java.io.UnsupportedEncodingException; |
27 import java.net.URLDecoder; | |
31 | 28 import java.util.ArrayList; |
29 import java.util.List; | |
3 | 30 |
31 | 31 import org.json.JSONArray; |
3 | 32 import org.json.JSONException; |
33 import org.json.JSONObject; | |
31 | 34 import org.restlet.data.Form; |
3 | 35 import org.restlet.data.Status; |
36 import org.restlet.ext.json.JsonRepresentation; | |
37 import org.restlet.representation.Representation; | |
38 import org.restlet.resource.Delete; | |
39 import org.restlet.resource.Get; | |
40 import org.restlet.resource.Post; | |
41 import org.restlet.resource.Put; | |
42 | |
4 | 43 import de.mpiwg.itgroup.annotations.Annotation; |
105
7417f5915181
check admin permission before changing permissions.
casties
parents:
102
diff
changeset
|
44 import de.mpiwg.itgroup.annotations.Annotation.Action; |
15 | 45 import de.mpiwg.itgroup.annotations.Person; |
4 | 46 import de.mpiwg.itgroup.annotations.neo4j.AnnotationStore; |
31 | 47 import de.mpiwg.itgroup.annotations.restlet.utils.JSONObjectComparator; |
3 | 48 |
49 /** | |
4 | 50 * Implements the "annotations" uri of the Annotator API. see |
51 * <https://github.com/okfn/annotator/wiki/Storage> | |
3 | 52 * |
53 * @author dwinter, casties | |
54 * | |
55 */ | |
56 public class AnnotatorAnnotations extends AnnotatorResourceImpl { | |
57 | |
58 /** | |
59 * GET with JSON content-type. | |
60 * | |
61 * @param entity | |
62 * @return | |
63 */ | |
64 @Get("json") | |
65 public Representation doGetJSON(Representation entity) { | |
75 | 66 logger.fine("AnnotatorAnnotations doGetJSON!"); |
3 | 67 // id from URI /annotations/{id} |
65 | 68 String id = null; |
3 | 69 String jsonId = (String) getRequest().getAttributes().get("id"); |
65 | 70 if (jsonId != null) { |
71 // URL decode | |
72 try { | |
73 jsonId = URLDecoder.decode(jsonId, "UTF-8"); | |
74 } catch (UnsupportedEncodingException e) { | |
75 // this shouldn't happen | |
76 } | |
77 id = decodeJsonId(jsonId); | |
75 | 78 logger.fine("annotation-id=" + id); |
65 | 79 } |
3 | 80 |
14
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
4
diff
changeset
|
81 // do authentication |
88 | 82 Person authUser = getUserFromAuthToken(entity); |
75 | 83 logger.fine("request authenticated=" + authUser); |
3 | 84 |
37 | 85 if (id == null) { |
63
9f8c9611848a
fixed bug with new rectangle shapes. added limit, offset and sortBy parameters to annotator/ and annotator/search.
casties
parents:
61
diff
changeset
|
86 // no id -- send all annotations |
9f8c9611848a
fixed bug with new rectangle shapes. added limit, offset and sortBy parameters to annotator/ and annotator/search.
casties
parents:
61
diff
changeset
|
87 Form form = getRequest().getResourceRef().getQueryAsForm(); |
101 | 88 int limit = getInt(form.getFirstValue("limit", "1000")); |
89 int offset = getInt(form.getFirstValue("offset", "0")); | |
63
9f8c9611848a
fixed bug with new rectangle shapes. added limit, offset and sortBy parameters to annotator/ and annotator/search.
casties
parents:
61
diff
changeset
|
90 String sortBy = form.getFirstValue("sortBy"); |
9f8c9611848a
fixed bug with new rectangle shapes. added limit, offset and sortBy parameters to annotator/ and annotator/search.
casties
parents:
61
diff
changeset
|
91 return getAllAnnotations(authUser, limit, offset, sortBy); |
37 | 92 } |
93 | |
63
9f8c9611848a
fixed bug with new rectangle shapes. added limit, offset and sortBy parameters to annotator/ and annotator/search.
casties
parents:
61
diff
changeset
|
94 // send annotation with id |
16 | 95 AnnotationStore store = getAnnotationStore(); |
96 Annotation annot = store.getAnnotationById(id); | |
14
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
4
diff
changeset
|
97 if (annot != null) { |
105
7417f5915181
check admin permission before changing permissions.
casties
parents:
102
diff
changeset
|
98 if (!annot.isActionAllowed(Action.read, authUser, store)) { |
14
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
4
diff
changeset
|
99 setStatus(Status.CLIENT_ERROR_FORBIDDEN, "Not Authorized!"); |
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
4
diff
changeset
|
100 return null; |
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
4
diff
changeset
|
101 } |
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
4
diff
changeset
|
102 JSONObject result = createAnnotatorJson(annot, (authUser == null)); |
4 | 103 return new JsonRepresentation(result); |
104 } else { | |
14
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
4
diff
changeset
|
105 // not found |
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
4
diff
changeset
|
106 setStatus(Status.CLIENT_ERROR_NOT_FOUND); |
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
4
diff
changeset
|
107 return null; |
3 | 108 } |
109 } | |
110 | |
63
9f8c9611848a
fixed bug with new rectangle shapes. added limit, offset and sortBy parameters to annotator/ and annotator/search.
casties
parents:
61
diff
changeset
|
111 private Representation getAllAnnotations(Person authUser, int limit, int offset, String sortBy) { |
31 | 112 AnnotationStore store = getAnnotationStore(); |
113 ArrayList<JSONObject> results = new ArrayList<JSONObject>(); | |
65 | 114 |
63
9f8c9611848a
fixed bug with new rectangle shapes. added limit, offset and sortBy parameters to annotator/ and annotator/search.
casties
parents:
61
diff
changeset
|
115 // read all annotations |
101 | 116 List<Annotation> annotations = store.getAnnotations(null, null, 0, 0); |
31 | 117 for (Annotation annotation : annotations) { |
61 | 118 // check permission |
105
7417f5915181
check admin permission before changing permissions.
casties
parents:
102
diff
changeset
|
119 if (!annotation.isActionAllowed(Action.read, authUser, store)) |
65 | 120 continue; |
63
9f8c9611848a
fixed bug with new rectangle shapes. added limit, offset and sortBy parameters to annotator/ and annotator/search.
casties
parents:
61
diff
changeset
|
121 // add annotation to list |
61 | 122 JSONObject jo = createAnnotatorJson(annotation, false); |
123 results.add(jo); | |
124 } | |
125 | |
63
9f8c9611848a
fixed bug with new rectangle shapes. added limit, offset and sortBy parameters to annotator/ and annotator/search.
casties
parents:
61
diff
changeset
|
126 // sort if necessary |
61 | 127 if (sortBy != null) { |
128 JSONObjectComparator.sortAnnotations(results, sortBy); | |
129 } | |
65 | 130 |
63
9f8c9611848a
fixed bug with new rectangle shapes. added limit, offset and sortBy parameters to annotator/ and annotator/search.
casties
parents:
61
diff
changeset
|
131 // put in JSON list |
9f8c9611848a
fixed bug with new rectangle shapes. added limit, offset and sortBy parameters to annotator/ and annotator/search.
casties
parents:
61
diff
changeset
|
132 JSONArray rows = new JSONArray(); |
9f8c9611848a
fixed bug with new rectangle shapes. added limit, offset and sortBy parameters to annotator/ and annotator/search.
casties
parents:
61
diff
changeset
|
133 int cnt = 0; |
101 | 134 int max = limit + offset; |
61 | 135 for (JSONObject result : results) { |
63
9f8c9611848a
fixed bug with new rectangle shapes. added limit, offset and sortBy parameters to annotator/ and annotator/search.
casties
parents:
61
diff
changeset
|
136 cnt += 1; |
101 | 137 if (cnt < offset) continue; |
63
9f8c9611848a
fixed bug with new rectangle shapes. added limit, offset and sortBy parameters to annotator/ and annotator/search.
casties
parents:
61
diff
changeset
|
138 rows.put(result); |
101 | 139 if (limit > 0 && cnt >= max) break; |
61 | 140 } |
141 | |
31 | 142 // assemble result object |
143 JSONObject result = new JSONObject(); | |
144 try { | |
63
9f8c9611848a
fixed bug with new rectangle shapes. added limit, offset and sortBy parameters to annotator/ and annotator/search.
casties
parents:
61
diff
changeset
|
145 result.put("rows", rows); |
9f8c9611848a
fixed bug with new rectangle shapes. added limit, offset and sortBy parameters to annotator/ and annotator/search.
casties
parents:
61
diff
changeset
|
146 result.put("total", rows.length()); |
31 | 147 } catch (JSONException e) { |
148 setStatus(Status.SERVER_ERROR_INTERNAL, "JSON Error"); | |
149 return null; | |
150 } | |
151 return new JsonRepresentation(result); | |
152 } | |
153 | |
61 | 154 /** |
20
715aa11d138b
fixes in permission handling: admin and delete default to creator.
casties
parents:
16
diff
changeset
|
155 * POST with JSON content-type. Creates a new Annotation. |
3 | 156 * |
157 * @return | |
158 */ | |
159 @Post("json") | |
160 public Representation doPostJson(Representation entity) { | |
75 | 161 logger.fine("AnnotatorAnnotations doPostJSON!"); |
61 | 162 |
163 // do authentication TODO: who's allowed to create? | |
88 | 164 Person authUser = getUserFromAuthToken(entity); |
75 | 165 logger.fine("request authenticated=" + authUser); |
14
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
4
diff
changeset
|
166 if (authUser == null) { |
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
4
diff
changeset
|
167 setStatus(Status.CLIENT_ERROR_FORBIDDEN, "Not Authorized!"); |
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
4
diff
changeset
|
168 return null; |
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
4
diff
changeset
|
169 } |
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
4
diff
changeset
|
170 |
3 | 171 Annotation annot = null; |
172 try { | |
173 JsonRepresentation jrep = new JsonRepresentation(entity); | |
174 JSONObject jo = jrep.getJsonObject(); | |
175 if (jo == null) { | |
176 setStatus(Status.SERVER_ERROR_INTERNAL); | |
177 return null; | |
178 } | |
179 // make sure id is not set for POST | |
180 jo.remove("id"); | |
88 | 181 // create Annotation object from posted JSON |
3 | 182 annot = createAnnotation(jo, entity); |
102
9140017e8962
fix bug with empty username. add logging for JSON exceptions.
casties
parents:
101
diff
changeset
|
183 } catch (IOException e) { |
9140017e8962
fix bug with empty username. add logging for JSON exceptions.
casties
parents:
101
diff
changeset
|
184 logger.warning(e.toString()); |
3 | 185 setStatus(Status.SERVER_ERROR_INTERNAL); |
186 return null; | |
187 } catch (JSONException e) { | |
102
9140017e8962
fix bug with empty username. add logging for JSON exceptions.
casties
parents:
101
diff
changeset
|
188 logger.warning(e.toString()); |
3 | 189 setStatus(Status.CLIENT_ERROR_BAD_REQUEST); |
190 return null; | |
191 } | |
4 | 192 if (annot == null) { |
3 | 193 setStatus(Status.CLIENT_ERROR_BAD_REQUEST); |
194 return null; | |
195 } | |
196 Annotation storedAnnot; | |
4 | 197 // store Annotation |
198 storedAnnot = getAnnotationStore().storeAnnotation(annot); | |
199 /* | |
200 * according to https://github.com/okfn/annotator/wiki/Storage we should | |
201 * return 303: see other. For now we return the annotation. | |
3 | 202 */ |
14
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
4
diff
changeset
|
203 JSONObject jo = createAnnotatorJson(storedAnnot, (authUser == null)); |
3 | 204 JsonRepresentation retRep = new JsonRepresentation(jo); |
205 return retRep; | |
206 } | |
207 | |
208 /** | |
20
715aa11d138b
fixes in permission handling: admin and delete default to creator.
casties
parents:
16
diff
changeset
|
209 * PUT with JSON content-type. Modifies an Annotation. |
3 | 210 * |
211 * @param entity | |
212 * @return | |
213 */ | |
214 @Put("json") | |
215 public Representation doPutJSON(Representation entity) { | |
75 | 216 logger.fine("AnnotatorAnnotations doPutJSON!"); |
3 | 217 // id from URI /annotations/{id} |
218 String jsonId = (String) getRequest().getAttributes().get("id"); | |
219 String id = decodeJsonId(jsonId); | |
75 | 220 logger.fine("annotation-id=" + id); |
3 | 221 |
14
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
4
diff
changeset
|
222 // do authentication |
88 | 223 Person authUser = getUserFromAuthToken(entity); |
75 | 224 logger.fine("request authenticated=" + authUser); |
3 | 225 |
226 Annotation annot = null; | |
4 | 227 AnnotationStore store = getAnnotationStore(); |
3 | 228 try { |
229 JsonRepresentation jrep = new JsonRepresentation(entity); | |
230 JSONObject jo = jrep.getJsonObject(); | |
231 if (jo == null) { | |
232 setStatus(Status.CLIENT_ERROR_BAD_REQUEST); | |
233 return null; | |
234 } | |
235 // get stored Annotation | |
4 | 236 Annotation storedAnnot = store.getAnnotationById(id); |
237 if (storedAnnot == null) { | |
3 | 238 setStatus(Status.CLIENT_ERROR_NOT_FOUND); |
239 return null; | |
240 } | |
105
7417f5915181
check admin permission before changing permissions.
casties
parents:
102
diff
changeset
|
241 if (!storedAnnot.isActionAllowed(Action.update, authUser, store)) { |
14
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
4
diff
changeset
|
242 setStatus(Status.CLIENT_ERROR_FORBIDDEN); |
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
4
diff
changeset
|
243 return null; |
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
4
diff
changeset
|
244 } |
3 | 245 // update from posted JSON |
246 annot = updateAnnotation(storedAnnot, jo, entity); | |
247 // store Annotation | |
4 | 248 storedAnnot = store.storeAnnotation(annot); |
249 /* | |
250 * according to https://github.com/okfn/annotator/wiki/Storage we | |
251 * should return 303: see other. but the client doesn't like it | |
252 * setStatus(Status.REDIRECTION_SEE_OTHER); // go to same URL as | |
253 * this one Reference thisUrl = this.getReference(); | |
254 * this.getResponse().setLocationRef(thisUrl); | |
255 */ | |
3 | 256 // return new annotation |
14
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
4
diff
changeset
|
257 jo = createAnnotatorJson(storedAnnot, (authUser == null)); |
3 | 258 JsonRepresentation retRep = new JsonRepresentation(jo); |
259 return retRep; | |
260 } catch (JSONException e) { | |
75 | 261 logger.severe("Error in doPutJSON: "+e); |
3 | 262 setStatus(Status.CLIENT_ERROR_BAD_REQUEST); |
263 } catch (IOException e) { | |
75 | 264 logger.severe("Error in doPutJSON: "+e); |
3 | 265 setStatus(Status.SERVER_ERROR_INTERNAL, "Other Error"); |
266 } | |
267 return null; | |
268 } | |
269 | |
270 /** | |
20
715aa11d138b
fixes in permission handling: admin and delete default to creator.
casties
parents:
16
diff
changeset
|
271 * DELETE with JSON content-type. Deletes an Annotation. |
3 | 272 * |
273 * @param entity | |
274 * @return | |
275 */ | |
276 @Delete("json") | |
277 public Representation doDeleteJSON(Representation entity) { | |
75 | 278 logger.fine("AnnotatorAnnotations doDeleteJSON!"); |
3 | 279 // id from URI /annotations/{id} |
280 String jsonId = (String) getRequest().getAttributes().get("id"); | |
281 String id = decodeJsonId(jsonId); | |
75 | 282 logger.fine("annotation-id=" + id); |
3 | 283 |
14
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
4
diff
changeset
|
284 // do authentication |
88 | 285 Person authUser = getUserFromAuthToken(entity); |
75 | 286 logger.fine("request authenticated=" + authUser); |
16 | 287 AnnotationStore store = getAnnotationStore(); |
288 Annotation annot = store.getAnnotationById(id); | |
14
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
4
diff
changeset
|
289 if (annot != null) { |
105
7417f5915181
check admin permission before changing permissions.
casties
parents:
102
diff
changeset
|
290 if (!annot.isActionAllowed(Action.delete, authUser, store)) { |
14
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
4
diff
changeset
|
291 setStatus(Status.CLIENT_ERROR_FORBIDDEN, "Not Authorized!"); |
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
4
diff
changeset
|
292 return null; |
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
4
diff
changeset
|
293 } |
3 | 294 } |
4 | 295 // delete annotation |
32
0731c4549065
UI for editing groups and persons works now. (still no authorisation!)
casties
parents:
22
diff
changeset
|
296 store.deleteAnnotationById(id); |
4 | 297 setStatus(Status.SUCCESS_NO_CONTENT); |
3 | 298 return null; |
299 } | |
300 | |
301 } |