View Javadoc

1   /*
2    * Copyright 2015 Data Archiving and Networked Services (an institute of
3    * Koninklijke Nederlandse Akademie van Wetenschappen), King's College London,
4    * Georg-August-Universitaet Goettingen Stiftung Oeffentlichen Rechts
5    *
6    * Licensed under the EUPL, Version 1.1 or – as soon they will be approved by
7    * the European Commission - subsequent versions of the EUPL (the "Licence");
8    * You may not use this work except in compliance with the Licence.
9    * You may obtain a copy of the Licence at:
10   *
11   * https://joinup.ec.europa.eu/software/page/eupl
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the Licence is distributed on an "AS IS" basis,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the Licence for the specific language governing
17   * permissions and limitations under the Licence.
18   */
19  
20  package eu.ehri.extension;
21  
22  import com.fasterxml.jackson.core.type.TypeReference;
23  import com.google.common.collect.Iterables;
24  import com.google.common.collect.Maps;
25  import com.tinkerpop.blueprints.CloseableIterable;
26  import com.tinkerpop.blueprints.Graph;
27  import com.tinkerpop.blueprints.Vertex;
28  import com.tinkerpop.blueprints.util.io.graphson.GraphSONMode;
29  import com.tinkerpop.blueprints.util.io.graphson.GraphSONWriter;
30  import eu.ehri.extension.base.AbstractResource;
31  import eu.ehri.project.acl.PermissionType;
32  import eu.ehri.project.acl.wrapper.AclGraph;
33  import eu.ehri.project.core.Tx;
34  import eu.ehri.project.definitions.Ontology;
35  import eu.ehri.project.models.EntityClass;
36  import eu.ehri.project.models.Group;
37  import eu.ehri.project.models.UserProfile;
38  import eu.ehri.project.models.base.Accessor;
39  import eu.ehri.project.persistence.Bundle;
40  import eu.ehri.project.tools.JsonDataExporter;
41  import org.neo4j.graphdb.GraphDatabaseService;
42  
43  import javax.ws.rs.Consumes;
44  import javax.ws.rs.GET;
45  import javax.ws.rs.POST;
46  import javax.ws.rs.Path;
47  import javax.ws.rs.Produces;
48  import javax.ws.rs.QueryParam;
49  import javax.ws.rs.core.Context;
50  import javax.ws.rs.core.MediaType;
51  import javax.ws.rs.core.Response;
52  import javax.ws.rs.core.StreamingOutput;
53  import java.io.IOException;
54  import java.util.HashMap;
55  import java.util.List;
56  import java.util.Map;
57  
58  /**
59   * Provides additional Admin methods needed by client systems
60   * and general graph-maintenance functionality.
61   */
62  @Path(AdminResource.ENDPOINT)
63  public class AdminResource extends AbstractResource {
64  
65      public static final String ENDPOINT = "admin";
66      public static final String DEFAULT_USER_ID_PREFIX = "user";
67      public static final String DEFAULT_USER_ID_FORMAT = "%s%06d";
68  
69      public AdminResource(@Context GraphDatabaseService database) {
70          super(database);
71      }
72  
73      /**
74       * Export the DB as a stream of JSON in
75       * <a href="https://github.com/tinkerpop/blueprints/wiki/GraphSON-Reader-and-Writer-Library">GraphSON</a> format.
76       * <p>
77       * The mode used is EXTENDED.
78       */
79      @GET
80      @Produces(MediaType.APPLICATION_JSON)
81      @Path("export-graphson")
82      public Response getGraphSON() throws Exception {
83          return Response.ok((StreamingOutput) stream -> {
84              try (final Tx tx = beginTx()) {
85                  Accessor accessor = getRequesterUserProfile();
86                  AclGraph<?> aclGraph = new AclGraph<Graph>(graph.getBaseGraph(), accessor);
87                  GraphSONWriter.outputGraph(aclGraph, stream, GraphSONMode.EXTENDED);
88                  tx.success();
89              }
90          }).build();
91      }
92  
93      @GET
94      @Produces(MediaType.APPLICATION_JSON)
95      @Path("export-json")
96      public Response exportNodes() throws Exception {
97          return Response.ok((StreamingOutput) stream -> {
98              try (final Tx tx = beginTx()) {
99                  Accessor accessor = getRequesterUserProfile();
100                 AclGraph<?> aclGraph = new AclGraph<Graph>(graph.getBaseGraph(), accessor);
101                 JsonDataExporter.outputGraph(aclGraph, stream);
102                 tx.success();
103             }
104         }).build();
105     }
106 
107     /**
108      * Create a new user with a default name and identifier.
109      *
110      * @param jsonData Additional key/value data for the created object
111      * @param groups   IDs for groups to which the user should belong
112      * @return A new user
113      */
114     @POST
115     @Produces(MediaType.APPLICATION_JSON)
116     @Consumes(MediaType.APPLICATION_JSON)
117     @Path("create-default-user-profile")
118     public Response createDefaultUserProfile(String jsonData,
119             @QueryParam(GROUP_PARAM) List<String> groups) throws Exception {
120         try (final Tx tx = beginTx()) {
121             String ident = getNextDefaultUserId();
122             Bundle bundle = Bundle.Builder.withClass(EntityClass.USER_PROFILE)
123                     .addDataValue(Ontology.IDENTIFIER_KEY, ident)
124                     .addDataValue(Ontology.NAME_KEY, ident)
125                     .addData(parseUserData(jsonData))
126                     .build();
127 
128             // NB: This assumes that admin's ID is the same as its identifier.
129             Accessor admin = manager.getEntity(Group.ADMIN_GROUP_IDENTIFIER, Accessor.class);
130             UserProfile user = api().withAccessor(admin).create(bundle, UserProfile.class);
131 
132             // add to the groups
133             for (String groupId : groups) {
134                 Group group = manager.getEntity(groupId, EntityClass.GROUP, Group.class);
135                 group.addMember(user);
136             }
137 
138             // Grant them owner permissions on their own account.
139             api().aclManager().grantPermission(user, PermissionType.OWNER, user);
140             Response response = creationResponse(user);
141             tx.success();
142             return response;
143         }
144     }
145 
146     // Helpers...
147 
148     private String getNextDefaultUserId() {
149         try (CloseableIterable<Vertex> query = manager.getVertices(EntityClass.USER_PROFILE)) {
150             long start = Iterables.size(query) + 1;
151             while (manager.exists(String.format(DEFAULT_USER_ID_FORMAT,
152                     DEFAULT_USER_ID_PREFIX, start))) start++;
153             return String.format(DEFAULT_USER_ID_FORMAT, DEFAULT_USER_ID_PREFIX, start);
154         }
155     }
156 
157     private Map<String, Object> parseUserData(String json) throws IOException {
158         if (json == null || json.trim().equals("")) {
159             return Maps.newHashMap();
160         } else {
161             TypeReference<HashMap<String, Object>> typeRef = new TypeReference<
162                     HashMap<String, Object>
163                     >() {
164             };
165             return jsonMapper.readValue(json, typeRef);
166         }
167     }
168 }