package io.lumify.web.routes.workspace;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import io.lumify.core.config.Configuration;
import io.lumify.core.model.audit.AuditAction;
import io.lumify.core.model.audit.AuditRepository;
import io.lumify.core.model.ontology.OntologyRepository;
import io.lumify.core.model.properties.LumifyProperties;
import io.lumify.core.model.termMention.TermMentionRepository;
import io.lumify.core.model.user.UserRepository;
import io.lumify.core.model.workQueue.WorkQueueRepository;
import io.lumify.core.model.workspace.WorkspaceRepository;
import io.lumify.core.security.LumifyVisibility;
import io.lumify.core.security.VisibilityTranslator;
import io.lumify.core.user.User;
import io.lumify.core.util.GraphUtil;
import io.lumify.core.util.LumifyLogger;
import io.lumify.core.util.LumifyLoggerFactory;
import io.lumify.web.clientapi.model.VisibilityJson;
import org.json.JSONArray;
import org.json.JSONObject;
import org.securegraph.*;
import java.util.List;
import static org.securegraph.util.IterableUtils.toList;
@Singleton
public class WorkspaceHelper {
private static final LumifyLogger LOGGER = LumifyLoggerFactory.getLogger(WorkspaceHelper.class);
private final TermMentionRepository termMentionRepository;
private final AuditRepository auditRepository;
private final UserRepository userRepository;
private final WorkQueueRepository workQueueRepository;
private final Graph graph;
private final VisibilityTranslator visibilityTranslator;
private String entityHasImageIri;
private String artifactContainsImageOfEntityIri;
private final OntologyRepository ontologyRepository;
@Inject
public WorkspaceHelper(
final TermMentionRepository termMentionRepository,
final Configuration configuration,
final AuditRepository auditRepository,
final UserRepository userRepository,
final WorkQueueRepository workQueueRepository,
final Graph graph,
final VisibilityTranslator visibilityTranslator,
final OntologyRepository ontologyRepository
) {
this.termMentionRepository = termMentionRepository;
this.auditRepository = auditRepository;
this.userRepository = userRepository;
this.workQueueRepository = workQueueRepository;
this.graph = graph;
this.visibilityTranslator = visibilityTranslator;
this.ontologyRepository = ontologyRepository;
this.entityHasImageIri = ontologyRepository.getRelationshipIRIByIntent("entityHasImage");
if (this.entityHasImageIri == null) {
LOGGER.warn("'entityHasImage' intent has not been defined. Please update your ontology.");
}
this.artifactContainsImageOfEntityIri = ontologyRepository.getRelationshipIRIByIntent("artifactContainsImageOfEntity");
if (this.artifactContainsImageOfEntityIri == null) {
LOGGER.warn("'artifactContainsImageOfEntity' intent has not been defined. Please update your ontology.");
}
}
public void unresolveTerm(Vertex resolvedVertex, Vertex termMention, LumifyVisibility visibility, User user, Authorizations authorizations) {
Vertex sourceVertex = termMentionRepository.findSourceVertex(termMention, authorizations);
if (sourceVertex == null) {
return;
}
List<Edge> edges = toList(sourceVertex.getEdges(Direction.BOTH, authorizations));
if (edges.size() == 1) {
graph.removeEdge(edges.get(0), authorizations);
workQueueRepository.pushEdgeDeletion(edges.get(0));
auditRepository.auditRelationship(AuditAction.DELETE, sourceVertex, resolvedVertex, edges.get(0), "", "", user, visibility.getVisibility());
}
termMentionRepository.delete(termMention, authorizations);
workQueueRepository.pushTextUpdated(sourceVertex.getId());
graph.flush();
auditRepository.auditVertex(AuditAction.UNRESOLVE, resolvedVertex.getId(), "", "", user, visibility.getVisibility());
}
public void deleteProperty(Vertex vertex, Property property, boolean propertyIsPublic, String workspaceId, User user, Authorizations authorizations) {
auditRepository.auditEntityProperty(AuditAction.DELETE, vertex.getId(), property.getKey(), property.getName(), property.getValue(), null, "", "", property.getMetadata(), user, property.getVisibility());
if (propertyIsPublic) {
vertex.markPropertyHidden(property, new Visibility(workspaceId), authorizations);
} else {
vertex.removeProperty(property.getKey(), property.getName(), authorizations);
}
graph.flush();
workQueueRepository.pushGraphPropertyQueue(vertex, property);
}
public void deleteEdge(String workspaceId, Edge edge, Vertex sourceVertex, Vertex destVertex, boolean isPublicEdge, User user, Authorizations authorizations) {
ensureOntologyIrisInitialized();
if (isPublicEdge) {
Visibility workspaceVisibility = new Visibility(workspaceId);
graph.markEdgeHidden(edge, workspaceVisibility, authorizations);
if (edge.getLabel().equals(entityHasImageIri)) {
Property entityHasImage = sourceVertex.getProperty(LumifyProperties.ENTITY_IMAGE_VERTEX_ID.getPropertyName());
if (entityHasImage != null) {
sourceVertex.markPropertyHidden(entityHasImage, workspaceVisibility, authorizations);
this.workQueueRepository.pushElementImageQueue(sourceVertex, entityHasImage);
}
}
for (Vertex termMention : termMentionRepository.findByEdgeId(sourceVertex.getId(), edge.getId(), authorizations)) {
termMentionRepository.markHidden(termMention, workspaceVisibility, authorizations);
workQueueRepository.pushTextUpdated(sourceVertex.getId());
}
graph.flush();
this.workQueueRepository.pushEdgeDeletion(edge);
} else {
graph.removeEdge(edge, authorizations);
if (edge.getLabel().equals(entityHasImageIri)) {
Property entityHasImage = sourceVertex.getProperty(LumifyProperties.ENTITY_IMAGE_VERTEX_ID.getPropertyName());
if (entityHasImage != null) {
sourceVertex.removeProperty(entityHasImage.getName(), authorizations);
this.workQueueRepository.pushElementImageQueue(sourceVertex, entityHasImage);
}
}
for (Vertex termMention : termMentionRepository.findByEdgeId(sourceVertex.getId(), edge.getId(), authorizations)) {
termMentionRepository.delete(termMention, authorizations);
workQueueRepository.pushTextUpdated(sourceVertex.getId());
}
graph.flush();
this.workQueueRepository.pushEdgeDeletion(edge);
// TODO: replace "" when we implement commenting on ui
auditRepository.auditRelationship(AuditAction.DELETE, sourceVertex, destVertex, edge, "", "", user, new LumifyVisibility().getVisibility());
}
graph.flush();
}
private void ensureOntologyIrisInitialized() {
if (this.entityHasImageIri == null) {
this.entityHasImageIri = ontologyRepository.getRelationshipIRIByIntent("entityHasImage");
}
if (this.artifactContainsImageOfEntityIri == null) {
this.artifactContainsImageOfEntityIri = ontologyRepository.getRelationshipIRIByIntent("artifactContainsImageOfEntity");
}
}
public void deleteVertex(Vertex vertex, String workspaceId, boolean isPublicVertex, Authorizations authorizations, User user) {
ensureOntologyIrisInitialized();
if (isPublicVertex) {
Visibility workspaceVisibility = new Visibility(workspaceId);
graph.markVertexHidden(vertex, workspaceVisibility, authorizations);
graph.flush();
workQueueRepository.pushVertexDeletion(vertex);
} else {
JSONArray unresolved = new JSONArray();
VisibilityJson visibilityJson = LumifyProperties.VISIBILITY_JSON.getPropertyValue(vertex);
visibilityJson = GraphUtil.updateVisibilityJsonRemoveFromAllWorkspace(visibilityJson);
LumifyVisibility lumifyVisibility = visibilityTranslator.toVisibility(visibilityJson);
// because we store the current vertex image in a property we need to possibly find that property and change it
// if we are deleting the current image.
for (Edge edge : vertex.getEdges(Direction.BOTH, entityHasImageIri, authorizations)) {
if (edge.getVertexId(Direction.IN).equals(vertex.getId())) {
Vertex outVertex = edge.getVertex(Direction.OUT, authorizations);
Property entityHasImage = outVertex.getProperty(LumifyProperties.ENTITY_IMAGE_VERTEX_ID.getPropertyName());
outVertex.removeProperty(entityHasImage.getName(), authorizations);
workQueueRepository.pushElementImageQueue(outVertex, entityHasImage);
}
}
// because detected objects are currently stored as properties on the artifact that reference the entity
// that they are resolved to we need to delete that property
for (Edge edge : vertex.getEdges(Direction.BOTH, artifactContainsImageOfEntityIri, authorizations)) {
for (Property rowKeyProperty : vertex.getProperties(LumifyProperties.ROW_KEY.getPropertyName())) {
String multiValueKey = rowKeyProperty.getValue().toString();
if (edge.getVertexId(Direction.IN).equals(vertex.getId())) {
Vertex outVertex = edge.getVertex(Direction.OUT, authorizations);
// remove property
LumifyProperties.DETECTED_OBJECT.removeProperty(outVertex, multiValueKey, authorizations);
graph.removeEdge(edge, authorizations);
auditRepository.auditRelationship(AuditAction.DELETE, outVertex, vertex, edge, "", "", user, lumifyVisibility.getVisibility());
workQueueRepository.pushEdgeDeletion(edge);
workQueueRepository.pushGraphPropertyQueue(outVertex, multiValueKey,
LumifyProperties.DETECTED_OBJECT.getPropertyName(), workspaceId, visibilityJson.getSource());
}
}
}
// because we store term mentions with an added visibility we need to delete them with that added authorizations.
// we also need to notify the front-end of changes as well as audit the changes
for (Vertex termMention : termMentionRepository.findResolvedTo(vertex.getId(), authorizations)) {
unresolveTerm(vertex, termMention, lumifyVisibility, user, authorizations);
JSONObject result = new JSONObject();
result.put("success", true);
unresolved.put(result);
}
// because we store workspaces with an added visibility we need to delete them with that added authorizations.
Authorizations systemAuthorization = userRepository.getAuthorizations(user, WorkspaceRepository.VISIBILITY_STRING, workspaceId);
Vertex workspaceVertex = graph.getVertex(workspaceId, systemAuthorization);
for (Edge edge : workspaceVertex.getEdges(vertex, Direction.BOTH, systemAuthorization)) {
graph.removeEdge(edge, systemAuthorization);
}
graph.removeVertex(vertex, authorizations);
graph.flush();
this.workQueueRepository.pushVertexDeletion(vertex);
// TODO: replace "" when we implement commenting on ui
auditRepository.auditVertex(AuditAction.DELETE, vertex.getId(), "", "", user, new LumifyVisibility().getVisibility());
}
graph.flush();
}
}