Skip to content

Commit 988c3b4

Browse files
authored
Merge pull request #72 from openfga/feat/listrelation-context-contextual-tuples
feat: support context and contextual tuples on listrelations
2 parents a35b74b + abe0c5e commit 988c3b4

File tree

4 files changed

+102
-1
lines changed

4 files changed

+102
-1
lines changed

src/main/java/dev/openfga/sdk/api/client/OpenFgaClient.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,9 @@ public CompletableFuture<ClientListObjectsResponse> listObjects(
679679
var bodyContextualTuples = ClientTupleKey.asContextualTupleKeys(contextualTuples);
680680
body.contextualTuples(bodyContextualTuples);
681681
}
682+
if (request.getContext() != null) {
683+
body.context(request.getContext());
684+
}
682685
}
683686

684687
if (options != null && !isNullOrWhitespace(options.getAuthorizationModelId())) {
@@ -726,7 +729,9 @@ public CompletableFuture<ClientListRelationsResponse> listRelations(
726729
.map(relation -> new ClientCheckRequest()
727730
.user(request.getUser())
728731
.relation(relation)
729-
._object(request.getObject()))
732+
._object(request.getObject())
733+
.contextualTuples(request.getContextualTupleKeys())
734+
.context(request.getContext()))
730735
.collect(Collectors.toList());
731736

732737
return this.batchCheck(batchCheckRequests, options.asClientBatchCheckOptions())

src/main/java/dev/openfga/sdk/api/client/model/ClientListObjectsRequest.java

+10
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public class ClientListObjectsRequest {
1919
private String relation;
2020
private String type;
2121
private List<ClientTupleKey> contextualTupleKeys;
22+
private Object context;
2223

2324
public ClientListObjectsRequest user(String user) {
2425
this.user = user;
@@ -63,4 +64,13 @@ public ClientListObjectsRequest contextualTupleKeys(List<ClientTupleKey> context
6364
public List<ClientTupleKey> getContextualTupleKeys() {
6465
return contextualTupleKeys;
6566
}
67+
68+
public ClientListObjectsRequest context(Object context) {
69+
this.context = context;
70+
return this;
71+
}
72+
73+
public Object getContext() {
74+
return context;
75+
}
6676
}

src/main/java/dev/openfga/sdk/api/client/model/ClientListRelationsRequest.java

+14
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public class ClientListRelationsRequest {
1919
private String _object;
2020
private List<String> relations;
2121
private List<ClientTupleKey> contextualTupleKeys;
22+
private Object context;
2223

2324
public ClientListRelationsRequest user(String user) {
2425
this.user = user;
@@ -63,4 +64,17 @@ public ClientListRelationsRequest contextualTupleKeys(List<ClientTupleKey> conte
6364
public List<ClientTupleKey> getContextualTupleKeys() {
6465
return contextualTupleKeys;
6566
}
67+
68+
public ClientListRelationsRequest context(Object context) {
69+
this.context = context;
70+
return this;
71+
}
72+
73+
/**
74+
* Get context
75+
* @return context
76+
**/
77+
public Object getContext() {
78+
return context;
79+
}
6680
}

src/test/java/dev/openfga/sdk/api/client/OpenFgaClientTest.java

+72
Original file line numberDiff line numberDiff line change
@@ -1975,6 +1975,30 @@ public void listObjects_500() throws Exception {
19751975
"{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseData());
19761976
}
19771977

1978+
@Test
1979+
public void listObjectsWithContextTest() throws Exception {
1980+
// Given
1981+
String postPath = String.format("https://localhost/stores/%s/list-objects", DEFAULT_STORE_ID);
1982+
String expectedBody = String.format(
1983+
"{\"authorization_model_id\":\"%s\",\"type\":null,\"relation\":\"%s\",\"user\":\"%s\",\"contextual_tuples\":null,\"context\":{\"some\":\"context\"}}",
1984+
DEFAULT_AUTH_MODEL_ID, DEFAULT_RELATION, DEFAULT_USER);
1985+
mockHttpClient
1986+
.onPost(postPath)
1987+
.withBody(is(expectedBody))
1988+
.doReturn(200, String.format("{\"objects\":[\"%s\"]}", DEFAULT_OBJECT));
1989+
ClientListObjectsRequest request = new ClientListObjectsRequest()
1990+
.relation(DEFAULT_RELATION)
1991+
.user(DEFAULT_USER)
1992+
.context(Map.of("some", "context"));
1993+
1994+
// When
1995+
ClientListObjectsResponse response = fga.listObjects(request).get();
1996+
1997+
// Then
1998+
mockHttpClient.verify().post(postPath).withBody(is(expectedBody)).called(1);
1999+
assertEquals(List.of(DEFAULT_OBJECT), response.getObjects());
2000+
}
2001+
19782002
/**
19792003
* Check whether a user is authorized to access an object.
19802004
*/
@@ -2196,6 +2220,54 @@ public void listRelations_500() throws Exception {
21962220
"{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseData());
21972221
}
21982222

2223+
@Test
2224+
public void listRelations_contextAndContextualTuples() throws Exception {
2225+
// Given
2226+
String postUrl = String.format("https://localhost/stores/%s/check", DEFAULT_STORE_ID);
2227+
String expectedBody = String.format(
2228+
"{\"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\"}}",
2229+
DEFAULT_USER,
2230+
"owner",
2231+
DEFAULT_OBJECT,
2232+
DEFAULT_USER,
2233+
DEFAULT_RELATION,
2234+
DEFAULT_OBJECT,
2235+
DEFAULT_AUTH_MODEL_ID);
2236+
mockHttpClient
2237+
.onPost(postUrl)
2238+
.withBody(is(expectedBody))
2239+
.withHeader(CLIENT_METHOD_HEADER, "BatchCheck")
2240+
.withHeader(CLIENT_BULK_REQUEST_ID_HEADER, anyValidUUID())
2241+
.doReturn(200, "{\"allowed\":false}");
2242+
ClientListRelationsRequest request = new ClientListRelationsRequest()
2243+
.relations(List.of("owner"))
2244+
._object(DEFAULT_OBJECT)
2245+
.user(DEFAULT_USER)
2246+
.context(Map.of("some", "context"))
2247+
.contextualTupleKeys(List.of(new ClientTupleKey()
2248+
.user(DEFAULT_USER)
2249+
.relation(DEFAULT_RELATION)
2250+
._object(DEFAULT_OBJECT)));
2251+
ClientListRelationsOptions options =
2252+
new ClientListRelationsOptions().authorizationModelId(DEFAULT_AUTH_MODEL_ID);
2253+
2254+
// When
2255+
ClientListRelationsResponse response =
2256+
fga.listRelations(request, options).get();
2257+
2258+
// Then
2259+
mockHttpClient
2260+
.verify()
2261+
.post(postUrl)
2262+
.withBody(is(expectedBody))
2263+
.withHeader(CLIENT_METHOD_HEADER, "BatchCheck")
2264+
.withHeader(CLIENT_BULK_REQUEST_ID_HEADER, anyValidUUID())
2265+
.called(1);
2266+
assertNotNull(response);
2267+
assertNotNull(response.getRelations());
2268+
assertTrue(response.getRelations().isEmpty());
2269+
}
2270+
21992271
/**
22002272
* Read assertions for an authorization model ID.
22012273
*/

0 commit comments

Comments
 (0)