package io.lumify.core.model.workspace; import io.lumify.core.exception.LumifyAccessDeniedException; import io.lumify.core.security.LumifyVisibility; import io.lumify.core.user.User; import io.lumify.core.util.LumifyLogger; import io.lumify.core.util.LumifyLoggerFactory; import io.lumify.web.clientapi.model.ClientApiWorkspace; import io.lumify.web.clientapi.model.ClientApiWorkspaceDiff; import io.lumify.web.clientapi.model.GraphPosition; import io.lumify.web.clientapi.model.WorkspaceAccess; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.securegraph.Graph; import org.securegraph.util.ConvertingIterable; import java.util.ArrayList; import java.util.List; import java.util.Locale; import static com.google.common.base.Preconditions.checkNotNull; public abstract class WorkspaceRepository { private static final LumifyLogger LOGGER = LumifyLoggerFactory.getLogger(WorkspaceRepository.class); public static final String VISIBILITY_STRING = "workspace"; public static final LumifyVisibility VISIBILITY = new LumifyVisibility(VISIBILITY_STRING); public static final String WORKSPACE_CONCEPT_IRI = "http://lumify.io/workspace#workspace"; public static final String WORKSPACE_TO_ENTITY_RELATIONSHIP_IRI = "http://lumify.io/workspace#toEntity"; public static final String WORKSPACE_TO_USER_RELATIONSHIP_IRI = "http://lumify.io/workspace#toUser"; public static final String WORKSPACE_ID_PREFIX = "WORKSPACE_"; public static final String OWL_IRI = "http://lumify.io/workspace"; private final Graph graph; protected WorkspaceRepository(Graph graph) { this.graph = graph; } public abstract void delete(Workspace workspace, User user); public Workspace findById(String workspaceId, User user) { return findById(workspaceId, false, user); } public abstract Workspace findById(String workspaceId, boolean includeHidden, User user); public Iterable<Workspace> findByIds(final Iterable<String> workspaceIds, final User user) { return new ConvertingIterable<String, Workspace>(workspaceIds) { @Override protected Workspace convert(String workspaceId) { if (workspaceId == null) { return null; } try { return findById(workspaceId, user); } catch (LumifyAccessDeniedException ex) { return null; } } }; } public abstract Workspace add(String workspaceId, String title, User user); public Workspace add(String title, User user) { String workspaceId = WORKSPACE_ID_PREFIX + graph.getIdGenerator().nextId(); return add(workspaceId, title, user); } public abstract Iterable<Workspace> findAllForUser(User user); public abstract void setTitle(Workspace workspace, String title, User user); public abstract List<WorkspaceUser> findUsersWithAccess(String workspaceId, User user); public abstract List<WorkspaceEntity> findEntities(Workspace workspace, User user); public Workspace copy(Workspace workspace, User user) { return copyTo(workspace, user, user); } public Workspace copyTo(Workspace workspace, User destinationUser, User user) { Workspace newWorkspace = add("Copy of " + workspace.getDisplayTitle(), destinationUser); List<WorkspaceEntity> entities = findEntities(workspace, user); Iterable<Update> updates = new ConvertingIterable<WorkspaceEntity, Update>(entities) { @Override protected Update convert(WorkspaceEntity entity) { return new Update(entity.getEntityVertexId(), entity.isVisible(), new GraphPosition(entity.getGraphPositionX(), entity.getGraphPositionY())); } }; updateEntitiesOnWorkspace(newWorkspace, updates, destinationUser); return newWorkspace; } public abstract void softDeleteEntitiesFromWorkspace(Workspace workspace, List<String> entityIdsToDelete, User authUser); public abstract void deleteUserFromWorkspace(Workspace workspace, String userId, User user); public abstract void updateUserOnWorkspace(Workspace workspace, String userId, WorkspaceAccess workspaceAccess, User user); public abstract ClientApiWorkspaceDiff getDiff(Workspace workspace, User user, Locale locale, String timeZone); public String getCreatorUserId(String workspaceId, User user) { for (WorkspaceUser workspaceUser : findUsersWithAccess(workspaceId, user)) { if (workspaceUser.isCreator()) { return workspaceUser.getUserId(); } } return null; } public abstract boolean hasCommentPermissions(String workspaceId, User user); public abstract boolean hasWritePermissions(String workspaceId, User user); public abstract boolean hasReadPermissions(String workspaceId, User user); public JSONArray toJson(Iterable<Workspace> workspaces, User user, boolean includeVertices) { JSONArray resultJson = new JSONArray(); for (Workspace workspace : workspaces) { resultJson.put(toJson(workspace, user, includeVertices)); } return resultJson; } public JSONObject toJson(Workspace workspace, User user, boolean includeVertices) { checkNotNull(workspace, "workspace cannot be null"); checkNotNull(user, "user cannot be null"); try { JSONObject workspaceJson = new JSONObject(); workspaceJson.put("workspaceId", workspace.getWorkspaceId()); workspaceJson.put("title", workspace.getDisplayTitle()); String creatorUserId = getCreatorUserId(workspace.getWorkspaceId(), user); if (creatorUserId != null) { workspaceJson.put("createdBy", creatorUserId); workspaceJson.put("sharedToUser", !creatorUserId.equals(user.getUserId())); } workspaceJson.put("editable", hasWritePermissions(workspace.getWorkspaceId(), user)); JSONArray usersJson = new JSONArray(); for (WorkspaceUser workspaceUser : findUsersWithAccess(workspace.getWorkspaceId(), user)) { String userId = workspaceUser.getUserId(); JSONObject userJson = new JSONObject(); userJson.put("userId", userId); userJson.put("access", workspaceUser.getWorkspaceAccess().toString().toLowerCase()); usersJson.put(userJson); } workspaceJson.put("users", usersJson); if (includeVertices) { JSONArray verticesJson = new JSONArray(); for (WorkspaceEntity workspaceEntity : findEntities(workspace, user)) { if (!workspaceEntity.isVisible()) { continue; } JSONObject vertexJson = new JSONObject(); vertexJson.put("vertexId", workspaceEntity.getEntityVertexId()); Integer graphPositionX = workspaceEntity.getGraphPositionX(); Integer graphPositionY = workspaceEntity.getGraphPositionY(); if (graphPositionX != null && graphPositionY != null) { JSONObject graphPositionJson = new JSONObject(); graphPositionJson.put("x", graphPositionX); graphPositionJson.put("y", graphPositionY); vertexJson.put("graphPosition", graphPositionJson); } verticesJson.put(vertexJson); } workspaceJson.put("vertices", verticesJson); } return workspaceJson; } catch (JSONException e) { throw new RuntimeException(e); } } public ClientApiWorkspace toClientApi(Workspace workspace, User user, boolean includeVertices) { checkNotNull(workspace, "workspace cannot be null"); checkNotNull(user, "user cannot be null"); try { ClientApiWorkspace workspaceClientApi = new ClientApiWorkspace(); workspaceClientApi.setWorkspaceId(workspace.getWorkspaceId()); workspaceClientApi.setTitle(workspace.getDisplayTitle()); String creatorUserId = getCreatorUserId(workspace.getWorkspaceId(), user); if (creatorUserId != null) { workspaceClientApi.setCreatedBy(creatorUserId); workspaceClientApi.setSharedToUser(!creatorUserId.equals(user.getUserId())); } workspaceClientApi.setEditable(hasWritePermissions(workspace.getWorkspaceId(), user)); workspaceClientApi.setCommentable(hasCommentPermissions(workspace.getWorkspaceId(), user)); for (WorkspaceUser u : findUsersWithAccess(workspace.getWorkspaceId(), user)) { String userId = u.getUserId(); ClientApiWorkspace.User workspaceUser = new ClientApiWorkspace.User(); workspaceUser.setUserId(userId); workspaceUser.setAccess(u.getWorkspaceAccess()); workspaceClientApi.addUser(workspaceUser); } if (includeVertices) { for (WorkspaceEntity workspaceEntity : findEntities(workspace, user)) { if (!workspaceEntity.isVisible()) { continue; } ClientApiWorkspace.Vertex v = new ClientApiWorkspace.Vertex(); v.setVertexId(workspaceEntity.getEntityVertexId()); Integer graphPositionX = workspaceEntity.getGraphPositionX(); Integer graphPositionY = workspaceEntity.getGraphPositionY(); if (graphPositionX != null && graphPositionY != null) { GraphPosition graphPosition = new GraphPosition(graphPositionX, graphPositionY); v.setGraphPosition(graphPosition); v.setGraphLayoutJson(null); } else { v.setGraphPosition(null); String graphLayoutJson = workspaceEntity.getGraphLayoutJson(); if (graphLayoutJson != null) { v.setGraphLayoutJson(graphLayoutJson); } else { v.setGraphLayoutJson(null); } } workspaceClientApi.addVertex(v); } } else { workspaceClientApi.removeVertices(); } return workspaceClientApi; } catch (JSONException e) { throw new RuntimeException(e); } } protected Graph getGraph() { return graph; } public abstract void updateEntitiesOnWorkspace(Workspace workspace, Iterable<Update> updates, User user); public void updateEntityOnWorkspace(Workspace workspace, Update update, User user) { List<Update> updates = new ArrayList<>(); updates.add(update); updateEntitiesOnWorkspace(workspace, updates, user); } public void updateEntityOnWorkspace(Workspace workspace, String vertexId, Boolean visible, GraphPosition graphPosition, User user) { updateEntityOnWorkspace(workspace, new Update(vertexId, visible, graphPosition), user); } public void updateEntityOnWorkspace(String workspaceId, String vertexId, Boolean visible, GraphPosition graphPosition, User user) { Workspace workspace = findById(workspaceId, user); updateEntityOnWorkspace(workspace, vertexId, visible, graphPosition, user); } public static class Update { private final String vertexId; private final Boolean visible; private final GraphPosition graphPosition; private final String graphLayoutJson; public Update(String vertexId, Boolean visible, GraphPosition graphPosition) { this.vertexId = vertexId; this.visible = visible; this.graphPosition = graphPosition; graphLayoutJson = null; } public Update(String vertexId, Boolean visible, GraphPosition graphPosition, String graphLayoutJson) { this.vertexId = vertexId; this.visible = visible; this.graphPosition = graphPosition; this.graphLayoutJson = graphLayoutJson; } public String getVertexId() { return vertexId; } public Boolean getVisible() { return visible; } public GraphPosition getGraphPosition() { return graphPosition; } public String getGraphLayoutJson() { return graphLayoutJson; } } }