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.Lists;
23 import com.tinkerpop.blueprints.Vertex;
24 import com.tinkerpop.gremlin.java.GremlinPipeline;
25 import com.tinkerpop.pipes.PipeFunction;
26 import eu.ehri.extension.base.AbstractAccessibleResource;
27 import eu.ehri.extension.base.AbstractResource;
28 import eu.ehri.extension.base.DeleteResource;
29 import eu.ehri.extension.base.GetResource;
30 import eu.ehri.extension.base.ListResource;
31 import eu.ehri.extension.base.UpdateResource;
32 import eu.ehri.project.acl.AclManager;
33 import eu.ehri.project.core.Tx;
34 import eu.ehri.project.definitions.Entities;
35 import eu.ehri.project.exceptions.AccessDenied;
36 import eu.ehri.project.exceptions.DeserializationError;
37 import eu.ehri.project.exceptions.ItemNotFound;
38 import eu.ehri.project.exceptions.PermissionDenied;
39 import eu.ehri.project.exceptions.ValidationError;
40 import eu.ehri.project.models.DocumentaryUnit;
41 import eu.ehri.project.models.EntityClass;
42 import eu.ehri.project.models.UserProfile;
43 import eu.ehri.project.models.VirtualUnit;
44 import eu.ehri.project.models.base.Accessor;
45 import eu.ehri.project.persistence.Bundle;
46 import org.neo4j.graphdb.GraphDatabaseService;
47
48 import javax.ws.rs.Consumes;
49 import javax.ws.rs.DELETE;
50 import javax.ws.rs.DefaultValue;
51 import javax.ws.rs.GET;
52 import javax.ws.rs.POST;
53 import javax.ws.rs.PUT;
54 import javax.ws.rs.Path;
55 import javax.ws.rs.PathParam;
56 import javax.ws.rs.Produces;
57 import javax.ws.rs.QueryParam;
58 import javax.ws.rs.core.Context;
59 import javax.ws.rs.core.MediaType;
60 import javax.ws.rs.core.Response;
61 import java.util.List;
62
63
64
65
66 @Path(AbstractResource.RESOURCE_ENDPOINT_PREFIX + "/" + Entities.VIRTUAL_UNIT)
67 public final class VirtualUnitResource extends
68 AbstractAccessibleResource<VirtualUnit>
69 implements GetResource, ListResource, UpdateResource, DeleteResource {
70
71 public static final String INCLUDED = "includes";
72
73 public VirtualUnitResource(@Context GraphDatabaseService database) {
74 super(database, VirtualUnit.class);
75 }
76
77 @GET
78 @Produces(MediaType.APPLICATION_JSON)
79 @Path("{id:[^/]+}")
80 @Override
81 public Response get(@PathParam("id") String id) throws ItemNotFound {
82 return getItem(id);
83 }
84
85 @GET
86 @Produces(MediaType.APPLICATION_JSON)
87 @Override
88 public Response list() {
89 return listItems();
90 }
91
92 @GET
93 @Produces(MediaType.APPLICATION_JSON)
94 @Path("{id:[^/]+}/list")
95 public Response listChildVirtualUnits(
96 @PathParam("id") String id,
97 @QueryParam(ALL_PARAM) @DefaultValue("false") boolean all) throws ItemNotFound {
98 try (final Tx tx = beginTx()) {
99 VirtualUnit parent = manager.getEntity(id, VirtualUnit.class);
100 Response response = streamingPage(() -> {
101 Iterable<VirtualUnit> units = all
102 ? parent.getAllChildren()
103 : parent.getChildren();
104 return getQuery().page(units, cls);
105 });
106 tx.success();
107 return response;
108 }
109 }
110
111 @GET
112 @Produces(MediaType.APPLICATION_JSON)
113 @Path("{id:[^/]+}/includes")
114 public Response listIncludedVirtualUnits(
115 @PathParam("id") String id) throws ItemNotFound {
116 try (final Tx tx = beginTx()) {
117 VirtualUnit parent = manager.getEntity(id, VirtualUnit.class);
118 Response response = streamingPage(() -> getQuery()
119 .page(parent.getIncludedUnits(), DocumentaryUnit.class));
120 tx.success();
121 return response;
122 }
123 }
124
125 @POST
126 @Path("{id:[^/]+}/includes")
127 public Response addIncludedVirtualUnits(
128 @PathParam("id") String id, @QueryParam(ID_PARAM) List<String> includedIds)
129 throws ItemNotFound, PermissionDenied {
130 try (final Tx tx = beginTx()) {
131 UserProfile currentUser = getCurrentUser();
132 VirtualUnit parent = api().detail(id, cls);
133 Response item = single(api().virtualUnits().addIncludedUnits(parent,
134 getIncludedUnits(includedIds, currentUser)));
135 tx.success();
136 return item;
137 }
138 }
139
140 @DELETE
141 @Path("{id:[^/]+}/includes")
142 public Response removeIncludedVirtualUnits(
143 @PathParam("id") String id, @QueryParam(ID_PARAM) List<String> includedIds)
144 throws ItemNotFound, PermissionDenied {
145 try (final Tx tx = beginTx()) {
146 UserProfile currentUser = getCurrentUser();
147 VirtualUnit parent = api().detail(id, cls);
148 Response item = single(api().virtualUnits().removeIncludedUnits(parent,
149 getIncludedUnits(includedIds, currentUser)));
150 tx.success();
151 return item;
152 }
153 }
154
155 @POST
156 @Path("{from:[^/]+}/includes/{to:[^/]+}")
157 public void moveIncludedVirtualUnits(
158 @PathParam("from") String fromId, @PathParam("to") String toId,
159 @QueryParam(ID_PARAM) List<String> includedIds)
160 throws ItemNotFound, PermissionDenied {
161 try (final Tx tx = beginTx()) {
162 UserProfile currentUser = getCurrentUser();
163 VirtualUnit fromVu = api().detail(fromId, cls);
164 VirtualUnit toVu = api().detail(toId, cls);
165 Iterable<DocumentaryUnit> units = getIncludedUnits(includedIds, currentUser);
166 api().virtualUnits().moveIncludedUnits(fromVu, toVu, units);
167 tx.success();
168 }
169 }
170
171 @POST
172 @Consumes(MediaType.APPLICATION_JSON)
173 @Produces(MediaType.APPLICATION_JSON)
174 public Response createTopLevelVirtualUnit(Bundle bundle,
175 @QueryParam(ACCESSOR_PARAM) List<String> accessors,
176 @QueryParam(ID_PARAM) List<String> includedIds)
177 throws PermissionDenied, ValidationError,
178 DeserializationError, ItemNotFound {
179 try (final Tx tx = beginTx()) {
180 final Accessor currentUser = getCurrentUser();
181 final Iterable<DocumentaryUnit> includedUnits
182 = getIncludedUnits(includedIds, currentUser);
183
184 Response item = createItem(bundle, accessors, virtualUnit -> {
185 virtualUnit.setAuthor(currentUser);
186 for (DocumentaryUnit include : includedUnits) {
187 virtualUnit.addIncludedUnit(include);
188 }
189 });
190 tx.success();
191 return item;
192 }
193 }
194
195 @PUT
196 @Consumes(MediaType.APPLICATION_JSON)
197 @Produces(MediaType.APPLICATION_JSON)
198 @Path("{id:[^/]+}")
199 @Override
200 public Response update(@PathParam("id") String id, Bundle bundle)
201 throws PermissionDenied, ValidationError,
202 DeserializationError, ItemNotFound {
203 try (final Tx tx = beginTx()) {
204 Response item = updateItem(id, bundle);
205 tx.success();
206 return item;
207 }
208 }
209
210 @DELETE
211 @Path("{id:[^/]+}")
212 @Override
213 public void delete(@PathParam("id") String id)
214 throws PermissionDenied, ItemNotFound, ValidationError {
215 try (final Tx tx = beginTx()) {
216 deleteItem(id);
217 tx.success();
218 }
219 }
220
221 @POST
222 @Consumes(MediaType.APPLICATION_JSON)
223 @Produces(MediaType.APPLICATION_JSON)
224 @Path("{id:[^/]+}")
225 public Response createChildVirtualUnit(@PathParam("id") String id,
226 Bundle bundle, @QueryParam(ACCESSOR_PARAM) List<String> accessors,
227 @QueryParam(ID_PARAM) List<String> includedIds)
228 throws AccessDenied, PermissionDenied, ValidationError,
229 DeserializationError, ItemNotFound {
230 try (final Tx tx = beginTx()) {
231 Accessor currentUser = getRequesterUserProfile();
232 final Iterable<DocumentaryUnit> includedUnits
233 = getIncludedUnits(includedIds, currentUser);
234 final VirtualUnit parent = api().detail(id, cls);
235
236
237
238
239 Response item = createItem(bundle, accessors, virtualUnit -> {
240 parent.addChild(virtualUnit);
241 for (DocumentaryUnit included : includedUnits) {
242 virtualUnit.addIncludedUnit(included);
243 }
244 });
245 tx.success();
246 return item;
247 }
248 }
249
250
251
252
253
254
255 private List<DocumentaryUnit> getIncludedUnits(
256 List<String> ids, Accessor accessor) throws ItemNotFound {
257 Iterable<Vertex> vertices = manager.getVertices(ids);
258
259 PipeFunction<Vertex, Boolean> aclFilter = AclManager.getAclFilterFunction(accessor);
260
261 PipeFunction<Vertex, Boolean> typeFilter = vertex -> {
262 EntityClass entityClass = manager.getEntityClass(vertex);
263 return EntityClass.DOCUMENTARY_UNIT.equals(entityClass);
264 };
265
266 GremlinPipeline<Vertex, Vertex> units = new GremlinPipeline<Vertex, Vertex>(
267 vertices).filter(typeFilter).filter(aclFilter);
268 return Lists.newArrayList(graph.frameVertices(units, DocumentaryUnit.class));
269 }
270 }