Skip to content

Commit

Permalink
New GraphQL version
Browse files Browse the repository at this point in the history
  • Loading branch information
kerim1 committed Feb 1, 2023
1 parent 8ae355c commit e600e77
Show file tree
Hide file tree
Showing 24 changed files with 252 additions and 284 deletions.
2 changes: 1 addition & 1 deletion timbuctoo-instancev4/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-java</artifactId>
<version>11.0</version>
<version>20.0</version>
</dependency>

<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import nl.knaw.huygens.timbuctoo.v5.dataset.ImportStatus;
import nl.knaw.huygens.timbuctoo.v5.dataset.OptimizedPatchListener;
import nl.knaw.huygens.timbuctoo.v5.datastores.quadstore.dto.ChangeType;
import nl.knaw.huygens.timbuctoo.v5.datastores.quadstore.dto.CursorQuad;
import nl.knaw.huygens.timbuctoo.v5.datastores.quadstore.dto.Direction;
import nl.knaw.huygens.timbuctoo.v5.datastores.quadstore.dto.QuadGraphs;
import nl.knaw.huygens.timbuctoo.v5.datastores.schemastore.SchemaStore;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,14 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sleepycat.je.DatabaseException;
import graphql.ExecutionResult;
import graphql.GraphQL;
import graphql.GraphQLException;
import graphql.schema.GraphQLSchema;
import nl.knaw.huygens.timbuctoo.util.UriHelper;
import nl.knaw.huygens.timbuctoo.v5.dataset.DataSetRepository;
import nl.knaw.huygens.timbuctoo.v5.dataset.exceptions.RdfProcessingFailedException;
import nl.knaw.huygens.timbuctoo.v5.dropwizard.contenttypes.SerializerWriter;
import nl.knaw.huygens.timbuctoo.v5.dropwizard.contenttypes.SerializerWriterRegistry;
import nl.knaw.huygens.timbuctoo.v5.graphql.datafetchers.dto.RootData;
import nl.knaw.huygens.timbuctoo.v5.graphql.security.PermissionBasedFieldVisibility;
import nl.knaw.huygens.timbuctoo.v5.graphql.security.UserPermissionCheck;
import nl.knaw.huygens.timbuctoo.v5.graphql.serializable.SerializerExecutionStrategy;
Expand Down Expand Up @@ -44,7 +41,6 @@
import static graphql.ExecutionInput.newExecutionInput;
import static nl.knaw.huygens.timbuctoo.util.JsonBuilder.jsn;
import static nl.knaw.huygens.timbuctoo.util.JsonBuilder.jsnO;
import static nl.knaw.huygens.timbuctoo.v5.graphql.datafetchers.dto.ContextData.contextData;

@Path("/v5/graphql")
public class GraphQl {
Expand All @@ -58,8 +54,7 @@ public class GraphQl {

public GraphQl(Supplier<GraphQLSchema> graphqlGetter, SerializerWriterRegistry serializerWriterRegistry,
UserValidator userValidator, UriHelper uriHelper, PermissionFetcher permissionFetcher,
DataSetRepository dataSetRepository)
throws DatabaseException, RdfProcessingFailedException {
DataSetRepository dataSetRepository) {
this.graphqlGetter = graphqlGetter;
this.serializerWriterRegistry = serializerWriterRegistry;
this.userValidator = userValidator;
Expand All @@ -85,7 +80,7 @@ public Response postJson(JsonNode body, @QueryParam("query") String query,
} else {
queryFromBody = null;
}
Map variables = null;
Map<String, Object> variables = null;
if (body.has("variables")) {
try {
variables = objectMapper.treeToValue(body.get("variables"), HashMap.class);
Expand Down Expand Up @@ -119,14 +114,13 @@ public Response get(@QueryParam("query") String query, @HeaderParam("accept") St
return executeGraphql(null, acceptHeader, acceptParam, query, null, null, authHeader);
}


public Response executeGraphql(String query, String acceptHeader, String acceptParam, String queryFromBody,
Map variables, String operationName, String authHeader) {
Map<String, Object> variables, String operationName, String authHeader) {
final SerializerWriter serializerWriter;
if (acceptParam != null && !acceptParam.isEmpty()) {
acceptHeader = acceptParam; //Accept param overrules header because it's more under the user's control
}
if (unSpecifiedAcceptHeader(acceptHeader)) {
if (acceptHeader == null || acceptHeader.isEmpty() || "*/*".equals(acceptHeader)) {
acceptHeader = MediaType.APPLICATION_JSON;
}
if (MediaType.APPLICATION_JSON.equals(acceptHeader)) {
Expand Down Expand Up @@ -166,14 +160,11 @@ public Response executeGraphql(String query, String acceptHeader, String acceptP
user = Optional.empty();
}

UserPermissionCheck userPermissionCheck = new UserPermissionCheck(
user,
permissionFetcher
);

final GraphQLSchema transform = graphqlGetter
.get()
.transform(b -> b.fieldVisibility(new PermissionBasedFieldVisibility(userPermissionCheck,dataSetRepository)));
final UserPermissionCheck userPermissionCheck = new UserPermissionCheck(user, permissionFetcher);
final GraphQLSchema schema = graphqlGetter.get();
final GraphQLSchema transform = schema.transform(sb ->
sb.codeRegistry(schema.getCodeRegistry().transform(crb ->
crb.fieldVisibility(new PermissionBasedFieldVisibility(userPermissionCheck, dataSetRepository)))));
final GraphQL.Builder builder = GraphQL.newGraphQL(transform);

if (serializerWriter != null) {
Expand All @@ -185,8 +176,8 @@ public Response executeGraphql(String query, String acceptHeader, String acceptP
try {
final ExecutionResult result = graphQl
.execute(newExecutionInput()
.root(new RootData(user))
.context(contextData(userPermissionCheck, user))
.root(new Object())
.graphQLContext(Map.of("userPermissionCheck", userPermissionCheck, "user", user))
.query(queryFromBody)
.operationName(operationName)
.variables(variables == null ? Collections.emptyMap() : variables)
Expand Down Expand Up @@ -219,10 +210,4 @@ public Response executeGraphql(String query, String acceptHeader, String acceptP
// throw e;
}
}


public boolean unSpecifiedAcceptHeader(@HeaderParam("accept") String acceptHeader) {
return acceptHeader == null || acceptHeader.isEmpty() || "*/*".equals(acceptHeader);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,23 @@
public class DirectiveRetriever {
public static Optional<String> getDirectiveArgument(GraphQLObjectType parentType, String directiveName,
String argumentName) {
// if (parentType.getDefinition().getDirectives(directiveName).isEmpty()) {
// return Optional.empty();
// }
if (parentType.getDefinition().getDirectives(directiveName).isEmpty()) {
return Optional.empty();
}

// return Optional.of(parentType.getDefinition().getDirectives(directiveName).get(0))
return Optional.ofNullable(parentType.getDefinition().getDirective(directiveName))
return Optional.of(parentType.getDefinition().getDirectives(directiveName).get(0))
.map(d -> d.getArgument(argumentName))
.map(v -> (StringValue) v.getValue())
.map(StringValue::getValue);
}

public static Optional<String> getDirectiveArgument(GraphQLFieldDefinition field, String directiveName,
String argumentName) {
// if (field.getDefinition().getDirectives(directiveName).isEmpty()) {
// return Optional.empty();
// }
//
// return Optional.of(field.getDefinition().getDirectives(directiveName).get(0))
return Optional.ofNullable(field.getDefinition().getDirective(directiveName))
if (field.getDefinition().getDirectives(directiveName).isEmpty()) {
return Optional.empty();
}

return Optional.of(field.getDefinition().getDirectives(directiveName).get(0))
.map(d -> d.getArgument(argumentName))
.map(v -> (StringValue) v.getValue())
.map(StringValue::getValue);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@
import graphql.schema.DataFetcher;
import graphql.schema.DataFetchingEnvironment;
import nl.knaw.huygens.timbuctoo.v5.dataset.DataSetRepository;
import nl.knaw.huygens.timbuctoo.v5.graphql.datafetchers.dto.ContextData;
import nl.knaw.huygens.timbuctoo.v5.graphql.datafetchers.dto.DataSetWithDatabase;
import nl.knaw.huygens.timbuctoo.v5.graphql.security.UserPermissionCheck;
import nl.knaw.huygens.timbuctoo.v5.graphql.security.UserPermissionCheck.OldGraphQlPermission;
import nl.knaw.huygens.timbuctoo.v5.security.dto.Permission;
import nl.knaw.huygens.timbuctoo.v5.security.dto.User;

import java.util.Optional;
import java.util.stream.Stream;

public class DataMetaDataListFetcher implements DataFetcher {

private final DataSetRepository dataSetRepository;

public DataMetaDataListFetcher(DataSetRepository dataSetRepository) {
Expand All @@ -22,20 +21,19 @@ public DataMetaDataListFetcher(DataSetRepository dataSetRepository) {
@Override
public Object get(DataFetchingEnvironment env) {
return (Iterable) () -> {
Stream<DataSetWithDatabase> dataSets = dataSetRepository.getDataSets()
.stream()
.map(dataSet -> new DataSetWithDatabase(dataSet,
((ContextData) env.getContext())
.getUserPermissionCheck()));
Stream<DataSetWithDatabase> dataSets = dataSetRepository
.getDataSets()
.stream()
.map(dataSet -> new DataSetWithDatabase(dataSet, env.getGraphQlContext().get("userPermissionCheck")));
if (env.getArgument("ownOnly")) {
String userId =
((ContextData) env.getContext()).getUser().map(u -> "u" + u.getPersistentId()).orElse(null);
Optional<User> user = env.getGraphQlContext().get("user");
String userId = user.map(u -> "u" + u.getPersistentId()).orElse(null);
dataSets = dataSets.filter(d -> d.getOwnerId().equals(userId));
}
// translate
OldGraphQlPermission permission = OldGraphQlPermission.valueOf(env.getArgument("permission"));
dataSets = dataSets.filter(d -> ((ContextData) env.getContext()).getUserPermissionCheck()
.hasOldGraphQlPermission(d, permission));
UserPermissionCheck userPermissionCheck = env.getGraphQlContext().get("userPermissionCheck");
dataSets = dataSets.filter(d -> userPermissionCheck.hasOldGraphQlPermission(d, permission));

return dataSets.iterator();
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import nl.knaw.huygens.timbuctoo.v5.dataset.dto.DataSet;
import nl.knaw.huygens.timbuctoo.v5.dataset.dto.DataSetMetaData;
import nl.knaw.huygens.timbuctoo.v5.dataset.dto.LogEntry;
import nl.knaw.huygens.timbuctoo.v5.graphql.datafetchers.dto.ContextData;
import nl.knaw.huygens.timbuctoo.v5.graphql.datafetchers.dto.LogEntryImportStatus;
import nl.knaw.huygens.timbuctoo.v5.graphql.mutations.MutationHelpers;
import nl.knaw.huygens.timbuctoo.v5.security.dto.Permission;
Expand All @@ -29,11 +28,10 @@ public DataSetImportStatusFetcher(DataSetRepository dataSetRepository) {

@Override
public List<LogEntryImportStatus> get(DataFetchingEnvironment env) {
User currentUser = env.<ContextData>getContext().getUser()
.orElseThrow(() -> new RuntimeException("You are not logged in"));
Optional<User> user = env.getGraphQlContext().get("user");
User currentUser = user.orElseThrow(() -> new RuntimeException("You are not logged in"));

DataSetMetaData dataSetMetaData = env.getSource();

MutationHelpers.checkPermission(env, dataSetMetaData, Permission.READ_IMPORT_STATUS);

DataSetMetaData input = env.getSource();
Expand All @@ -43,16 +41,16 @@ public List<LogEntryImportStatus> get(DataFetchingEnvironment env) {
input.getDataSetId()
);

return dataSetOpt.map(dataSet -> dataSet.getImportManager().getLogList())
.map(logList -> {
final int[] num = new int[]{0};
return logList.getEntries().stream().map(logEntry -> {
Iterable<LogEntry> unprocessedEntries = logList::getUnprocessed;
boolean unprocessed = stream(unprocessedEntries.spliterator(), false)
.anyMatch(unprocessedEntry -> unprocessedEntry.equals(logEntry));
return new LogEntryImportStatus(logEntry, num[0]++, unprocessed);
}).collect(toList());
}).orElse(Lists.newArrayList());
return dataSetOpt
.map(dataSet -> dataSet.getImportManager().getLogList())
.map(logList -> {
final int[] num = new int[]{0};
return logList.getEntries().stream().map(logEntry -> {
Iterable<LogEntry> unprocessedEntries = logList::getUnprocessed;
boolean unprocessed = stream(unprocessedEntries.spliterator(), false)
.anyMatch(unprocessedEntry -> unprocessedEntry.equals(logEntry));
return new LogEntryImportStatus(logEntry, num[0]++, unprocessed);
}).collect(toList());
}).orElse(Lists.newArrayList());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import nl.knaw.huygens.timbuctoo.v5.dataset.dto.DataSet;
import nl.knaw.huygens.timbuctoo.v5.dataset.dto.DataSetMetaData;
import nl.knaw.huygens.timbuctoo.v5.dataset.dto.LogEntry;
import nl.knaw.huygens.timbuctoo.v5.graphql.datafetchers.dto.ContextData;
import nl.knaw.huygens.timbuctoo.v5.graphql.datafetchers.dto.LogEntryImportStatus;
import nl.knaw.huygens.timbuctoo.v5.graphql.mutations.MutationHelpers;
import nl.knaw.huygens.timbuctoo.v5.security.dto.Permission;
Expand All @@ -26,11 +25,10 @@ public ImportStatusFetcher(DataSetRepository dataSetRepository) {

@Override
public LogEntryImportStatus get(DataFetchingEnvironment env) {
User currentUser = env.<ContextData>getContext().getUser()
.orElseThrow(() -> new RuntimeException("You are not logged in"));
Optional<User> user = env.getGraphQlContext().get("user");
User currentUser = user.orElseThrow(() -> new RuntimeException("You are not logged in"));

DataSetMetaData dataSetMetaData = env.getSource();

MutationHelpers.checkPermission(env, dataSetMetaData, Permission.READ_IMPORT_STATUS);

Optional<DataSet> dataSetOpt = dataSetRepository.getDataSet(
Expand All @@ -39,19 +37,19 @@ public LogEntryImportStatus get(DataFetchingEnvironment env) {
dataSetMetaData.getDataSetId()
);

return dataSetOpt.map(dataSet -> dataSet.getImportManager().getLogList())
.map(logList -> {
int id = Integer.parseInt(env.getArgument("id"));
List<LogEntry> entries = logList.getEntries();
if (entries.size() > id) {
LogEntry logEntry = logList.getEntries().get(id);
Iterable<LogEntry> unprocessedEntries = logList::getUnprocessed;
boolean unprocessed = stream(unprocessedEntries.spliterator(), false)
.anyMatch(unprocessedEntry -> unprocessedEntry.equals(logEntry));
return new LogEntryImportStatus(logEntry, id, unprocessed);
}
return null;
}).orElseThrow(() -> new RuntimeException("No import status with id: " + env.getArgument("id")));

return dataSetOpt
.map(dataSet -> dataSet.getImportManager().getLogList())
.map(logList -> {
int id = Integer.parseInt(env.getArgument("id"));
List<LogEntry> entries = logList.getEntries();
if (entries.size() > id) {
LogEntry logEntry = logList.getEntries().get(id);
Iterable<LogEntry> unprocessedEntries = logList::getUnprocessed;
boolean unprocessed = stream(unprocessedEntries.spliterator(), false)
.anyMatch(unprocessedEntry -> unprocessedEntry.equals(logEntry));
return new LogEntryImportStatus(logEntry, id, unprocessed);
}
return null;
}).orElseThrow(() -> new RuntimeException("No import status with id: " + env.getArgument("id")));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
import nl.knaw.huygens.timbuctoo.v5.dataset.dto.DataSet;
import nl.knaw.huygens.timbuctoo.v5.datastores.quadstore.dto.CursorQuad;
import nl.knaw.huygens.timbuctoo.v5.graphql.datafetchers.berkeleydb.dto.LazyTypeSubjectReference;
import nl.knaw.huygens.timbuctoo.v5.graphql.datafetchers.dto.ContextData;
import nl.knaw.huygens.timbuctoo.v5.graphql.datafetchers.dto.DataSetWithDatabase;
import nl.knaw.huygens.timbuctoo.v5.graphql.datafetchers.dto.SubjectGraphReference;
import nl.knaw.huygens.timbuctoo.v5.graphql.datafetchers.dto.SubjectReference;
import nl.knaw.huygens.timbuctoo.v5.graphql.security.UserPermissionCheck;
import nl.knaw.huygens.timbuctoo.v5.security.dto.User;

import java.util.HashSet;
import java.util.List;
Expand All @@ -24,7 +24,6 @@
import static nl.knaw.huygens.timbuctoo.util.Tuple.tuple;

public class OtherDataSetFetcher implements DataFetcher<List<Map>> {

private final DataSetRepository repo;

public OtherDataSetFetcher(DataSetRepository repo) {
Expand All @@ -34,15 +33,16 @@ public OtherDataSetFetcher(DataSetRepository repo) {
@Override
public List<Map> get(DataFetchingEnvironment env) {
if (env.getSource() instanceof SubjectGraphReference) {
final Set<String> dataSetIds = new HashSet<>();
SubjectGraphReference source = env.getSource();
ContextData contextData = env.getContext();
Stream<DataSet> dataSets = contextData.getUser()
Optional<User> optUser = env.getGraphQlContext().get("user");
UserPermissionCheck userPermissionCheck = env.getGraphQlContext().get("userPermissionCheck");

Stream<DataSet> dataSets = optUser
.map(user -> repo.getDataSetsWithReadAccess(user).stream())
.orElseGet(() -> repo.getDataSets().stream().filter(d -> d.getMetadata().isPublished()));

if (env.containsArgument("dataSetIds")) {
dataSetIds.addAll(env.getArgument("dataSetIds"));
final Set<String> dataSetIds = new HashSet<>(env.getArgument("dataSetIds"));
dataSets = dataSets.filter(d -> dataSetIds.contains(d.getMetadata().getCombinedId()));
}
final String ownId = source.getDataSet().getMetadata().getCombinedId();
Expand All @@ -55,13 +55,11 @@ public List<Map> get(DataFetchingEnvironment env) {
})
.filter(i -> i.getRight().isPresent())
.map(i -> ImmutableMap.of(
"metadata", new DataSetWithDatabase(i.getLeft(), env.<ContextData>getContext().getUserPermissionCheck()),
"metadata", new DataSetWithDatabase(i.getLeft(), userPermissionCheck),
"entity", new LazyTypeSubjectReference(i.getRight().get().getSubject(), source.getGraph(), i.getLeft())
))
.collect(toList());

}
return Lists.newArrayList();
}

}
Loading

0 comments on commit e600e77

Please sign in to comment.