1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package eu.ehri.extension;
21
22 import com.google.common.collect.Sets;
23 import eu.ehri.extension.base.AbstractAccessibleResource;
24 import eu.ehri.extension.base.AbstractResource;
25 import eu.ehri.extension.base.DeleteResource;
26 import eu.ehri.extension.base.GetResource;
27 import eu.ehri.extension.base.ListResource;
28 import eu.ehri.extension.base.UpdateResource;
29 import eu.ehri.project.api.Api;
30 import eu.ehri.project.api.EventsApi;
31 import eu.ehri.project.api.UserProfilesApi;
32 import eu.ehri.project.core.Tx;
33 import eu.ehri.project.definitions.Entities;
34 import eu.ehri.project.exceptions.DeserializationError;
35 import eu.ehri.project.exceptions.ItemNotFound;
36 import eu.ehri.project.exceptions.PermissionDenied;
37 import eu.ehri.project.exceptions.ValidationError;
38 import eu.ehri.project.models.Annotation;
39 import eu.ehri.project.models.Group;
40 import eu.ehri.project.models.Link;
41 import eu.ehri.project.models.UserProfile;
42 import eu.ehri.project.models.VirtualUnit;
43 import eu.ehri.project.models.base.Watchable;
44 import eu.ehri.project.persistence.Bundle;
45 import org.neo4j.graphdb.GraphDatabaseService;
46
47 import javax.ws.rs.Consumes;
48 import javax.ws.rs.DELETE;
49 import javax.ws.rs.DefaultValue;
50 import javax.ws.rs.GET;
51 import javax.ws.rs.POST;
52 import javax.ws.rs.PUT;
53 import javax.ws.rs.Path;
54 import javax.ws.rs.PathParam;
55 import javax.ws.rs.Produces;
56 import javax.ws.rs.QueryParam;
57 import javax.ws.rs.core.Context;
58 import javax.ws.rs.core.MediaType;
59 import javax.ws.rs.core.Response;
60 import java.util.List;
61 import java.util.Set;
62
63
64
65
66 @Path(AbstractResource.RESOURCE_ENDPOINT_PREFIX + "/" + Entities.USER_PROFILE)
67 public class UserProfileResource extends AbstractAccessibleResource<UserProfile>
68 implements GetResource, ListResource, UpdateResource, DeleteResource {
69
70
71 public UserProfileResource(@Context GraphDatabaseService database) {
72 super(database, UserProfile.class);
73 }
74
75 @GET
76 @Produces(MediaType.APPLICATION_JSON)
77 @Path("{id:[^/]+}")
78 @Override
79 public Response get(@PathParam("id") String id) throws ItemNotFound {
80 return getItem(id);
81 }
82
83 @GET
84 @Produces(MediaType.APPLICATION_JSON)
85 @Override
86 public Response list() {
87 return listItems();
88 }
89
90 @POST
91 @Consumes(MediaType.APPLICATION_JSON)
92 @Produces(MediaType.APPLICATION_JSON)
93 public Response createUserProfile(Bundle bundle,
94 @QueryParam(GROUP_PARAM) List<String> groupIds,
95 @QueryParam(ACCESSOR_PARAM) List<String> accessors) throws PermissionDenied,
96 ValidationError, DeserializationError,
97 ItemNotFound {
98 try (final Tx tx = beginTx()) {
99 final Api.Acl acl = api().acl();
100 final Set<Group> groups = Sets.newHashSet();
101 for (String groupId : groupIds) {
102 groups.add(manager.getEntity(groupId, Group.class));
103 }
104 Response item = createItem(bundle, accessors, userProfile -> {
105 for (Group group : groups) {
106 acl.addAccessorToGroup(group, userProfile);
107 }
108 });
109 tx.success();
110 return item;
111 } catch (ItemNotFound e) {
112 throw new DeserializationError("User or group given as accessor not found: " + e.getValue());
113 }
114 }
115
116 @PUT
117 @Consumes(MediaType.APPLICATION_JSON)
118 @Produces(MediaType.APPLICATION_JSON)
119 @Path("{id:[^/]+}")
120 @Override
121 public Response update(@PathParam("id") String id, Bundle bundle)
122 throws PermissionDenied, ValidationError,
123 DeserializationError, ItemNotFound {
124 try (final Tx tx = beginTx()) {
125 Response item = updateItem(id, bundle);
126 tx.success();
127 return item;
128 }
129 }
130
131 @DELETE
132 @Path("{id:[^/]+}")
133 @Override
134 public void delete(@PathParam("id") String id)
135 throws PermissionDenied, ItemNotFound, ValidationError {
136 try (final Tx tx = beginTx()) {
137 deleteItem(id);
138 tx.success();
139 }
140 }
141
142 @GET
143 @Produces(MediaType.APPLICATION_JSON)
144 @Path("{id:[^/]+}/followers")
145 public Response listFollowers(@PathParam("id") String userId) throws ItemNotFound {
146 try (final Tx tx = beginTx()) {
147 UserProfile user = api().detail(userId, cls);
148 Response response = streamingPage(() -> getQuery()
149 .page(user.getFollowers(), UserProfile.class));
150 tx.success();
151 return response;
152 }
153 }
154
155 @GET
156 @Produces(MediaType.APPLICATION_JSON)
157 @Path("{id:[^/]+}/following")
158 public Response listFollowing(@PathParam("id") String userId) throws ItemNotFound {
159 try (final Tx tx = beginTx()) {
160 UserProfile user = api().detail(userId, cls);
161 Response response = streamingPage(() -> getQuery()
162 .page(user.getFollowing(), UserProfile.class));
163 tx.success();
164 return response;
165 }
166 }
167
168 @GET
169 @Produces(MediaType.APPLICATION_JSON)
170 @Path("{id:[^/]+}/is-following/{otherId:[^/]+}")
171 public boolean isFollowing(
172 @PathParam("id") String userId,
173 @PathParam("otherId") String otherId)
174 throws PermissionDenied, ItemNotFound {
175 try (final Tx tx = beginTx()) {
176 UserProfile user = api().detail(userId, cls);
177 boolean following = user.isFollowing(
178 manager.getEntity(otherId, UserProfile.class));
179 tx.success();
180 return following;
181 }
182 }
183
184 @GET
185 @Produces(MediaType.APPLICATION_JSON)
186 @Path("{id:[^/]+}/is-follower/{otherId:[^/]+}")
187 public boolean isFollower(
188 @PathParam("id") String userId,
189 @PathParam("otherId") String otherId)
190 throws PermissionDenied, ItemNotFound {
191 try (final Tx tx = beginTx()) {
192 UserProfile user = api().detail(userId, cls);
193 boolean follower = user.isFollower(manager.getEntity(otherId, UserProfile.class));
194 tx.success();
195 return follower;
196 }
197 }
198
199 @POST
200 @Path("{id:[^/]+}/following")
201 public void followUserProfile(
202 @PathParam("id") String userId,
203 @QueryParam(ID_PARAM) List<String> otherIds)
204 throws PermissionDenied, ItemNotFound {
205 try (final Tx tx = beginTx()) {
206 userProfilesApi().addFollowers(userId, otherIds);
207 tx.success();
208 }
209 }
210
211 @DELETE
212 @Path("{id:[^/]+}/following")
213 public void unfollowUserProfile(
214 @PathParam("id") String userId,
215 @QueryParam(ID_PARAM) List<String> otherIds)
216 throws PermissionDenied, ItemNotFound {
217 try (final Tx tx = beginTx()) {
218 userProfilesApi().removeFollowers(userId, otherIds);
219 tx.success();
220 }
221 }
222
223 @GET
224 @Produces(MediaType.APPLICATION_JSON)
225 @Path("{id:[^/]+}/blocked")
226 public Response listBlocked(@PathParam("id") String userId) throws ItemNotFound {
227 try (final Tx tx = beginTx()) {
228 UserProfile user = api().detail(userId, cls);
229 Response response = streamingPage(() -> getQuery()
230 .page(user.getBlocked(), UserProfile.class));
231 tx.success();
232 return response;
233 }
234 }
235
236 @GET
237 @Produces(MediaType.APPLICATION_JSON)
238 @Path("{id:[^/]+}/is-blocking/{otherId:[^/]+}")
239 public boolean isBlocking(
240 @PathParam("id") String userId,
241 @PathParam("otherId") String otherId)
242 throws PermissionDenied, ItemNotFound {
243 try (final Tx tx = beginTx()) {
244 UserProfile user = api().detail(userId, cls);
245 boolean blocking = user.isBlocking(manager.getEntity(otherId, UserProfile.class));
246 tx.success();
247 return blocking;
248 }
249 }
250
251 @POST
252 @Path("{id:[^/]+}/blocked")
253 public void blockUserProfile(
254 @PathParam("id") String userId,
255 @QueryParam(ID_PARAM) List<String> otherIds)
256 throws PermissionDenied, ItemNotFound {
257 try (final Tx tx = beginTx()) {
258 userProfilesApi().addBlocked(userId, otherIds);
259 tx.success();
260 }
261 }
262
263 @DELETE
264 @Path("{id:[^/]+}/blocked")
265 public void unblockUserProfile(
266 @PathParam("id") String userId,
267 @QueryParam(ID_PARAM) List<String> otherIds)
268 throws PermissionDenied, ItemNotFound {
269 try (final Tx tx = beginTx()) {
270 userProfilesApi().removeBlocked(userId, otherIds);
271 tx.success();
272 }
273 }
274
275 @GET
276 @Produces(MediaType.APPLICATION_JSON)
277 @Path("{id:[^/]+}/watching")
278 public Response listWatching(@PathParam("id") String userId) throws ItemNotFound {
279 try (final Tx tx = beginTx()) {
280 UserProfile user = api().detail(userId, cls);
281 Response response = streamingPage(() -> getQuery()
282 .page(user.getWatching(), Watchable.class));
283 tx.success();
284 return response;
285 }
286 }
287
288 @POST
289 @Path("{id:[^/]+}/watching")
290 public void watchItem(
291 @PathParam("id") String userId,
292 @QueryParam(ID_PARAM) List<String> otherIds)
293 throws PermissionDenied, ItemNotFound {
294 try (final Tx tx = beginTx()) {
295 userProfilesApi().addWatching(userId, otherIds);
296 tx.success();
297 }
298 }
299
300 @DELETE
301 @Path("{id:[^/]+}/watching")
302 public void unwatchItem(
303 @PathParam("id") String userId,
304 @QueryParam(ID_PARAM) List<String> otherIds)
305 throws PermissionDenied, ItemNotFound {
306 try (final Tx tx = beginTx()) {
307 userProfilesApi().removeWatching(userId, otherIds);
308 tx.success();
309 }
310 }
311
312 @GET
313 @Produces(MediaType.APPLICATION_JSON)
314 @Path("{id:[^/]+}/is-watching/{otherId:[^/]+}")
315 public boolean isWatching(
316 @PathParam("id") String userId,
317 @PathParam("otherId") String otherId)
318 throws PermissionDenied, ItemNotFound {
319 try (final Tx tx = beginTx()) {
320 UserProfile user = api().detail(userId, cls);
321 boolean watching = user.isWatching(manager.getEntity(otherId, Watchable.class));
322 tx.success();
323 return watching;
324 }
325 }
326
327 @GET
328 @Produces(MediaType.APPLICATION_JSON)
329 @Path("{id:[^/]+}/annotations")
330 public Response listAnnotations(@PathParam("id") String userId) throws ItemNotFound {
331 try (final Tx tx = beginTx()) {
332 UserProfile user = api().detail(userId, cls);
333 Response response = streamingPage(() -> getQuery()
334 .page(user.getAnnotations(), Annotation.class));
335 tx.success();
336 return response;
337 }
338 }
339
340 @GET
341 @Produces(MediaType.APPLICATION_JSON)
342 @Path("{id:[^/]+}/links")
343 public Response pageLinks(@PathParam("id") String userId) throws ItemNotFound {
344 try (final Tx tx = beginTx()) {
345 UserProfile user = api().detail(userId, cls);
346 Response response = streamingPage(() -> getQuery()
347 .page(user.getLinks(), Link.class));
348 tx.success();
349 return response;
350 }
351 }
352
353 @GET
354 @Produces(MediaType.APPLICATION_JSON)
355 @Path("{id:[^/]+}/virtual-units")
356 public Response pageVirtualUnits(@PathParam("id") String userId) throws ItemNotFound {
357 try (final Tx tx = beginTx()) {
358 UserProfile user = api().detail(userId, cls);
359 Response response = streamingPage(() -> getQuery()
360 .page(user.getVirtualUnits(), VirtualUnit.class));
361 tx.success();
362 return response;
363 }
364 }
365
366
367
368
369
370
371
372
373
374
375 @GET
376 @Produces(MediaType.APPLICATION_JSON)
377 @Path("{id:[^/]+}/actions")
378 public Response aggregateUserActions(
379 @PathParam("id") String userId,
380 @QueryParam(AGGREGATION_PARAM) @DefaultValue("strict") EventsApi.Aggregation aggregation)
381 throws ItemNotFound {
382 try (final Tx tx = beginTx()) {
383 UserProfile user = manager.getEntity(userId, UserProfile.class);
384 EventsApi eventsApi = getEventsApi()
385 .withAggregation(aggregation);
386 Response response = streamingListOfLists(() -> eventsApi.aggregateActions(user));
387 tx.success();
388 return response;
389 }
390 }
391
392
393
394
395
396
397
398
399
400
401
402 @GET
403 @Produces(MediaType.APPLICATION_JSON)
404 @Path("{id:[^/]+}/events")
405 public Response aggregateEventsForUser(
406 @PathParam("id") String userId,
407 @QueryParam(AGGREGATION_PARAM) @DefaultValue("user") EventsApi.Aggregation aggregation)
408 throws ItemNotFound {
409 try (final Tx tx = beginTx()) {
410 UserProfile asUser = manager.getEntity(userId, UserProfile.class);
411 EventsApi eventsApi = getEventsApi()
412 .withAggregation(aggregation);
413 Response response = streamingListOfLists(() -> eventsApi.aggregateAsUser(asUser));
414 tx.success();
415 return response;
416 }
417 }
418
419
420
421 private UserProfilesApi userProfilesApi() {
422
423 return api().enableLogging(false).userProfiles();
424 }
425 }