Skip to content

Commit

Permalink
Merge pull request #72 from openfga/feat/listrelation-context-context…
Browse files Browse the repository at this point in the history
…ual-tuples

feat: support context and contextual tuples on listrelations
  • Loading branch information
ewanharris authored Apr 9, 2024
2 parents a35b74b + abe0c5e commit 988c3b4
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 1 deletion.
7 changes: 6 additions & 1 deletion src/main/java/dev/openfga/sdk/api/client/OpenFgaClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,9 @@ public CompletableFuture<ClientListObjectsResponse> listObjects(
var bodyContextualTuples = ClientTupleKey.asContextualTupleKeys(contextualTuples);
body.contextualTuples(bodyContextualTuples);
}
if (request.getContext() != null) {
body.context(request.getContext());
}
}

if (options != null && !isNullOrWhitespace(options.getAuthorizationModelId())) {
Expand Down Expand Up @@ -726,7 +729,9 @@ public CompletableFuture<ClientListRelationsResponse> listRelations(
.map(relation -> new ClientCheckRequest()
.user(request.getUser())
.relation(relation)
._object(request.getObject()))
._object(request.getObject())
.contextualTuples(request.getContextualTupleKeys())
.context(request.getContext()))
.collect(Collectors.toList());

return this.batchCheck(batchCheckRequests, options.asClientBatchCheckOptions())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public class ClientListObjectsRequest {
private String relation;
private String type;
private List<ClientTupleKey> contextualTupleKeys;
private Object context;

public ClientListObjectsRequest user(String user) {
this.user = user;
Expand Down Expand Up @@ -63,4 +64,13 @@ public ClientListObjectsRequest contextualTupleKeys(List<ClientTupleKey> context
public List<ClientTupleKey> getContextualTupleKeys() {
return contextualTupleKeys;
}

public ClientListObjectsRequest context(Object context) {
this.context = context;
return this;
}

public Object getContext() {
return context;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public class ClientListRelationsRequest {
private String _object;
private List<String> relations;
private List<ClientTupleKey> contextualTupleKeys;
private Object context;

public ClientListRelationsRequest user(String user) {
this.user = user;
Expand Down Expand Up @@ -63,4 +64,17 @@ public ClientListRelationsRequest contextualTupleKeys(List<ClientTupleKey> conte
public List<ClientTupleKey> getContextualTupleKeys() {
return contextualTupleKeys;
}

public ClientListRelationsRequest context(Object context) {
this.context = context;
return this;
}

/**
* Get context
* @return context
**/
public Object getContext() {
return context;
}
}
72 changes: 72 additions & 0 deletions src/test/java/dev/openfga/sdk/api/client/OpenFgaClientTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1975,6 +1975,30 @@ public void listObjects_500() throws Exception {
"{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseData());
}

@Test
public void listObjectsWithContextTest() throws Exception {
// Given
String postPath = String.format("https://localhost/stores/%s/list-objects", DEFAULT_STORE_ID);
String expectedBody = String.format(
"{\"authorization_model_id\":\"%s\",\"type\":null,\"relation\":\"%s\",\"user\":\"%s\",\"contextual_tuples\":null,\"context\":{\"some\":\"context\"}}",
DEFAULT_AUTH_MODEL_ID, DEFAULT_RELATION, DEFAULT_USER);
mockHttpClient
.onPost(postPath)
.withBody(is(expectedBody))
.doReturn(200, String.format("{\"objects\":[\"%s\"]}", DEFAULT_OBJECT));
ClientListObjectsRequest request = new ClientListObjectsRequest()
.relation(DEFAULT_RELATION)
.user(DEFAULT_USER)
.context(Map.of("some", "context"));

// When
ClientListObjectsResponse response = fga.listObjects(request).get();

// Then
mockHttpClient.verify().post(postPath).withBody(is(expectedBody)).called(1);
assertEquals(List.of(DEFAULT_OBJECT), response.getObjects());
}

/**
* Check whether a user is authorized to access an object.
*/
Expand Down Expand Up @@ -2196,6 +2220,54 @@ public void listRelations_500() throws Exception {
"{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseData());
}

@Test
public void listRelations_contextAndContextualTuples() throws Exception {
// Given
String postUrl = String.format("https://localhost/stores/%s/check", DEFAULT_STORE_ID);
String expectedBody = String.format(
"{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"contextual_tuples\":{\"tuple_keys\":[{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\",\"condition\":null}]},\"authorization_model_id\":\"%s\",\"trace\":null,\"context\":{\"some\":\"context\"}}",
DEFAULT_USER,
"owner",
DEFAULT_OBJECT,
DEFAULT_USER,
DEFAULT_RELATION,
DEFAULT_OBJECT,
DEFAULT_AUTH_MODEL_ID);
mockHttpClient
.onPost(postUrl)
.withBody(is(expectedBody))
.withHeader(CLIENT_METHOD_HEADER, "BatchCheck")
.withHeader(CLIENT_BULK_REQUEST_ID_HEADER, anyValidUUID())
.doReturn(200, "{\"allowed\":false}");
ClientListRelationsRequest request = new ClientListRelationsRequest()
.relations(List.of("owner"))
._object(DEFAULT_OBJECT)
.user(DEFAULT_USER)
.context(Map.of("some", "context"))
.contextualTupleKeys(List.of(new ClientTupleKey()
.user(DEFAULT_USER)
.relation(DEFAULT_RELATION)
._object(DEFAULT_OBJECT)));
ClientListRelationsOptions options =
new ClientListRelationsOptions().authorizationModelId(DEFAULT_AUTH_MODEL_ID);

// When
ClientListRelationsResponse response =
fga.listRelations(request, options).get();

// Then
mockHttpClient
.verify()
.post(postUrl)
.withBody(is(expectedBody))
.withHeader(CLIENT_METHOD_HEADER, "BatchCheck")
.withHeader(CLIENT_BULK_REQUEST_ID_HEADER, anyValidUUID())
.called(1);
assertNotNull(response);
assertNotNull(response.getRelations());
assertTrue(response.getRelations().isEmpty());
}

/**
* Read assertions for an authorization model ID.
*/
Expand Down

0 comments on commit 988c3b4

Please sign in to comment.