From 10ce677540f3c189e54cbe82bf50b1cd5c3ad1f7 Mon Sep 17 00:00:00 2001 From: Ewan Harris Date: Wed, 1 May 2024 15:01:52 +0100 Subject: [PATCH 1/2] feat: support list users --- .openapi-generator/FILES | 23 ++ README.md | 75 +++- docs/FgaObject.md | 15 + docs/ListUsersRequest.md | 18 + docs/ListUsersResponse.md | 14 + docs/ObjectOrUserset.md | 14 + docs/OpenFgaApi.md | 201 +++++++++- docs/TypedWildcard.md | 14 + docs/UnprocessableContentErrorCode.md | 15 + docs/UnprocessableContentMessageResponse.md | 14 + docs/User.md | 16 + docs/UserTypeFilter.md | 14 + docs/UsersetUser.md | 16 + .../java/dev/openfga/sdk/api/OpenFgaApi.java | 61 ++- .../openfga/sdk/api/client/OpenFgaClient.java | 42 ++ .../client/model/ClientListUsersRequest.java | 86 +++++ .../client/model/ClientListUsersResponse.java | 45 +++ .../configuration/ClientListUsersOptions.java | 39 ++ .../dev/openfga/sdk/api/model/FgaObject.java | 175 +++++++++ .../sdk/api/model/ListUsersRequest.java | 362 ++++++++++++++++++ .../sdk/api/model/ListUsersResponse.java | 206 ++++++++++ .../sdk/api/model/ObjectOrUserset.java | 164 ++++++++ .../openfga/sdk/api/model/TypedWildcard.java | 139 +++++++ .../model/UnprocessableContentErrorCode.java | 67 ++++ .../UnprocessableContentMessageResponse.java | 180 +++++++++ .../java/dev/openfga/sdk/api/model/User.java | 196 ++++++++++ .../openfga/sdk/api/model/UserTypeFilter.java | 175 +++++++++ .../openfga/sdk/api/model/UsersetUser.java | 213 +++++++++++ .../sdk/api/client/OpenFgaClientTest.java | 49 ++- 29 files changed, 2630 insertions(+), 18 deletions(-) create mode 100644 docs/FgaObject.md create mode 100644 docs/ListUsersRequest.md create mode 100644 docs/ListUsersResponse.md create mode 100644 docs/ObjectOrUserset.md create mode 100644 docs/TypedWildcard.md create mode 100644 docs/UnprocessableContentErrorCode.md create mode 100644 docs/UnprocessableContentMessageResponse.md create mode 100644 docs/User.md create mode 100644 docs/UserTypeFilter.md create mode 100644 docs/UsersetUser.md create mode 100644 src/main/java/dev/openfga/sdk/api/client/model/ClientListUsersRequest.java create mode 100644 src/main/java/dev/openfga/sdk/api/client/model/ClientListUsersResponse.java create mode 100644 src/main/java/dev/openfga/sdk/api/configuration/ClientListUsersOptions.java create mode 100644 src/main/java/dev/openfga/sdk/api/model/FgaObject.java create mode 100644 src/main/java/dev/openfga/sdk/api/model/ListUsersRequest.java create mode 100644 src/main/java/dev/openfga/sdk/api/model/ListUsersResponse.java create mode 100644 src/main/java/dev/openfga/sdk/api/model/ObjectOrUserset.java create mode 100644 src/main/java/dev/openfga/sdk/api/model/TypedWildcard.java create mode 100644 src/main/java/dev/openfga/sdk/api/model/UnprocessableContentErrorCode.java create mode 100644 src/main/java/dev/openfga/sdk/api/model/UnprocessableContentMessageResponse.java create mode 100644 src/main/java/dev/openfga/sdk/api/model/User.java create mode 100644 src/main/java/dev/openfga/sdk/api/model/UserTypeFilter.java create mode 100644 src/main/java/dev/openfga/sdk/api/model/UsersetUser.java diff --git a/.openapi-generator/FILES b/.openapi-generator/FILES index 85e1fe0..388e4a2 100644 --- a/.openapi-generator/FILES +++ b/.openapi-generator/FILES @@ -36,6 +36,7 @@ docs/ErrorCode.md docs/ExpandRequest.md docs/ExpandRequestTupleKey.md docs/ExpandResponse.md +docs/FgaObject.md docs/GetStoreResponse.md docs/InternalErrorCode.md docs/InternalErrorMessageResponse.md @@ -43,11 +44,14 @@ docs/Leaf.md docs/ListObjectsRequest.md docs/ListObjectsResponse.md docs/ListStoresResponse.md +docs/ListUsersRequest.md +docs/ListUsersResponse.md docs/Metadata.md docs/Node.md docs/Nodes.md docs/NotFoundErrorCode.md docs/NullValue.md +docs/ObjectOrUserset.md docs/ObjectRelation.md docs/OpenFgaApi.md docs/PathUnknownErrorMessageResponse.md @@ -72,11 +76,17 @@ docs/TupleOperation.md docs/TupleToUserset.md docs/TypeDefinition.md docs/TypeName.md +docs/TypedWildcard.md +docs/UnprocessableContentErrorCode.md +docs/UnprocessableContentMessageResponse.md +docs/User.md +docs/UserTypeFilter.md docs/Users.md docs/Userset.md docs/UsersetTree.md docs/UsersetTreeDifference.md docs/UsersetTreeTupleToUserset.md +docs/UsersetUser.md docs/Usersets.md docs/ValidationErrorMessageResponse.md docs/WriteAssertionsRequest.md @@ -127,6 +137,8 @@ src/main/java/dev/openfga/sdk/api/client/model/ClientListObjectsResponse.java src/main/java/dev/openfga/sdk/api/client/model/ClientListRelationsRequest.java src/main/java/dev/openfga/sdk/api/client/model/ClientListRelationsResponse.java src/main/java/dev/openfga/sdk/api/client/model/ClientListStoresResponse.java +src/main/java/dev/openfga/sdk/api/client/model/ClientListUsersRequest.java +src/main/java/dev/openfga/sdk/api/client/model/ClientListUsersResponse.java src/main/java/dev/openfga/sdk/api/client/model/ClientReadAssertionsResponse.java src/main/java/dev/openfga/sdk/api/client/model/ClientReadAuthorizationModelResponse.java src/main/java/dev/openfga/sdk/api/client/model/ClientReadAuthorizationModelsResponse.java @@ -156,6 +168,7 @@ src/main/java/dev/openfga/sdk/api/configuration/ClientGetStoreOptions.java src/main/java/dev/openfga/sdk/api/configuration/ClientListObjectsOptions.java src/main/java/dev/openfga/sdk/api/configuration/ClientListRelationsOptions.java src/main/java/dev/openfga/sdk/api/configuration/ClientListStoresOptions.java +src/main/java/dev/openfga/sdk/api/configuration/ClientListUsersOptions.java src/main/java/dev/openfga/sdk/api/configuration/ClientReadAssertionsOptions.java src/main/java/dev/openfga/sdk/api/configuration/ClientReadAuthorizationModelOptions.java src/main/java/dev/openfga/sdk/api/configuration/ClientReadAuthorizationModelsOptions.java @@ -191,6 +204,7 @@ src/main/java/dev/openfga/sdk/api/model/ErrorCode.java src/main/java/dev/openfga/sdk/api/model/ExpandRequest.java src/main/java/dev/openfga/sdk/api/model/ExpandRequestTupleKey.java src/main/java/dev/openfga/sdk/api/model/ExpandResponse.java +src/main/java/dev/openfga/sdk/api/model/FgaObject.java src/main/java/dev/openfga/sdk/api/model/GetStoreResponse.java src/main/java/dev/openfga/sdk/api/model/InternalErrorCode.java src/main/java/dev/openfga/sdk/api/model/InternalErrorMessageResponse.java @@ -198,11 +212,14 @@ src/main/java/dev/openfga/sdk/api/model/Leaf.java src/main/java/dev/openfga/sdk/api/model/ListObjectsRequest.java src/main/java/dev/openfga/sdk/api/model/ListObjectsResponse.java src/main/java/dev/openfga/sdk/api/model/ListStoresResponse.java +src/main/java/dev/openfga/sdk/api/model/ListUsersRequest.java +src/main/java/dev/openfga/sdk/api/model/ListUsersResponse.java src/main/java/dev/openfga/sdk/api/model/Metadata.java src/main/java/dev/openfga/sdk/api/model/Node.java src/main/java/dev/openfga/sdk/api/model/Nodes.java src/main/java/dev/openfga/sdk/api/model/NotFoundErrorCode.java src/main/java/dev/openfga/sdk/api/model/NullValue.java +src/main/java/dev/openfga/sdk/api/model/ObjectOrUserset.java src/main/java/dev/openfga/sdk/api/model/ObjectRelation.java src/main/java/dev/openfga/sdk/api/model/PathUnknownErrorMessageResponse.java src/main/java/dev/openfga/sdk/api/model/ReadAssertionsResponse.java @@ -226,11 +243,17 @@ src/main/java/dev/openfga/sdk/api/model/TupleOperation.java src/main/java/dev/openfga/sdk/api/model/TupleToUserset.java src/main/java/dev/openfga/sdk/api/model/TypeDefinition.java src/main/java/dev/openfga/sdk/api/model/TypeName.java +src/main/java/dev/openfga/sdk/api/model/TypedWildcard.java +src/main/java/dev/openfga/sdk/api/model/UnprocessableContentErrorCode.java +src/main/java/dev/openfga/sdk/api/model/UnprocessableContentMessageResponse.java +src/main/java/dev/openfga/sdk/api/model/User.java +src/main/java/dev/openfga/sdk/api/model/UserTypeFilter.java src/main/java/dev/openfga/sdk/api/model/Users.java src/main/java/dev/openfga/sdk/api/model/Userset.java src/main/java/dev/openfga/sdk/api/model/UsersetTree.java src/main/java/dev/openfga/sdk/api/model/UsersetTreeDifference.java src/main/java/dev/openfga/sdk/api/model/UsersetTreeTupleToUserset.java +src/main/java/dev/openfga/sdk/api/model/UsersetUser.java src/main/java/dev/openfga/sdk/api/model/Usersets.java src/main/java/dev/openfga/sdk/api/model/ValidationErrorMessageResponse.java src/main/java/dev/openfga/sdk/api/model/WriteAssertionsRequest.java diff --git a/README.md b/README.md index aec3941..af94ea0 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ This is an autogenerated Java SDK for OpenFGA. It provides a wrapper around the - [Expand](#expand) - [List Objects](#list-objects) - [List Relations](#list-relations) + - [List Users](#list-users) - [Assertions](#assertions) - [Read Assertions](#read-assertions) - [Write Assertions](#write-assertions) @@ -136,7 +137,7 @@ public class Example { var config = new ClientConfiguration() .apiUrl(System.getenv("FGA_API_URL")) // If not specified, will default to "http://localhost:8080" .storeId(System.getenv("FGA_STORE_ID")) // Not required when calling createStore() or listStores() - .authorizationModelId(System.getenv("FGA_AUTHORIZATION_MODEL_ID")); // Optional, can be overridden per request + .authorizationModelId(System.getenv("FGA_MODEL_ID")); // Optional, can be overridden per request var fgaClient = new OpenFgaClient(config); var response = fgaClient.readAuthorizationModels().get(); @@ -159,7 +160,7 @@ public class Example { var config = new ClientConfiguration() .apiUrl(System.getenv("FGA_API_URL")) // If not specified, will default to "http://localhost:8080" .storeId(System.getenv("FGA_STORE_ID")) // Not required when calling createStore() or listStores() - .authorizationModelId(System.getenv("FGA_AUTHORIZATION_MODEL_ID")) // Optional, can be overridden per request + .authorizationModelId(System.getenv("FGA_MODEL_ID")) // Optional, can be overridden per request .credentials(new Credentials( new ApiToken(System.getenv("FGA_API_TOKEN")) // will be passed as the "Authorization: Bearer ${ApiToken}" request header )); @@ -185,7 +186,7 @@ public class Example { var config = new ClientConfiguration() .apiUrl(System.getenv("FGA_API_URL")) // If not specified, will default to "http://localhost:8080" .storeId(System.getenv("FGA_STORE_ID")) // Not required when calling createStore() or listStores() - .authorizationModelId(System.getenv("FGA_AUTHORIZATION_MODEL_ID")) // Optional, can be overridden per request + .authorizationModelId(System.getenv("FGA_MODEL_ID")) // Optional, can be overridden per request .credentials(new Credentials( new ClientCredentials() .apiTokenIssuer(System.getenv("FGA_API_TOKEN_ISSUER")) @@ -215,7 +216,7 @@ public class Example { var config = new ClientConfiguration() .apiUrl(System.getenv("FGA_API_URL")) // If not specified, will default to "http://localhost:8080" .storeId(System.getenv("FGA_STORE_ID")) // Not required when calling createStore() or listStores() - .authorizationModelId(System.getenv("FGA_AUTHORIZATION_MODEL_ID")) // Optional, can be overridden per request + .authorizationModelId(System.getenv("FGA_MODEL_ID")) // Optional, can be overridden per request .credentials(new Credentials( new ClientCredentials() .apiTokenIssuer(System.getenv("FGA_API_TOKEN_ISSUER")) @@ -765,6 +766,49 @@ var response = fgaClient.listRelations(request, options).get(); // response.getRelations() = ["can_view", "can_edit"] ``` +##### List Users + +List the users who have a certain relation to a particular type. + +[API Documentation](https://openfga.dev/api/service#/Relationship%20Queries/ListUsers) + +```java +// Only a single filter is allowed for the time being +var userFilters = new ArrayList() { + { + add(new UserTypeFilter().type("user")); + // user filters can also be of the form + // add(new UserTypeFilter().type("team").relation("member")); + } +}; + +var request = new ClientListUsersRequest() + ._object(new FgaObject().type("document").id("roadmap")) + .relation("can_read") + .userFilters(userFilters) + .context(Map.of("view_count", 100)) + .contextualTupleKeys(List.of( + new ClientTupleKey() + .user("user:81684243-9356-4421-8fbf-a4f8d36aa31b") + .relation("editor") + ._object("folder:product"), + new ClientTupleKey() + .user("folder:product") + .relation("parent") + ._object("document:roadmap") +)); + +var options = new ClientListUsersOptions() + .additionalHeaders(Map.of("Some-Http-Header", "Some value")) + // You can rely on the model id set in the configuration or override it for this specific request + .authorizationModelId("01GXSA8YR785C4FYS3C0RTG7B1"); + +var response = fgaClient.listUsers(request, options).get(); + +// response.getUsers() = [{object: {type: "user", id: "81684243-9356-4421-8fbf-a4f8d36aa31b"}}, {userset: { type: "user" }}, ...] +// response.getExcludedUsers = [ {object: {type: "user", id: "4a455e27-d15a-4434-82e0-136f9c2aa4cf"}}, ... ] +``` + #### Assertions ##### Read Assertions @@ -823,7 +867,7 @@ public class Example { var config = new ClientConfiguration() .apiUrl(System.getenv("FGA_API_URL")) // If not specified, will default to "http://localhost:8080" .storeId(System.getenv("FGA_STORE_ID")) // Not required when calling createStore() or listStores() - .authorizationModelId(System.getenv("FGA_AUTHORIZATION_MODEL_ID")) // Optional, can be overridden per request + .authorizationModelId(System.getenv("FGA_MODEL_ID")) // Optional, can be overridden per request .maxRetries(3) // retry up to 3 times on API requests .minimumRetryDelay(250); // wait a minimum of 250 milliseconds between requests @@ -844,6 +888,7 @@ public class Example { | [**getStore**](docs/OpenFgaApi.md#getstore) | **GET** /stores/{store_id} | Get a store | | [**listObjects**](docs/OpenFgaApi.md#listobjects) | **POST** /stores/{store_id}/list-objects | List all objects of the given type that the user has a relation with | | [**listStores**](docs/OpenFgaApi.md#liststores) | **GET** /stores | List all stores | +| [**listUsers**](docs/OpenFgaApi.md#listusers) | **POST** /stores/{store_id}/list-users | List the users matching the provided filter who have a certain relation to a particular type. | | [**read**](docs/OpenFgaApi.md#read) | **POST** /stores/{store_id}/read | Get tuples from the store that matches a query, without following userset rewrite rules | | [**readAssertions**](docs/OpenFgaApi.md#readassertions) | **GET** /stores/{store_id}/assertions/{authorization_model_id} | Read assertions for an authorization model ID | | [**readAuthorizationModel**](docs/OpenFgaApi.md#readauthorizationmodel) | **GET** /stores/{store_id}/authorization-models/{id} | Return a particular version of an authorization model | @@ -898,6 +943,8 @@ public class Example { - [ExpandResponse](https://github.com/openfga/java-sdk/blob/main/docs/ExpandResponse.md) +- [FgaObject](https://github.com/openfga/java-sdk/blob/main/docs/FgaObject.md) + - [GetStoreResponse](https://github.com/openfga/java-sdk/blob/main/docs/GetStoreResponse.md) - [InternalErrorCode](https://github.com/openfga/java-sdk/blob/main/docs/InternalErrorCode.md) @@ -912,6 +959,10 @@ public class Example { - [ListStoresResponse](https://github.com/openfga/java-sdk/blob/main/docs/ListStoresResponse.md) +- [ListUsersRequest](https://github.com/openfga/java-sdk/blob/main/docs/ListUsersRequest.md) + +- [ListUsersResponse](https://github.com/openfga/java-sdk/blob/main/docs/ListUsersResponse.md) + - [Metadata](https://github.com/openfga/java-sdk/blob/main/docs/Metadata.md) - [Node](https://github.com/openfga/java-sdk/blob/main/docs/Node.md) @@ -922,6 +973,8 @@ public class Example { - [NullValue](https://github.com/openfga/java-sdk/blob/main/docs/NullValue.md) +- [ObjectOrUserset](https://github.com/openfga/java-sdk/blob/main/docs/ObjectOrUserset.md) + - [ObjectRelation](https://github.com/openfga/java-sdk/blob/main/docs/ObjectRelation.md) - [PathUnknownErrorMessageResponse](https://github.com/openfga/java-sdk/blob/main/docs/PathUnknownErrorMessageResponse.md) @@ -968,6 +1021,16 @@ public class Example { - [TypeName](https://github.com/openfga/java-sdk/blob/main/docs/TypeName.md) +- [TypedWildcard](https://github.com/openfga/java-sdk/blob/main/docs/TypedWildcard.md) + +- [UnprocessableContentErrorCode](https://github.com/openfga/java-sdk/blob/main/docs/UnprocessableContentErrorCode.md) + +- [UnprocessableContentMessageResponse](https://github.com/openfga/java-sdk/blob/main/docs/UnprocessableContentMessageResponse.md) + +- [User](https://github.com/openfga/java-sdk/blob/main/docs/User.md) + +- [UserTypeFilter](https://github.com/openfga/java-sdk/blob/main/docs/UserTypeFilter.md) + - [Users](https://github.com/openfga/java-sdk/blob/main/docs/Users.md) - [Userset](https://github.com/openfga/java-sdk/blob/main/docs/Userset.md) @@ -978,6 +1041,8 @@ public class Example { - [UsersetTreeTupleToUserset](https://github.com/openfga/java-sdk/blob/main/docs/UsersetTreeTupleToUserset.md) +- [UsersetUser](https://github.com/openfga/java-sdk/blob/main/docs/UsersetUser.md) + - [Usersets](https://github.com/openfga/java-sdk/blob/main/docs/Usersets.md) - [ValidationErrorMessageResponse](https://github.com/openfga/java-sdk/blob/main/docs/ValidationErrorMessageResponse.md) diff --git a/docs/FgaObject.md b/docs/FgaObject.md new file mode 100644 index 0000000..e9309ea --- /dev/null +++ b/docs/FgaObject.md @@ -0,0 +1,15 @@ + + +# FgaObject + +Object represents an OpenFGA Object. An Object is composed of a type and identifier (e.g. 'document:1') See https://openfga.dev/docs/concepts#what-is-an-object + +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +|**type** | **String** | | | +|**id** | **String** | | | + + + diff --git a/docs/ListUsersRequest.md b/docs/ListUsersRequest.md new file mode 100644 index 0000000..2350bfd --- /dev/null +++ b/docs/ListUsersRequest.md @@ -0,0 +1,18 @@ + + +# ListUsersRequest + + +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +|**authorizationModelId** | **String** | | [optional] | +|**_object** | [**FgaObject**](FgaObject.md) | | | +|**relation** | **String** | | | +|**userFilters** | [**List<UserTypeFilter>**](UserTypeFilter.md) | The type of results returned. Only accepts exactly one value. | | +|**contextualTuples** | [**List<TupleKey>**](TupleKey.md) | | [optional] | +|**context** | **Object** | Additional request context that will be used to evaluate any ABAC conditions encountered in the query evaluation. | [optional] | + + + diff --git a/docs/ListUsersResponse.md b/docs/ListUsersResponse.md new file mode 100644 index 0000000..5da7fe1 --- /dev/null +++ b/docs/ListUsersResponse.md @@ -0,0 +1,14 @@ + + +# ListUsersResponse + + +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +|**users** | [**List<User>**](User.md) | | | +|**excludedUsers** | [**List<ObjectOrUserset>**](ObjectOrUserset.md) | | | + + + diff --git a/docs/ObjectOrUserset.md b/docs/ObjectOrUserset.md new file mode 100644 index 0000000..8b7c942 --- /dev/null +++ b/docs/ObjectOrUserset.md @@ -0,0 +1,14 @@ + + +# ObjectOrUserset + + +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +|**_object** | [**FgaObject**](FgaObject.md) | | [optional] | +|**userset** | [**UsersetUser**](UsersetUser.md) | | [optional] | + + + diff --git a/docs/OpenFgaApi.md b/docs/OpenFgaApi.md index 2beccb2..52c5138 100644 --- a/docs/OpenFgaApi.md +++ b/docs/OpenFgaApi.md @@ -18,6 +18,8 @@ All URIs are relative to *http://localhost* | [**listObjectsWithHttpInfo**](OpenFgaApi.md#listObjectsWithHttpInfo) | **POST** /stores/{store_id}/list-objects | List all objects of the given type that the user has a relation with | | [**listStores**](OpenFgaApi.md#listStores) | **GET** /stores | List all stores | | [**listStoresWithHttpInfo**](OpenFgaApi.md#listStoresWithHttpInfo) | **GET** /stores | List all stores | +| [**listUsers**](OpenFgaApi.md#listUsers) | **POST** /stores/{store_id}/list-users | List the users matching the provided filter who have a certain relation to a particular type. | +| [**listUsersWithHttpInfo**](OpenFgaApi.md#listUsersWithHttpInfo) | **POST** /stores/{store_id}/list-users | List the users matching the provided filter who have a certain relation to a particular type. | | [**read**](OpenFgaApi.md#read) | **POST** /stores/{store_id}/read | Get tuples from the store that matches a query, without following userset rewrite rules | | [**readWithHttpInfo**](OpenFgaApi.md#readWithHttpInfo) | **POST** /stores/{store_id}/read | Get tuples from the store that matches a query, without following userset rewrite rules | | [**readAssertions**](OpenFgaApi.md#readAssertions) | **GET** /stores/{store_id}/assertions/{authorization_model_id} | Read assertions for an authorization model ID | @@ -43,7 +45,7 @@ All URIs are relative to *http://localhost* Check whether a user is authorized to access an object -The Check API queries to check if the user has a certain relationship with an object in a certain store. A `contextual_tuples` object may also be included in the body of the request. This object contains one field `tuple_keys`, which is an array of tuple keys. Each of these tuples may have an associated `condition`. You may also provide an `authorization_model_id` in the body. This will be used to assert that the input `tuple_key` is valid for the model specified. If not specified, the assertion will be made against the latest authorization model ID. It is strongly recommended to specify authorization model id for better performance. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will return whether the relationship exists in the field `allowed`. ## Example In order to check if user `user:anne` of type `user` has a `reader` relationship with object `document:2021-budget` given the following contextual tuple ```json { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ``` the Check API can be used with the following request body: ```json { \"tuple_key\": { \"user\": \"user:anne\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ] }, \"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\" } ``` OpenFGA's response will include `{ \"allowed\": true }` if there is a relationship and `{ \"allowed\": false }` if there isn't. +The Check API returns whether a given user has a relationship with a given object in a given store. The `user` field of the request can be a specific target, such as `user:anne`, or a userset (set of users) such as `group:marketing#member` or a type-bound public access `user:*`. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). A `contextual_tuples` object may also be included in the body of the request. This object contains one field `tuple_keys`, which is an array of tuple keys. Each of these tuples may have an associated `condition`. You may also provide an `authorization_model_id` in the body. This will be used to assert that the input `tuple_key` is valid for the model specified. If not specified, the assertion will be made against the latest authorization model ID. It is strongly recommended to specify authorization model id for better performance. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will return whether the relationship exists in the field `allowed`. Some exceptions apply, but in general, if a Check API responds with `{allowed: true}`, then you can expect the equivalent ListObjects query to return the object, and viceversa. For example, if `Check(user:anne, reader, document:2021-budget)` responds with `{allowed: true}`, then `ListObjects(user:anne, reader, document)` may include `document:2021-budget` in the response. ## Examples ### Querying with contextual tuples In order to check if user `user:anne` of type `user` has a `reader` relationship with object `document:2021-budget` given the following contextual tuple ```json { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ``` the Check API can be used with the following request body: ```json { \"tuple_key\": { \"user\": \"user:anne\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ] }, \"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\" } ``` ### Querying usersets Some Checks will always return `true`, even without any tuples. For example, for the following authorization model ```python model schema 1.1 type user type document relations define reader: [user] ``` the following query ```json { \"tuple_key\": { \"user\": \"document:2021-budget#reader\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" } } ``` will always return `{ \"allowed\": true }`. This is because usersets are self-defining: the userset `document:2021-budget#reader` will always have the `reader` relation with `document:2021-budget`. ### Querying usersets with exclusion in the model A Check for a userset can yield results that must be treated carefully if the model involves exclusion. For example, for the following authorization model ```python model schema 1.1 type user type group relations define member: [user] type document relations define blocked: [user] define reader: [group#member] but not blocked ``` the following query ```json { \"tuple_key\": { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"group:finance\" }, { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, { \"user\": \"user:anne\", \"relation\": \"blocked\", \"object\": \"document:2021-budget\" } ] }, } ``` will return `{ \"allowed\": true }`, even though a specific user of the userset `group:finance#member` does not have the `reader` relationship with the given object. ### Example @@ -107,6 +109,7 @@ No authorization required | **400** | Request failed due to invalid input. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | | **500** | Request failed due to internal server error. | - | ## checkWithHttpInfo @@ -115,7 +118,7 @@ No authorization required Check whether a user is authorized to access an object -The Check API queries to check if the user has a certain relationship with an object in a certain store. A `contextual_tuples` object may also be included in the body of the request. This object contains one field `tuple_keys`, which is an array of tuple keys. Each of these tuples may have an associated `condition`. You may also provide an `authorization_model_id` in the body. This will be used to assert that the input `tuple_key` is valid for the model specified. If not specified, the assertion will be made against the latest authorization model ID. It is strongly recommended to specify authorization model id for better performance. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will return whether the relationship exists in the field `allowed`. ## Example In order to check if user `user:anne` of type `user` has a `reader` relationship with object `document:2021-budget` given the following contextual tuple ```json { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ``` the Check API can be used with the following request body: ```json { \"tuple_key\": { \"user\": \"user:anne\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ] }, \"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\" } ``` OpenFGA's response will include `{ \"allowed\": true }` if there is a relationship and `{ \"allowed\": false }` if there isn't. +The Check API returns whether a given user has a relationship with a given object in a given store. The `user` field of the request can be a specific target, such as `user:anne`, or a userset (set of users) such as `group:marketing#member` or a type-bound public access `user:*`. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). A `contextual_tuples` object may also be included in the body of the request. This object contains one field `tuple_keys`, which is an array of tuple keys. Each of these tuples may have an associated `condition`. You may also provide an `authorization_model_id` in the body. This will be used to assert that the input `tuple_key` is valid for the model specified. If not specified, the assertion will be made against the latest authorization model ID. It is strongly recommended to specify authorization model id for better performance. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will return whether the relationship exists in the field `allowed`. Some exceptions apply, but in general, if a Check API responds with `{allowed: true}`, then you can expect the equivalent ListObjects query to return the object, and viceversa. For example, if `Check(user:anne, reader, document:2021-budget)` responds with `{allowed: true}`, then `ListObjects(user:anne, reader, document)` may include `document:2021-budget` in the response. ## Examples ### Querying with contextual tuples In order to check if user `user:anne` of type `user` has a `reader` relationship with object `document:2021-budget` given the following contextual tuple ```json { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ``` the Check API can be used with the following request body: ```json { \"tuple_key\": { \"user\": \"user:anne\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ] }, \"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\" } ``` ### Querying usersets Some Checks will always return `true`, even without any tuples. For example, for the following authorization model ```python model schema 1.1 type user type document relations define reader: [user] ``` the following query ```json { \"tuple_key\": { \"user\": \"document:2021-budget#reader\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" } } ``` will always return `{ \"allowed\": true }`. This is because usersets are self-defining: the userset `document:2021-budget#reader` will always have the `reader` relation with `document:2021-budget`. ### Querying usersets with exclusion in the model A Check for a userset can yield results that must be treated carefully if the model involves exclusion. For example, for the following authorization model ```python model schema 1.1 type user type group relations define member: [user] type document relations define blocked: [user] define reader: [group#member] but not blocked ``` the following query ```json { \"tuple_key\": { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"group:finance\" }, { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, { \"user\": \"user:anne\", \"relation\": \"blocked\", \"object\": \"document:2021-budget\" } ] }, } ``` will return `{ \"allowed\": true }`, even though a specific user of the userset `group:finance#member` does not have the `reader` relationship with the given object. ### Example @@ -189,6 +192,7 @@ No authorization required | **400** | Request failed due to invalid input. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | | **500** | Request failed due to internal server error. | - | @@ -260,6 +264,7 @@ No authorization required | **400** | Request failed due to invalid input. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | | **500** | Request failed due to internal server error. | - | ## createStoreWithHttpInfo @@ -340,6 +345,7 @@ No authorization required | **400** | Request failed due to invalid input. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | | **500** | Request failed due to internal server error. | - | @@ -410,6 +416,7 @@ No authorization required | **400** | Request failed due to invalid input. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | | **500** | Request failed due to internal server error. | - | ## deleteStoreWithHttpInfo @@ -489,6 +496,7 @@ No authorization required | **400** | Request failed due to invalid input. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | | **500** | Request failed due to internal server error. | - | @@ -562,6 +570,7 @@ No authorization required | **400** | Request failed due to invalid input. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | | **500** | Request failed due to internal server error. | - | ## expandWithHttpInfo @@ -644,6 +653,7 @@ No authorization required | **400** | Request failed due to invalid input. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | | **500** | Request failed due to internal server error. | - | @@ -715,6 +725,7 @@ No authorization required | **400** | Request failed due to invalid input. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | | **500** | Request failed due to internal server error. | - | ## getStoreWithHttpInfo @@ -795,6 +806,7 @@ No authorization required | **400** | Request failed due to invalid input. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | | **500** | Request failed due to internal server error. | - | @@ -804,7 +816,7 @@ No authorization required List all objects of the given type that the user has a relation with -The ListObjects API returns a list of all the objects of the given type that the user has a relation with. To achieve this, both the store tuples and the authorization model are used. An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related objects in an array in the \"objects\" field of the response and they will be strings in the object format `<type>:<id>` (e.g. \"document:roadmap\"). The number of objects in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_OBJECTS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_OBJECTS_MAX_RESULTS, whichever is hit first. The objects given will not be sorted, and therefore two identical calls can give a given different set of objects. +The ListObjects API returns a list of all the objects of the given type that the user has a relation with. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related objects in an array in the \"objects\" field of the response and they will be strings in the object format `<type>:<id>` (e.g. \"document:roadmap\"). The number of objects in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_OBJECTS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_OBJECTS_MAX_RESULTS, whichever is hit first. The objects given will not be sorted, and therefore two identical calls can give a given different set of objects. ### Example @@ -868,6 +880,7 @@ No authorization required | **400** | Request failed due to invalid input. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | | **500** | Request failed due to internal server error. | - | ## listObjectsWithHttpInfo @@ -876,7 +889,7 @@ No authorization required List all objects of the given type that the user has a relation with -The ListObjects API returns a list of all the objects of the given type that the user has a relation with. To achieve this, both the store tuples and the authorization model are used. An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related objects in an array in the \"objects\" field of the response and they will be strings in the object format `<type>:<id>` (e.g. \"document:roadmap\"). The number of objects in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_OBJECTS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_OBJECTS_MAX_RESULTS, whichever is hit first. The objects given will not be sorted, and therefore two identical calls can give a given different set of objects. +The ListObjects API returns a list of all the objects of the given type that the user has a relation with. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related objects in an array in the \"objects\" field of the response and they will be strings in the object format `<type>:<id>` (e.g. \"document:roadmap\"). The number of objects in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_OBJECTS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_OBJECTS_MAX_RESULTS, whichever is hit first. The objects given will not be sorted, and therefore two identical calls can give a given different set of objects. ### Example @@ -950,6 +963,7 @@ No authorization required | **400** | Request failed due to invalid input. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | | **500** | Request failed due to internal server error. | - | @@ -1023,6 +1037,7 @@ No authorization required | **400** | Request failed due to invalid input. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | | **500** | Request failed due to internal server error. | - | ## listStoresWithHttpInfo @@ -1105,6 +1120,164 @@ No authorization required | **400** | Request failed due to invalid input. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | +| **500** | Request failed due to internal server error. | - | + + +## listUsers + +> CompletableFuture listUsers(storeId, body) + +List the users matching the provided filter who have a certain relation to a particular type. + +The ListUsers API returns a list of all the users of a specific type that have a relation to a given object. This API is available in an experimental capacity and can be enabled with the `--experimentals enable-list-users` flag. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related users in an array in the \"users\" field of the response. These results may include specific objects, usersets or type-bound public access. Each of these types of results is encoded in its own type and not represented as a string.In certain cases of negation via the `but not` operator, some results are marked as excluded from the main set of results. These exclusions are returned in the `excluded_users` property and should be handled appropriately at the point of implementation.The number of users in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_USERS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_USERS_MAX_RESULTS, whichever is hit first. The returned users will not be sorted, and therefore two identical calls may yield different sets of users. + +### Example + +```java +// Import classes: +import dev.openfga.sdk.api.client.ApiClient; +import dev.openfga.sdk.api.client.ApiException; +import dev.openfga.sdk.api.configuration.Configuration; +import dev.openfga.sdk.api.client.models.*; +import dev.openfga.sdk.api.OpenFgaApi; +import java.util.concurrent.CompletableFuture; + +public class Example { + public static void main(String[] args) { + ApiClient defaultClient = Configuration.getDefaultApiClient(); + defaultClient.setBasePath("http://localhost"); + + OpenFgaApi apiInstance = new OpenFgaApi(defaultClient); + String storeId = "storeId_example"; // String | + ListUsersRequest body = new ListUsersRequest(); // ListUsersRequest | + try { + CompletableFuture result = apiInstance.listUsers(storeId, body); + System.out.println(result.get()); + } catch (ApiException e) { + System.err.println("Exception when calling OpenFgaApi#listUsers"); + System.err.println("Status code: " + e.getCode()); + System.err.println("Reason: " + e.getResponseBody()); + System.err.println("Response headers: " + e.getResponseHeaders()); + e.printStackTrace(); + } + } +} +``` + +### Parameters + + +| Name | Type | Description | Notes | +|------------- | ------------- | ------------- | -------------| +| **storeId** | **String**| | | +| **body** | [**ListUsersRequest**](ListUsersRequest.md)| | | + +### Return type + +CompletableFuture<[**ListUsersResponse**](ListUsersResponse.md)> + + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: application/json +- **Accept**: application/json + +### HTTP response details +| Status code | Description | Response headers | +|-------------|-------------|------------------| +| **200** | A successful response. | - | +| **400** | Request failed due to invalid input. | - | +| **404** | Request failed due to incorrect path. | - | +| **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | +| **500** | Request failed due to internal server error. | - | + +## listUsersWithHttpInfo + +> CompletableFuture> listUsers listUsersWithHttpInfo(storeId, body) + +List the users matching the provided filter who have a certain relation to a particular type. + +The ListUsers API returns a list of all the users of a specific type that have a relation to a given object. This API is available in an experimental capacity and can be enabled with the `--experimentals enable-list-users` flag. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related users in an array in the \"users\" field of the response. These results may include specific objects, usersets or type-bound public access. Each of these types of results is encoded in its own type and not represented as a string.In certain cases of negation via the `but not` operator, some results are marked as excluded from the main set of results. These exclusions are returned in the `excluded_users` property and should be handled appropriately at the point of implementation.The number of users in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_USERS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_USERS_MAX_RESULTS, whichever is hit first. The returned users will not be sorted, and therefore two identical calls may yield different sets of users. + +### Example + +```java +// Import classes: +import dev.openfga.sdk.api.client.ApiClient; +import dev.openfga.sdk.api.client.ApiException; +import dev.openfga.sdk.api.client.ApiResponse; +import dev.openfga.sdk.api.configuration.Configuration; +import dev.openfga.sdk.api.client.models.*; +import dev.openfga.sdk.api.OpenFgaApi; +import java.util.concurrent.CompletableFuture; + +public class Example { + public static void main(String[] args) { + ApiClient defaultClient = Configuration.getDefaultApiClient(); + defaultClient.setBasePath("http://localhost"); + + OpenFgaApi apiInstance = new OpenFgaApi(defaultClient); + String storeId = "storeId_example"; // String | + ListUsersRequest body = new ListUsersRequest(); // ListUsersRequest | + try { + CompletableFuture> response = apiInstance.listUsersWithHttpInfo(storeId, body); + System.out.println("Status code: " + response.get().getStatusCode()); + System.out.println("Response headers: " + response.get().getHeaders()); + System.out.println("Response body: " + response.get().getData()); + } catch (InterruptedException | ExecutionException e) { + ApiException apiException = (ApiException)e.getCause(); + System.err.println("Exception when calling OpenFgaApi#listUsers"); + System.err.println("Status code: " + apiException.getCode()); + System.err.println("Response headers: " + apiException.getResponseHeaders()); + System.err.println("Reason: " + apiException.getResponseBody()); + e.printStackTrace(); + } catch (ApiException e) { + System.err.println("Exception when calling OpenFgaApi#listUsers"); + System.err.println("Status code: " + e.getCode()); + System.err.println("Response headers: " + e.getResponseHeaders()); + System.err.println("Reason: " + e.getResponseBody()); + e.printStackTrace(); + } + } +} +``` + +### Parameters + + +| Name | Type | Description | Notes | +|------------- | ------------- | ------------- | -------------| +| **storeId** | **String**| | | +| **body** | [**ListUsersRequest**](ListUsersRequest.md)| | | + +### Return type + +CompletableFuture> + + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: application/json +- **Accept**: application/json + +### HTTP response details +| Status code | Description | Response headers | +|-------------|-------------|------------------| +| **200** | A successful response. | - | +| **400** | Request failed due to invalid input. | - | +| **404** | Request failed due to incorrect path. | - | +| **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | | **500** | Request failed due to internal server error. | - | @@ -1178,6 +1351,7 @@ No authorization required | **400** | Request failed due to invalid input. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | | **500** | Request failed due to internal server error. | - | ## readWithHttpInfo @@ -1260,6 +1434,7 @@ No authorization required | **400** | Request failed due to invalid input. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | | **500** | Request failed due to internal server error. | - | @@ -1333,6 +1508,7 @@ No authorization required | **400** | Request failed due to invalid input. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | | **500** | Request failed due to internal server error. | - | ## readAssertionsWithHttpInfo @@ -1415,6 +1591,7 @@ No authorization required | **400** | Request failed due to invalid input. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | | **500** | Request failed due to internal server error. | - | @@ -1488,6 +1665,7 @@ No authorization required | **400** | Request failed due to invalid input. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | | **500** | Request failed due to internal server error. | - | ## readAuthorizationModelWithHttpInfo @@ -1570,6 +1748,7 @@ No authorization required | **400** | Request failed due to invalid input. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | | **500** | Request failed due to internal server error. | - | @@ -1645,6 +1824,7 @@ No authorization required | **400** | Request failed due to invalid input. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | | **500** | Request failed due to internal server error. | - | ## readAuthorizationModelsWithHttpInfo @@ -1729,6 +1909,7 @@ No authorization required | **400** | Request failed due to invalid input. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | | **500** | Request failed due to internal server error. | - | @@ -1806,6 +1987,7 @@ No authorization required | **400** | Request failed due to invalid input. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | | **500** | Request failed due to internal server error. | - | ## readChangesWithHttpInfo @@ -1892,6 +2074,7 @@ No authorization required | **400** | Request failed due to invalid input. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | | **500** | Request failed due to internal server error. | - | @@ -1901,7 +2084,7 @@ No authorization required Add or delete tuples from the store -The Write API will update the tuples for a certain store. Tuples and type definitions allow OpenFGA to determine whether a relationship exists between an object and an user. In the body, `writes` adds new tuples and `deletes` removes existing tuples. When deleting a tuple, any `condition` specified with it is ignored. The API is not idempotent: if, later on, you try to add the same tuple key (even if the `condition` is different), or if you try to delete a non-existing tuple, it will throw an error. An `authorization_model_id` may be specified in the body. If it is, it will be used to assert that each written tuple (not deleted) is valid for the model specified. If it is not specified, the latest authorization model ID will be used. ## Example ### Adding relationships To add `user:anne` as a `writer` for `document:2021-budget`, call write API with the following ```json { \"writes\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"writer\", \"object\": \"document:2021-budget\" } ] }, \"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\" } ``` ### Removing relationships To remove `user:bob` as a `reader` for `document:2021-budget`, call write API with the following ```json { \"deletes\": { \"tuple_keys\": [ { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" } ] } } ``` +The Write API will transactionally update the tuples for a certain store. Tuples and type definitions allow OpenFGA to determine whether a relationship exists between an object and an user. In the body, `writes` adds new tuples and `deletes` removes existing tuples. When deleting a tuple, any `condition` specified with it is ignored. The API is not idempotent: if, later on, you try to add the same tuple key (even if the `condition` is different), or if you try to delete a non-existing tuple, it will throw an error. The API will not allow you to write tuples such as `document:2021-budget#viewer@document:2021-budget#viewer`, because they are implicit. An `authorization_model_id` may be specified in the body. If it is, it will be used to assert that each written tuple (not deleted) is valid for the model specified. If it is not specified, the latest authorization model ID will be used. ## Example ### Adding relationships To add `user:anne` as a `writer` for `document:2021-budget`, call write API with the following ```json { \"writes\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"writer\", \"object\": \"document:2021-budget\" } ] }, \"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\" } ``` ### Removing relationships To remove `user:bob` as a `reader` for `document:2021-budget`, call write API with the following ```json { \"deletes\": { \"tuple_keys\": [ { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" } ] } } ``` ### Example @@ -1965,6 +2148,7 @@ No authorization required | **400** | Request failed due to invalid input. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | | **500** | Request failed due to internal server error. | - | ## writeWithHttpInfo @@ -1973,7 +2157,7 @@ No authorization required Add or delete tuples from the store -The Write API will update the tuples for a certain store. Tuples and type definitions allow OpenFGA to determine whether a relationship exists between an object and an user. In the body, `writes` adds new tuples and `deletes` removes existing tuples. When deleting a tuple, any `condition` specified with it is ignored. The API is not idempotent: if, later on, you try to add the same tuple key (even if the `condition` is different), or if you try to delete a non-existing tuple, it will throw an error. An `authorization_model_id` may be specified in the body. If it is, it will be used to assert that each written tuple (not deleted) is valid for the model specified. If it is not specified, the latest authorization model ID will be used. ## Example ### Adding relationships To add `user:anne` as a `writer` for `document:2021-budget`, call write API with the following ```json { \"writes\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"writer\", \"object\": \"document:2021-budget\" } ] }, \"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\" } ``` ### Removing relationships To remove `user:bob` as a `reader` for `document:2021-budget`, call write API with the following ```json { \"deletes\": { \"tuple_keys\": [ { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" } ] } } ``` +The Write API will transactionally update the tuples for a certain store. Tuples and type definitions allow OpenFGA to determine whether a relationship exists between an object and an user. In the body, `writes` adds new tuples and `deletes` removes existing tuples. When deleting a tuple, any `condition` specified with it is ignored. The API is not idempotent: if, later on, you try to add the same tuple key (even if the `condition` is different), or if you try to delete a non-existing tuple, it will throw an error. The API will not allow you to write tuples such as `document:2021-budget#viewer@document:2021-budget#viewer`, because they are implicit. An `authorization_model_id` may be specified in the body. If it is, it will be used to assert that each written tuple (not deleted) is valid for the model specified. If it is not specified, the latest authorization model ID will be used. ## Example ### Adding relationships To add `user:anne` as a `writer` for `document:2021-budget`, call write API with the following ```json { \"writes\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"writer\", \"object\": \"document:2021-budget\" } ] }, \"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\" } ``` ### Removing relationships To remove `user:bob` as a `reader` for `document:2021-budget`, call write API with the following ```json { \"deletes\": { \"tuple_keys\": [ { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" } ] } } ``` ### Example @@ -2047,6 +2231,7 @@ No authorization required | **400** | Request failed due to invalid input. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | | **500** | Request failed due to internal server error. | - | @@ -2121,6 +2306,7 @@ No authorization required | **400** | Request failed due to invalid input. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | | **500** | Request failed due to internal server error. | - | ## writeAssertionsWithHttpInfo @@ -2204,6 +2390,7 @@ No authorization required | **400** | Request failed due to invalid input. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | | **500** | Request failed due to internal server error. | - | @@ -2277,6 +2464,7 @@ No authorization required | **400** | Request failed due to invalid input. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | | **500** | Request failed due to internal server error. | - | ## writeAuthorizationModelWithHttpInfo @@ -2359,5 +2547,6 @@ No authorization required | **400** | Request failed due to invalid input. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | | **500** | Request failed due to internal server error. | - | diff --git a/docs/TypedWildcard.md b/docs/TypedWildcard.md new file mode 100644 index 0000000..f3e0f20 --- /dev/null +++ b/docs/TypedWildcard.md @@ -0,0 +1,14 @@ + + +# TypedWildcard + +Type bound public access. Normally represented using the `:*` syntax `employee:*` represents every object of type `employee`, including those not currently present in the system See https://openfga.dev/docs/concepts#what-is-type-bound-public-access + +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +|**type** | **String** | | | + + + diff --git a/docs/UnprocessableContentErrorCode.md b/docs/UnprocessableContentErrorCode.md new file mode 100644 index 0000000..8cfbcdc --- /dev/null +++ b/docs/UnprocessableContentErrorCode.md @@ -0,0 +1,15 @@ + + +# UnprocessableContentErrorCode + +## Enum + + +* `NO_THROTTLED_ERROR_CODE` (value: `"no_throttled_error_code"`) + +* `THROTTLED_TIMEOUT_ERROR` (value: `"throttled_timeout_error"`) + +* `UNKNOWN_DEFAULT_OPEN_API` (value: `"unknown_default_open_api"`) + + + diff --git a/docs/UnprocessableContentMessageResponse.md b/docs/UnprocessableContentMessageResponse.md new file mode 100644 index 0000000..d2f89a2 --- /dev/null +++ b/docs/UnprocessableContentMessageResponse.md @@ -0,0 +1,14 @@ + + +# UnprocessableContentMessageResponse + + +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +|**code** | **UnprocessableContentErrorCode** | | [optional] | +|**message** | **String** | | [optional] | + + + diff --git a/docs/User.md b/docs/User.md new file mode 100644 index 0000000..5da42fa --- /dev/null +++ b/docs/User.md @@ -0,0 +1,16 @@ + + +# User + +User. Represents any possible value for a user (subject or principal). Can be a: - Specific user object e.g.: 'user:will', 'folder:marketing', 'org:contoso', ...) - Specific userset (e.g. 'group:engineering#member') - Public-typed wildcard (e.g. 'user:*') See https://openfga.dev/docs/concepts#what-is-a-user + +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +|**_object** | [**FgaObject**](FgaObject.md) | | [optional] | +|**userset** | [**UsersetUser**](UsersetUser.md) | | [optional] | +|**wildcard** | [**TypedWildcard**](TypedWildcard.md) | | [optional] | + + + diff --git a/docs/UserTypeFilter.md b/docs/UserTypeFilter.md new file mode 100644 index 0000000..cff363c --- /dev/null +++ b/docs/UserTypeFilter.md @@ -0,0 +1,14 @@ + + +# UserTypeFilter + + +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +|**type** | **String** | | | +|**relation** | **String** | | [optional] | + + + diff --git a/docs/UsersetUser.md b/docs/UsersetUser.md new file mode 100644 index 0000000..0e9d21a --- /dev/null +++ b/docs/UsersetUser.md @@ -0,0 +1,16 @@ + + +# UsersetUser + +Userset. A set or group of users, represented in the `:#` format `group:fga#member` represents all members of group FGA, not to be confused by `group:fga` which represents the group itself as a specific object. See: https://openfga.dev/docs/modeling/building-blocks/usersets#what-is-a-userset + +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +|**type** | **String** | | | +|**id** | **String** | | | +|**relation** | **String** | | | + + + diff --git a/src/main/java/dev/openfga/sdk/api/OpenFgaApi.java b/src/main/java/dev/openfga/sdk/api/OpenFgaApi.java index cda75a0..ae2ed84 100644 --- a/src/main/java/dev/openfga/sdk/api/OpenFgaApi.java +++ b/src/main/java/dev/openfga/sdk/api/OpenFgaApi.java @@ -28,6 +28,8 @@ import dev.openfga.sdk.api.model.ListObjectsRequest; import dev.openfga.sdk.api.model.ListObjectsResponse; import dev.openfga.sdk.api.model.ListStoresResponse; +import dev.openfga.sdk.api.model.ListUsersRequest; +import dev.openfga.sdk.api.model.ListUsersResponse; import dev.openfga.sdk.api.model.ReadAssertionsResponse; import dev.openfga.sdk.api.model.ReadAuthorizationModelResponse; import dev.openfga.sdk.api.model.ReadAuthorizationModelsResponse; @@ -81,7 +83,7 @@ public OpenFgaApi(Configuration configuration, ApiClient apiClient) throws FgaIn /** * Check whether a user is authorized to access an object - * The Check API queries to check if the user has a certain relationship with an object in a certain store. A `contextual_tuples` object may also be included in the body of the request. This object contains one field `tuple_keys`, which is an array of tuple keys. Each of these tuples may have an associated `condition`. You may also provide an `authorization_model_id` in the body. This will be used to assert that the input `tuple_key` is valid for the model specified. If not specified, the assertion will be made against the latest authorization model ID. It is strongly recommended to specify authorization model id for better performance. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will return whether the relationship exists in the field `allowed`. ## Example In order to check if user `user:anne` of type `user` has a `reader` relationship with object `document:2021-budget` given the following contextual tuple ```json { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ``` the Check API can be used with the following request body: ```json { \"tuple_key\": { \"user\": \"user:anne\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ] }, \"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\" } ``` OpenFGA's response will include `{ \"allowed\": true }` if there is a relationship and `{ \"allowed\": false }` if there isn't. + * The Check API returns whether a given user has a relationship with a given object in a given store. The `user` field of the request can be a specific target, such as `user:anne`, or a userset (set of users) such as `group:marketing#member` or a type-bound public access `user:*`. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). A `contextual_tuples` object may also be included in the body of the request. This object contains one field `tuple_keys`, which is an array of tuple keys. Each of these tuples may have an associated `condition`. You may also provide an `authorization_model_id` in the body. This will be used to assert that the input `tuple_key` is valid for the model specified. If not specified, the assertion will be made against the latest authorization model ID. It is strongly recommended to specify authorization model id for better performance. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will return whether the relationship exists in the field `allowed`. Some exceptions apply, but in general, if a Check API responds with `{allowed: true}`, then you can expect the equivalent ListObjects query to return the object, and viceversa. For example, if `Check(user:anne, reader, document:2021-budget)` responds with `{allowed: true}`, then `ListObjects(user:anne, reader, document)` may include `document:2021-budget` in the response. ## Examples ### Querying with contextual tuples In order to check if user `user:anne` of type `user` has a `reader` relationship with object `document:2021-budget` given the following contextual tuple ```json { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ``` the Check API can be used with the following request body: ```json { \"tuple_key\": { \"user\": \"user:anne\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ] }, \"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\" } ``` ### Querying usersets Some Checks will always return `true`, even without any tuples. For example, for the following authorization model ```python model schema 1.1 type user type document relations define reader: [user] ``` the following query ```json { \"tuple_key\": { \"user\": \"document:2021-budget#reader\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" } } ``` will always return `{ \"allowed\": true }`. This is because usersets are self-defining: the userset `document:2021-budget#reader` will always have the `reader` relation with `document:2021-budget`. ### Querying usersets with exclusion in the model A Check for a userset can yield results that must be treated carefully if the model involves exclusion. For example, for the following authorization model ```python model schema 1.1 type user type group relations define member: [user] type document relations define blocked: [user] define reader: [group#member] but not blocked ``` the following query ```json { \"tuple_key\": { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"group:finance\" }, { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, { \"user\": \"user:anne\", \"relation\": \"blocked\", \"object\": \"document:2021-budget\" } ] }, } ``` will return `{ \"allowed\": true }`, even though a specific user of the userset `group:finance#member` does not have the `reader` relationship with the given object. * @param storeId (required) * @param body (required) * @return CompletableFuture<ApiResponse<CheckResponse>> @@ -94,7 +96,7 @@ public CompletableFuture> check(String storeId, Check /** * Check whether a user is authorized to access an object - * The Check API queries to check if the user has a certain relationship with an object in a certain store. A `contextual_tuples` object may also be included in the body of the request. This object contains one field `tuple_keys`, which is an array of tuple keys. Each of these tuples may have an associated `condition`. You may also provide an `authorization_model_id` in the body. This will be used to assert that the input `tuple_key` is valid for the model specified. If not specified, the assertion will be made against the latest authorization model ID. It is strongly recommended to specify authorization model id for better performance. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will return whether the relationship exists in the field `allowed`. ## Example In order to check if user `user:anne` of type `user` has a `reader` relationship with object `document:2021-budget` given the following contextual tuple ```json { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ``` the Check API can be used with the following request body: ```json { \"tuple_key\": { \"user\": \"user:anne\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ] }, \"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\" } ``` OpenFGA's response will include `{ \"allowed\": true }` if there is a relationship and `{ \"allowed\": false }` if there isn't. + * The Check API returns whether a given user has a relationship with a given object in a given store. The `user` field of the request can be a specific target, such as `user:anne`, or a userset (set of users) such as `group:marketing#member` or a type-bound public access `user:*`. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). A `contextual_tuples` object may also be included in the body of the request. This object contains one field `tuple_keys`, which is an array of tuple keys. Each of these tuples may have an associated `condition`. You may also provide an `authorization_model_id` in the body. This will be used to assert that the input `tuple_key` is valid for the model specified. If not specified, the assertion will be made against the latest authorization model ID. It is strongly recommended to specify authorization model id for better performance. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will return whether the relationship exists in the field `allowed`. Some exceptions apply, but in general, if a Check API responds with `{allowed: true}`, then you can expect the equivalent ListObjects query to return the object, and viceversa. For example, if `Check(user:anne, reader, document:2021-budget)` responds with `{allowed: true}`, then `ListObjects(user:anne, reader, document)` may include `document:2021-budget` in the response. ## Examples ### Querying with contextual tuples In order to check if user `user:anne` of type `user` has a `reader` relationship with object `document:2021-budget` given the following contextual tuple ```json { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ``` the Check API can be used with the following request body: ```json { \"tuple_key\": { \"user\": \"user:anne\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ] }, \"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\" } ``` ### Querying usersets Some Checks will always return `true`, even without any tuples. For example, for the following authorization model ```python model schema 1.1 type user type document relations define reader: [user] ``` the following query ```json { \"tuple_key\": { \"user\": \"document:2021-budget#reader\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" } } ``` will always return `{ \"allowed\": true }`. This is because usersets are self-defining: the userset `document:2021-budget#reader` will always have the `reader` relation with `document:2021-budget`. ### Querying usersets with exclusion in the model A Check for a userset can yield results that must be treated carefully if the model involves exclusion. For example, for the following authorization model ```python model schema 1.1 type user type group relations define member: [user] type document relations define blocked: [user] define reader: [group#member] but not blocked ``` the following query ```json { \"tuple_key\": { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"group:finance\" }, { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, { \"user\": \"user:anne\", \"relation\": \"blocked\", \"object\": \"document:2021-budget\" } ] }, } ``` will return `{ \"allowed\": true }`, even though a specific user of the userset `group:finance#member` does not have the `reader` relationship with the given object. * @param storeId (required) * @param body (required) * @param configurationOverride Override the {@link Configuration} this OpenFgaApi was constructed with @@ -300,7 +302,7 @@ private CompletableFuture> getStore(String storeId /** * List all objects of the given type that the user has a relation with - * The ListObjects API returns a list of all the objects of the given type that the user has a relation with. To achieve this, both the store tuples and the authorization model are used. An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related objects in an array in the \"objects\" field of the response and they will be strings in the object format `<type>:<id>` (e.g. \"document:roadmap\"). The number of objects in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_OBJECTS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_OBJECTS_MAX_RESULTS, whichever is hit first. The objects given will not be sorted, and therefore two identical calls can give a given different set of objects. + * The ListObjects API returns a list of all the objects of the given type that the user has a relation with. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related objects in an array in the \"objects\" field of the response and they will be strings in the object format `<type>:<id>` (e.g. \"document:roadmap\"). The number of objects in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_OBJECTS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_OBJECTS_MAX_RESULTS, whichever is hit first. The objects given will not be sorted, and therefore two identical calls can give a given different set of objects. * @param storeId (required) * @param body (required) * @return CompletableFuture<ApiResponse<ListObjectsResponse>> @@ -313,7 +315,7 @@ public CompletableFuture> listObjects(String st /** * List all objects of the given type that the user has a relation with - * The ListObjects API returns a list of all the objects of the given type that the user has a relation with. To achieve this, both the store tuples and the authorization model are used. An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related objects in an array in the \"objects\" field of the response and they will be strings in the object format `<type>:<id>` (e.g. \"document:roadmap\"). The number of objects in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_OBJECTS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_OBJECTS_MAX_RESULTS, whichever is hit first. The objects given will not be sorted, and therefore two identical calls can give a given different set of objects. + * The ListObjects API returns a list of all the objects of the given type that the user has a relation with. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related objects in an array in the \"objects\" field of the response and they will be strings in the object format `<type>:<id>` (e.g. \"document:roadmap\"). The number of objects in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_OBJECTS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_OBJECTS_MAX_RESULTS, whichever is hit first. The objects given will not be sorted, and therefore two identical calls can give a given different set of objects. * @param storeId (required) * @param body (required) * @param configurationOverride Override the {@link Configuration} this OpenFgaApi was constructed with @@ -389,6 +391,53 @@ private CompletableFuture> listStores( } } + /** + * List the users matching the provided filter who have a certain relation to a particular type. + * The ListUsers API returns a list of all the users of a specific type that have a relation to a given object. This API is available in an experimental capacity and can be enabled with the `--experimentals enable-list-users` flag. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related users in an array in the \"users\" field of the response. These results may include specific objects, usersets or type-bound public access. Each of these types of results is encoded in its own type and not represented as a string.In certain cases of negation via the `but not` operator, some results are marked as excluded from the main set of results. These exclusions are returned in the `excluded_users` property and should be handled appropriately at the point of implementation.The number of users in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_USERS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_USERS_MAX_RESULTS, whichever is hit first. The returned users will not be sorted, and therefore two identical calls may yield different sets of users. + * @param storeId (required) + * @param body (required) + * @return CompletableFuture<ApiResponse<ListUsersResponse>> + * @throws ApiException if fails to make API call + */ + public CompletableFuture> listUsers(String storeId, ListUsersRequest body) + throws ApiException, FgaInvalidParameterException { + return listUsers(storeId, body, this.configuration); + } + + /** + * List the users matching the provided filter who have a certain relation to a particular type. + * The ListUsers API returns a list of all the users of a specific type that have a relation to a given object. This API is available in an experimental capacity and can be enabled with the `--experimentals enable-list-users` flag. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related users in an array in the \"users\" field of the response. These results may include specific objects, usersets or type-bound public access. Each of these types of results is encoded in its own type and not represented as a string.In certain cases of negation via the `but not` operator, some results are marked as excluded from the main set of results. These exclusions are returned in the `excluded_users` property and should be handled appropriately at the point of implementation.The number of users in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_USERS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_USERS_MAX_RESULTS, whichever is hit first. The returned users will not be sorted, and therefore two identical calls may yield different sets of users. + * @param storeId (required) + * @param body (required) + * @param configurationOverride Override the {@link Configuration} this OpenFgaApi was constructed with + * @return CompletableFuture<ApiResponse<ListUsersResponse>> + * @throws ApiException if fails to make API call + */ + public CompletableFuture> listUsers( + String storeId, ListUsersRequest body, ConfigurationOverride configurationOverride) + throws ApiException, FgaInvalidParameterException { + return listUsers(storeId, body, this.configuration.override(configurationOverride)); + } + + private CompletableFuture> listUsers( + String storeId, ListUsersRequest body, Configuration configuration) + throws ApiException, FgaInvalidParameterException { + + assertParamExists(storeId, "storeId", "listUsers"); + + assertParamExists(body, "body", "listUsers"); + + String path = "/stores/{store_id}/list-users".replace("{store_id}", ApiClient.urlEncode(storeId.toString())); + + try { + HttpRequest request = buildHttpRequest("POST", path, body, configuration); + return new HttpRequestAttempt<>(request, "listUsers", ListUsersResponse.class, apiClient, configuration) + .attemptHttpRequest(); + } catch (ApiException e) { + return CompletableFuture.failedFuture(e); + } + } + /** * Get tuples from the store that matches a query, without following userset rewrite rules * The Read API will return the tuples for a certain store that match a query filter specified in the body of the request. The API doesn't guarantee order by any field. It is different from the `/stores/{store_id}/expand` API in that it only returns relationship tuples that are stored in the system and satisfy the query. In the body: 1. `tuple_key` is optional. If not specified, it will return all tuples in the store. 2. `tuple_key.object` is mandatory if `tuple_key` is specified. It can be a full object (e.g., `type:object_id`) or type only (e.g., `type:`). 3. `tuple_key.user` is mandatory if tuple_key is specified in the case the `tuple_key.object` is a type only. ## Examples ### Query for all objects in a type definition To query for all objects that `user:bob` has `reader` relationship in the `document` type definition, call read API with body of ```json { \"tuple_key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:\" } } ``` The API will return tuples and a continuation token, something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `user:bob` has a `reader` relationship with 1 document `document:2021-budget`. Note that this API, unlike the List Objects API, does not evaluate the tuples in the store. The continuation token will be empty if there are no more tuples to query. ### Query for all stored relationship tuples that have a particular relation and object To query for all users that have `reader` relationship with `document:2021-budget`, call read API with body of ```json { \"tuple_key\": { \"object\": \"document:2021-budget\", \"relation\": \"reader\" } } ``` The API will return something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `document:2021-budget` has 1 `reader` (`user:bob`). Note that, even if the model said that all `writers` are also `readers`, the API will not return writers such as `user:anne` because it only returns tuples and does not evaluate them. ### Query for all users with all relationships for a particular document To query for all users that have any relationship with `document:2021-budget`, call read API with body of ```json { \"tuple_key\": { \"object\": \"document:2021-budget\" } } ``` The API will return something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:anne\", \"relation\": \"writer\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-05T13:42:12.356Z\" }, { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `document:2021-budget` has 1 `reader` (`user:bob`) and 1 `writer` (`user:anne`). @@ -653,7 +702,7 @@ private CompletableFuture> readChanges( /** * Add or delete tuples from the store - * The Write API will update the tuples for a certain store. Tuples and type definitions allow OpenFGA to determine whether a relationship exists between an object and an user. In the body, `writes` adds new tuples and `deletes` removes existing tuples. When deleting a tuple, any `condition` specified with it is ignored. The API is not idempotent: if, later on, you try to add the same tuple key (even if the `condition` is different), or if you try to delete a non-existing tuple, it will throw an error. An `authorization_model_id` may be specified in the body. If it is, it will be used to assert that each written tuple (not deleted) is valid for the model specified. If it is not specified, the latest authorization model ID will be used. ## Example ### Adding relationships To add `user:anne` as a `writer` for `document:2021-budget`, call write API with the following ```json { \"writes\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"writer\", \"object\": \"document:2021-budget\" } ] }, \"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\" } ``` ### Removing relationships To remove `user:bob` as a `reader` for `document:2021-budget`, call write API with the following ```json { \"deletes\": { \"tuple_keys\": [ { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" } ] } } ``` + * The Write API will transactionally update the tuples for a certain store. Tuples and type definitions allow OpenFGA to determine whether a relationship exists between an object and an user. In the body, `writes` adds new tuples and `deletes` removes existing tuples. When deleting a tuple, any `condition` specified with it is ignored. The API is not idempotent: if, later on, you try to add the same tuple key (even if the `condition` is different), or if you try to delete a non-existing tuple, it will throw an error. The API will not allow you to write tuples such as `document:2021-budget#viewer@document:2021-budget#viewer`, because they are implicit. An `authorization_model_id` may be specified in the body. If it is, it will be used to assert that each written tuple (not deleted) is valid for the model specified. If it is not specified, the latest authorization model ID will be used. ## Example ### Adding relationships To add `user:anne` as a `writer` for `document:2021-budget`, call write API with the following ```json { \"writes\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"writer\", \"object\": \"document:2021-budget\" } ] }, \"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\" } ``` ### Removing relationships To remove `user:bob` as a `reader` for `document:2021-budget`, call write API with the following ```json { \"deletes\": { \"tuple_keys\": [ { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" } ] } } ``` * @param storeId (required) * @param body (required) * @return CompletableFuture<ApiResponse<Object>> @@ -666,7 +715,7 @@ public CompletableFuture> write(String storeId, WriteRequest /** * Add or delete tuples from the store - * The Write API will update the tuples for a certain store. Tuples and type definitions allow OpenFGA to determine whether a relationship exists between an object and an user. In the body, `writes` adds new tuples and `deletes` removes existing tuples. When deleting a tuple, any `condition` specified with it is ignored. The API is not idempotent: if, later on, you try to add the same tuple key (even if the `condition` is different), or if you try to delete a non-existing tuple, it will throw an error. An `authorization_model_id` may be specified in the body. If it is, it will be used to assert that each written tuple (not deleted) is valid for the model specified. If it is not specified, the latest authorization model ID will be used. ## Example ### Adding relationships To add `user:anne` as a `writer` for `document:2021-budget`, call write API with the following ```json { \"writes\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"writer\", \"object\": \"document:2021-budget\" } ] }, \"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\" } ``` ### Removing relationships To remove `user:bob` as a `reader` for `document:2021-budget`, call write API with the following ```json { \"deletes\": { \"tuple_keys\": [ { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" } ] } } ``` + * The Write API will transactionally update the tuples for a certain store. Tuples and type definitions allow OpenFGA to determine whether a relationship exists between an object and an user. In the body, `writes` adds new tuples and `deletes` removes existing tuples. When deleting a tuple, any `condition` specified with it is ignored. The API is not idempotent: if, later on, you try to add the same tuple key (even if the `condition` is different), or if you try to delete a non-existing tuple, it will throw an error. The API will not allow you to write tuples such as `document:2021-budget#viewer@document:2021-budget#viewer`, because they are implicit. An `authorization_model_id` may be specified in the body. If it is, it will be used to assert that each written tuple (not deleted) is valid for the model specified. If it is not specified, the latest authorization model ID will be used. ## Example ### Adding relationships To add `user:anne` as a `writer` for `document:2021-budget`, call write API with the following ```json { \"writes\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"writer\", \"object\": \"document:2021-budget\" } ] }, \"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\" } ``` ### Removing relationships To remove `user:bob` as a `reader` for `document:2021-budget`, call write API with the following ```json { \"deletes\": { \"tuple_keys\": [ { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" } ] } } ``` * @param storeId (required) * @param body (required) * @param configurationOverride Override the {@link Configuration} this OpenFgaApi was constructed with diff --git a/src/main/java/dev/openfga/sdk/api/client/OpenFgaClient.java b/src/main/java/dev/openfga/sdk/api/client/OpenFgaClient.java index f4d2d1f..1ab2a06 100644 --- a/src/main/java/dev/openfga/sdk/api/client/OpenFgaClient.java +++ b/src/main/java/dev/openfga/sdk/api/client/OpenFgaClient.java @@ -738,6 +738,48 @@ public CompletableFuture listRelations( .thenCompose(responses -> call(() -> ClientListRelationsResponse.fromBatchCheckResponses(responses))); } + /** + * ListUsers - List all users of the given type that the object has a relation with (evaluates) + */ + public CompletableFuture listUsers(ClientListUsersRequest request) + throws FgaInvalidParameterException { + return listUsers(request, null); + } + + /** + * ListUsers - List all users of the given type that the object has a relation with (evaluates) + */ + public CompletableFuture listUsers( + ClientListUsersRequest request, ClientListUsersOptions options) throws FgaInvalidParameterException { + configuration.assertValid(); + String storeId = configuration.getStoreIdChecked(); + + ListUsersRequest body = new ListUsersRequest(); + + if (request != null) { + body._object(request.getObject()).relation(request.getRelation()).userFilters(request.getUserFilters()); + if (request.getContextualTupleKeys() != null) { + var contextualTuples = request.getContextualTupleKeys(); + var bodyContextualTuples = ClientTupleKey.asContextualTupleKeys(contextualTuples); + body.contextualTuples(bodyContextualTuples.getTupleKeys()); + } + if (request.getContext() != null) { + body.context(request.getContext()); + } + } + + if (options != null && !isNullOrWhitespace(options.getAuthorizationModelId())) { + body.authorizationModelId(options.getAuthorizationModelId()); + } else { + String authorizationModelId = configuration.getAuthorizationModelId(); + body.authorizationModelId(authorizationModelId); + } + + var overrides = new ConfigurationOverride().addHeaders(options); + + return call(() -> api.listUsers(storeId, body, overrides)).thenApply(ClientListUsersResponse::new); + } + /* ************ * Assertions * **************/ diff --git a/src/main/java/dev/openfga/sdk/api/client/model/ClientListUsersRequest.java b/src/main/java/dev/openfga/sdk/api/client/model/ClientListUsersRequest.java new file mode 100644 index 0000000..33b5dd6 --- /dev/null +++ b/src/main/java/dev/openfga/sdk/api/client/model/ClientListUsersRequest.java @@ -0,0 +1,86 @@ +/* + * OpenFGA + * A high performance and flexible authorization/permission engine built for developers and inspired by Google Zanzibar. + * + * The version of the OpenAPI document: 0.1 + * Contact: community@openfga.dev + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +package dev.openfga.sdk.api.client.model; + +import dev.openfga.sdk.api.model.FgaObject; +import dev.openfga.sdk.api.model.UserTypeFilter; +import java.util.List; + +public class ClientListUsersRequest { + private FgaObject _object; + private String relation; + private List userFilters; + private List contextualTupleKeys; + private Object context; + + public ClientListUsersRequest _object(FgaObject _object) { + this._object = _object; + return this; + } + + /** + * Get _object + * @return _object + **/ + public FgaObject getObject() { + return _object; + } + + public ClientListUsersRequest relation(String relation) { + this.relation = relation; + return this; + } + + /** + * Get relation + * @return relation + **/ + public String getRelation() { + return relation; + } + + public ClientListUsersRequest userFilters(List userFilters) { + this.userFilters = userFilters; + return this; + } + + /** + * Get userFilters + * @return userFilters + **/ + public List getUserFilters() { + return userFilters; + } + + public ClientListUsersRequest contextualTupleKeys(List contextualTupleKeys) { + this.contextualTupleKeys = contextualTupleKeys; + return this; + } + + public List getContextualTupleKeys() { + return contextualTupleKeys; + } + + public ClientListUsersRequest context(Object context) { + this.context = context; + return this; + } + + /** + * Get context + * @return context + **/ + public Object getContext() { + return context; + } +} diff --git a/src/main/java/dev/openfga/sdk/api/client/model/ClientListUsersResponse.java b/src/main/java/dev/openfga/sdk/api/client/model/ClientListUsersResponse.java new file mode 100644 index 0000000..151d7a3 --- /dev/null +++ b/src/main/java/dev/openfga/sdk/api/client/model/ClientListUsersResponse.java @@ -0,0 +1,45 @@ +/* + * OpenFGA + * A high performance and flexible authorization/permission engine built for developers and inspired by Google Zanzibar. + * + * The version of the OpenAPI document: 0.1 + * Contact: community@openfga.dev + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +package dev.openfga.sdk.api.client.model; + +import dev.openfga.sdk.api.client.ApiResponse; +import dev.openfga.sdk.api.model.ListUsersResponse; +import java.util.List; +import java.util.Map; + +public class ClientListUsersResponse extends ListUsersResponse { + private final int statusCode; + private final Map> headers; + private final String rawResponse; + + public ClientListUsersResponse(ApiResponse apiResponse) { + this.statusCode = apiResponse.getStatusCode(); + this.headers = apiResponse.getHeaders(); + this.rawResponse = apiResponse.getRawResponse(); + ListUsersResponse response = apiResponse.getData(); + this.setUsers(response.getUsers()); + this.setExcludedUsers(response.getExcludedUsers()); + } + + public int getStatusCode() { + return statusCode; + } + + public Map> getHeaders() { + return headers; + } + + public String getRawResponse() { + return rawResponse; + } +} diff --git a/src/main/java/dev/openfga/sdk/api/configuration/ClientListUsersOptions.java b/src/main/java/dev/openfga/sdk/api/configuration/ClientListUsersOptions.java new file mode 100644 index 0000000..6e48a69 --- /dev/null +++ b/src/main/java/dev/openfga/sdk/api/configuration/ClientListUsersOptions.java @@ -0,0 +1,39 @@ +/* + * OpenFGA + * A high performance and flexible authorization/permission engine built for developers and inspired by Google Zanzibar. + * + * The version of the OpenAPI document: 0.1 + * Contact: community@openfga.dev + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +package dev.openfga.sdk.api.configuration; + +import java.util.Map; + +public class ClientListUsersOptions implements AdditionalHeadersSupplier { + private Map additionalHeaders; + private String authorizationModelId; + + public ClientListUsersOptions additionalHeaders(Map additionalHeaders) { + this.additionalHeaders = additionalHeaders; + return this; + } + + @Override + public Map getAdditionalHeaders() { + return this.additionalHeaders; + } + + public ClientListUsersOptions authorizationModelId(String authorizationModelId) { + this.authorizationModelId = authorizationModelId; + return this; + } + + public String getAuthorizationModelId() { + return authorizationModelId; + } +} diff --git a/src/main/java/dev/openfga/sdk/api/model/FgaObject.java b/src/main/java/dev/openfga/sdk/api/model/FgaObject.java new file mode 100644 index 0000000..3701829 --- /dev/null +++ b/src/main/java/dev/openfga/sdk/api/model/FgaObject.java @@ -0,0 +1,175 @@ +/* + * OpenFGA + * A high performance and flexible authorization/permission engine built for developers and inspired by Google Zanzibar. + * + * The version of the OpenAPI document: 0.1 + * Contact: community@openfga.dev + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +package dev.openfga.sdk.api.model; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.Objects; +import java.util.StringJoiner; + +/** + * Object represents an OpenFGA Object. An Object is composed of a type and identifier (e.g. 'document:1') See https://openfga.dev/docs/concepts#what-is-an-object + */ +@JsonPropertyOrder({FgaObject.JSON_PROPERTY_TYPE, FgaObject.JSON_PROPERTY_ID}) +public class FgaObject { + public static final String JSON_PROPERTY_TYPE = "type"; + private String type; + + public static final String JSON_PROPERTY_ID = "id"; + private String id; + + public FgaObject() {} + + public FgaObject type(String type) { + this.type = type; + return this; + } + + /** + * Get type + * @return type + **/ + @javax.annotation.Nonnull + @JsonProperty(JSON_PROPERTY_TYPE) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getType() { + return type; + } + + @JsonProperty(JSON_PROPERTY_TYPE) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setType(String type) { + this.type = type; + } + + public FgaObject id(String id) { + this.id = id; + return this; + } + + /** + * Get id + * @return id + **/ + @javax.annotation.Nonnull + @JsonProperty(JSON_PROPERTY_ID) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getId() { + return id; + } + + @JsonProperty(JSON_PROPERTY_ID) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setId(String id) { + this.id = id; + } + + /** + * Return true if this FgaObject object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + FgaObject fgaObject = (FgaObject) o; + return Objects.equals(this.type, fgaObject.type) && Objects.equals(this.id, fgaObject.id); + } + + @Override + public int hashCode() { + return Objects.hash(type, id); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class FgaObject {\n"); + sb.append(" type: ").append(toIndentedString(type)).append("\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + /** + * Convert the instance into URL query string. + * + * @return URL query string + */ + public String toUrlQueryString() { + return toUrlQueryString(null); + } + + /** + * Convert the instance into URL query string. + * + * @param prefix prefix of the query string + * @return URL query string + */ + public String toUrlQueryString(String prefix) { + String suffix = ""; + String containerSuffix = ""; + String containerPrefix = ""; + if (prefix == null) { + // style=form, explode=true, e.g. /pet?name=cat&type=manx + prefix = ""; + } else { + // deepObject style e.g. /pet?id[name]=cat&id[type]=manx + prefix = prefix + "["; + suffix = "]"; + containerSuffix = "]"; + containerPrefix = "["; + } + + StringJoiner joiner = new StringJoiner("&"); + + // add `type` to the URL query string + if (getType() != null) { + joiner.add(String.format( + "%stype%s=%s", + prefix, + suffix, + URLEncoder.encode(String.valueOf(getType()), StandardCharsets.UTF_8) + .replaceAll("\\+", "%20"))); + } + + // add `id` to the URL query string + if (getId() != null) { + joiner.add(String.format( + "%sid%s=%s", + prefix, + suffix, + URLEncoder.encode(String.valueOf(getId()), StandardCharsets.UTF_8) + .replaceAll("\\+", "%20"))); + } + + return joiner.toString(); + } +} diff --git a/src/main/java/dev/openfga/sdk/api/model/ListUsersRequest.java b/src/main/java/dev/openfga/sdk/api/model/ListUsersRequest.java new file mode 100644 index 0000000..f9c7947 --- /dev/null +++ b/src/main/java/dev/openfga/sdk/api/model/ListUsersRequest.java @@ -0,0 +1,362 @@ +/* + * OpenFGA + * A high performance and flexible authorization/permission engine built for developers and inspired by Google Zanzibar. + * + * The version of the OpenAPI document: 0.1 + * Contact: community@openfga.dev + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +package dev.openfga.sdk.api.model; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.StringJoiner; + +/** + * ListUsersRequest + */ +@JsonPropertyOrder({ + ListUsersRequest.JSON_PROPERTY_AUTHORIZATION_MODEL_ID, + ListUsersRequest.JSON_PROPERTY_OBJECT, + ListUsersRequest.JSON_PROPERTY_RELATION, + ListUsersRequest.JSON_PROPERTY_USER_FILTERS, + ListUsersRequest.JSON_PROPERTY_CONTEXTUAL_TUPLES, + ListUsersRequest.JSON_PROPERTY_CONTEXT +}) +public class ListUsersRequest { + public static final String JSON_PROPERTY_AUTHORIZATION_MODEL_ID = "authorization_model_id"; + private String authorizationModelId; + + public static final String JSON_PROPERTY_OBJECT = "object"; + private FgaObject _object; + + public static final String JSON_PROPERTY_RELATION = "relation"; + private String relation; + + public static final String JSON_PROPERTY_USER_FILTERS = "user_filters"; + private List userFilters = new ArrayList<>(); + + public static final String JSON_PROPERTY_CONTEXTUAL_TUPLES = "contextual_tuples"; + private List contextualTuples = new ArrayList<>(); + + public static final String JSON_PROPERTY_CONTEXT = "context"; + private Object context; + + public ListUsersRequest() {} + + public ListUsersRequest authorizationModelId(String authorizationModelId) { + this.authorizationModelId = authorizationModelId; + return this; + } + + /** + * Get authorizationModelId + * @return authorizationModelId + **/ + @javax.annotation.Nullable + @JsonProperty(JSON_PROPERTY_AUTHORIZATION_MODEL_ID) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public String getAuthorizationModelId() { + return authorizationModelId; + } + + @JsonProperty(JSON_PROPERTY_AUTHORIZATION_MODEL_ID) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setAuthorizationModelId(String authorizationModelId) { + this.authorizationModelId = authorizationModelId; + } + + public ListUsersRequest _object(FgaObject _object) { + this._object = _object; + return this; + } + + /** + * Get _object + * @return _object + **/ + @javax.annotation.Nonnull + @JsonProperty(JSON_PROPERTY_OBJECT) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public FgaObject getObject() { + return _object; + } + + @JsonProperty(JSON_PROPERTY_OBJECT) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setObject(FgaObject _object) { + this._object = _object; + } + + public ListUsersRequest relation(String relation) { + this.relation = relation; + return this; + } + + /** + * Get relation + * @return relation + **/ + @javax.annotation.Nonnull + @JsonProperty(JSON_PROPERTY_RELATION) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getRelation() { + return relation; + } + + @JsonProperty(JSON_PROPERTY_RELATION) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setRelation(String relation) { + this.relation = relation; + } + + public ListUsersRequest userFilters(List userFilters) { + this.userFilters = userFilters; + return this; + } + + public ListUsersRequest addUserFiltersItem(UserTypeFilter userFiltersItem) { + if (this.userFilters == null) { + this.userFilters = new ArrayList<>(); + } + this.userFilters.add(userFiltersItem); + return this; + } + + /** + * The type of results returned. Only accepts exactly one value. + * @return userFilters + **/ + @javax.annotation.Nonnull + @JsonProperty(JSON_PROPERTY_USER_FILTERS) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public List getUserFilters() { + return userFilters; + } + + @JsonProperty(JSON_PROPERTY_USER_FILTERS) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setUserFilters(List userFilters) { + this.userFilters = userFilters; + } + + public ListUsersRequest contextualTuples(List contextualTuples) { + this.contextualTuples = contextualTuples; + return this; + } + + public ListUsersRequest addContextualTuplesItem(TupleKey contextualTuplesItem) { + if (this.contextualTuples == null) { + this.contextualTuples = new ArrayList<>(); + } + this.contextualTuples.add(contextualTuplesItem); + return this; + } + + /** + * Get contextualTuples + * @return contextualTuples + **/ + @javax.annotation.Nullable + @JsonProperty(JSON_PROPERTY_CONTEXTUAL_TUPLES) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public List getContextualTuples() { + return contextualTuples; + } + + @JsonProperty(JSON_PROPERTY_CONTEXTUAL_TUPLES) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setContextualTuples(List contextualTuples) { + this.contextualTuples = contextualTuples; + } + + public ListUsersRequest context(Object context) { + this.context = context; + return this; + } + + /** + * Additional request context that will be used to evaluate any ABAC conditions encountered in the query evaluation. + * @return context + **/ + @javax.annotation.Nullable + @JsonProperty(JSON_PROPERTY_CONTEXT) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public Object getContext() { + return context; + } + + @JsonProperty(JSON_PROPERTY_CONTEXT) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setContext(Object context) { + this.context = context; + } + + /** + * Return true if this ListUsers_request object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ListUsersRequest listUsersRequest = (ListUsersRequest) o; + return Objects.equals(this.authorizationModelId, listUsersRequest.authorizationModelId) + && Objects.equals(this._object, listUsersRequest._object) + && Objects.equals(this.relation, listUsersRequest.relation) + && Objects.equals(this.userFilters, listUsersRequest.userFilters) + && Objects.equals(this.contextualTuples, listUsersRequest.contextualTuples) + && Objects.equals(this.context, listUsersRequest.context); + } + + @Override + public int hashCode() { + return Objects.hash(authorizationModelId, _object, relation, userFilters, contextualTuples, context); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ListUsersRequest {\n"); + sb.append(" authorizationModelId: ") + .append(toIndentedString(authorizationModelId)) + .append("\n"); + sb.append(" _object: ").append(toIndentedString(_object)).append("\n"); + sb.append(" relation: ").append(toIndentedString(relation)).append("\n"); + sb.append(" userFilters: ").append(toIndentedString(userFilters)).append("\n"); + sb.append(" contextualTuples: ") + .append(toIndentedString(contextualTuples)) + .append("\n"); + sb.append(" context: ").append(toIndentedString(context)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + /** + * Convert the instance into URL query string. + * + * @return URL query string + */ + public String toUrlQueryString() { + return toUrlQueryString(null); + } + + /** + * Convert the instance into URL query string. + * + * @param prefix prefix of the query string + * @return URL query string + */ + public String toUrlQueryString(String prefix) { + String suffix = ""; + String containerSuffix = ""; + String containerPrefix = ""; + if (prefix == null) { + // style=form, explode=true, e.g. /pet?name=cat&type=manx + prefix = ""; + } else { + // deepObject style e.g. /pet?id[name]=cat&id[type]=manx + prefix = prefix + "["; + suffix = "]"; + containerSuffix = "]"; + containerPrefix = "["; + } + + StringJoiner joiner = new StringJoiner("&"); + + // add `authorization_model_id` to the URL query string + if (getAuthorizationModelId() != null) { + joiner.add(String.format( + "%sauthorization_model_id%s=%s", + prefix, + suffix, + URLEncoder.encode(String.valueOf(getAuthorizationModelId()), StandardCharsets.UTF_8) + .replaceAll("\\+", "%20"))); + } + + // add `object` to the URL query string + if (getObject() != null) { + joiner.add(getObject().toUrlQueryString(prefix + "object" + suffix)); + } + + // add `relation` to the URL query string + if (getRelation() != null) { + joiner.add(String.format( + "%srelation%s=%s", + prefix, + suffix, + URLEncoder.encode(String.valueOf(getRelation()), StandardCharsets.UTF_8) + .replaceAll("\\+", "%20"))); + } + + // add `user_filters` to the URL query string + if (getUserFilters() != null) { + for (int i = 0; i < getUserFilters().size(); i++) { + if (getUserFilters().get(i) != null) { + joiner.add(getUserFilters() + .get(i) + .toUrlQueryString(String.format( + "%suser_filters%s%s", + prefix, + suffix, + "".equals(suffix) + ? "" + : String.format("%s%d%s", containerPrefix, i, containerSuffix)))); + } + } + } + + // add `contextual_tuples` to the URL query string + if (getContextualTuples() != null) { + for (int i = 0; i < getContextualTuples().size(); i++) { + if (getContextualTuples().get(i) != null) { + joiner.add(getContextualTuples() + .get(i) + .toUrlQueryString(String.format( + "%scontextual_tuples%s%s", + prefix, + suffix, + "".equals(suffix) + ? "" + : String.format("%s%d%s", containerPrefix, i, containerSuffix)))); + } + } + } + + // add `context` to the URL query string + if (getContext() != null) { + joiner.add(String.format( + "%scontext%s=%s", + prefix, + suffix, + URLEncoder.encode(String.valueOf(getContext()), StandardCharsets.UTF_8) + .replaceAll("\\+", "%20"))); + } + + return joiner.toString(); + } +} diff --git a/src/main/java/dev/openfga/sdk/api/model/ListUsersResponse.java b/src/main/java/dev/openfga/sdk/api/model/ListUsersResponse.java new file mode 100644 index 0000000..9d3ce2b --- /dev/null +++ b/src/main/java/dev/openfga/sdk/api/model/ListUsersResponse.java @@ -0,0 +1,206 @@ +/* + * OpenFGA + * A high performance and flexible authorization/permission engine built for developers and inspired by Google Zanzibar. + * + * The version of the OpenAPI document: 0.1 + * Contact: community@openfga.dev + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +package dev.openfga.sdk.api.model; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.StringJoiner; + +/** + * ListUsersResponse + */ +@JsonPropertyOrder({ListUsersResponse.JSON_PROPERTY_USERS, ListUsersResponse.JSON_PROPERTY_EXCLUDED_USERS}) +public class ListUsersResponse { + public static final String JSON_PROPERTY_USERS = "users"; + private List users = new ArrayList<>(); + + public static final String JSON_PROPERTY_EXCLUDED_USERS = "excluded_users"; + private List excludedUsers = new ArrayList<>(); + + public ListUsersResponse() {} + + public ListUsersResponse users(List users) { + this.users = users; + return this; + } + + public ListUsersResponse addUsersItem(User usersItem) { + if (this.users == null) { + this.users = new ArrayList<>(); + } + this.users.add(usersItem); + return this; + } + + /** + * Get users + * @return users + **/ + @javax.annotation.Nonnull + @JsonProperty(JSON_PROPERTY_USERS) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public List getUsers() { + return users; + } + + @JsonProperty(JSON_PROPERTY_USERS) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setUsers(List users) { + this.users = users; + } + + public ListUsersResponse excludedUsers(List excludedUsers) { + this.excludedUsers = excludedUsers; + return this; + } + + public ListUsersResponse addExcludedUsersItem(ObjectOrUserset excludedUsersItem) { + if (this.excludedUsers == null) { + this.excludedUsers = new ArrayList<>(); + } + this.excludedUsers.add(excludedUsersItem); + return this; + } + + /** + * Get excludedUsers + * @return excludedUsers + **/ + @javax.annotation.Nonnull + @JsonProperty(JSON_PROPERTY_EXCLUDED_USERS) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public List getExcludedUsers() { + return excludedUsers; + } + + @JsonProperty(JSON_PROPERTY_EXCLUDED_USERS) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setExcludedUsers(List excludedUsers) { + this.excludedUsers = excludedUsers; + } + + /** + * Return true if this ListUsersResponse object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ListUsersResponse listUsersResponse = (ListUsersResponse) o; + return Objects.equals(this.users, listUsersResponse.users) + && Objects.equals(this.excludedUsers, listUsersResponse.excludedUsers); + } + + @Override + public int hashCode() { + return Objects.hash(users, excludedUsers); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ListUsersResponse {\n"); + sb.append(" users: ").append(toIndentedString(users)).append("\n"); + sb.append(" excludedUsers: ").append(toIndentedString(excludedUsers)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + /** + * Convert the instance into URL query string. + * + * @return URL query string + */ + public String toUrlQueryString() { + return toUrlQueryString(null); + } + + /** + * Convert the instance into URL query string. + * + * @param prefix prefix of the query string + * @return URL query string + */ + public String toUrlQueryString(String prefix) { + String suffix = ""; + String containerSuffix = ""; + String containerPrefix = ""; + if (prefix == null) { + // style=form, explode=true, e.g. /pet?name=cat&type=manx + prefix = ""; + } else { + // deepObject style e.g. /pet?id[name]=cat&id[type]=manx + prefix = prefix + "["; + suffix = "]"; + containerSuffix = "]"; + containerPrefix = "["; + } + + StringJoiner joiner = new StringJoiner("&"); + + // add `users` to the URL query string + if (getUsers() != null) { + for (int i = 0; i < getUsers().size(); i++) { + if (getUsers().get(i) != null) { + joiner.add(getUsers() + .get(i) + .toUrlQueryString(String.format( + "%susers%s%s", + prefix, + suffix, + "".equals(suffix) + ? "" + : String.format("%s%d%s", containerPrefix, i, containerSuffix)))); + } + } + } + + // add `excluded_users` to the URL query string + if (getExcludedUsers() != null) { + for (int i = 0; i < getExcludedUsers().size(); i++) { + if (getExcludedUsers().get(i) != null) { + joiner.add(getExcludedUsers() + .get(i) + .toUrlQueryString(String.format( + "%sexcluded_users%s%s", + prefix, + suffix, + "".equals(suffix) + ? "" + : String.format("%s%d%s", containerPrefix, i, containerSuffix)))); + } + } + } + + return joiner.toString(); + } +} diff --git a/src/main/java/dev/openfga/sdk/api/model/ObjectOrUserset.java b/src/main/java/dev/openfga/sdk/api/model/ObjectOrUserset.java new file mode 100644 index 0000000..1a8bf07 --- /dev/null +++ b/src/main/java/dev/openfga/sdk/api/model/ObjectOrUserset.java @@ -0,0 +1,164 @@ +/* + * OpenFGA + * A high performance and flexible authorization/permission engine built for developers and inspired by Google Zanzibar. + * + * The version of the OpenAPI document: 0.1 + * Contact: community@openfga.dev + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +package dev.openfga.sdk.api.model; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import java.util.Objects; +import java.util.StringJoiner; + +/** + * ObjectOrUserset + */ +@JsonPropertyOrder({ObjectOrUserset.JSON_PROPERTY_OBJECT, ObjectOrUserset.JSON_PROPERTY_USERSET}) +public class ObjectOrUserset { + public static final String JSON_PROPERTY_OBJECT = "object"; + private FgaObject _object; + + public static final String JSON_PROPERTY_USERSET = "userset"; + private UsersetUser userset; + + public ObjectOrUserset() {} + + public ObjectOrUserset _object(FgaObject _object) { + this._object = _object; + return this; + } + + /** + * Get _object + * @return _object + **/ + @javax.annotation.Nullable + @JsonProperty(JSON_PROPERTY_OBJECT) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public FgaObject getObject() { + return _object; + } + + @JsonProperty(JSON_PROPERTY_OBJECT) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setObject(FgaObject _object) { + this._object = _object; + } + + public ObjectOrUserset userset(UsersetUser userset) { + this.userset = userset; + return this; + } + + /** + * Get userset + * @return userset + **/ + @javax.annotation.Nullable + @JsonProperty(JSON_PROPERTY_USERSET) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public UsersetUser getUserset() { + return userset; + } + + @JsonProperty(JSON_PROPERTY_USERSET) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setUserset(UsersetUser userset) { + this.userset = userset; + } + + /** + * Return true if this ObjectOrUserset object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ObjectOrUserset objectOrUserset = (ObjectOrUserset) o; + return Objects.equals(this._object, objectOrUserset._object) + && Objects.equals(this.userset, objectOrUserset.userset); + } + + @Override + public int hashCode() { + return Objects.hash(_object, userset); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ObjectOrUserset {\n"); + sb.append(" _object: ").append(toIndentedString(_object)).append("\n"); + sb.append(" userset: ").append(toIndentedString(userset)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + /** + * Convert the instance into URL query string. + * + * @return URL query string + */ + public String toUrlQueryString() { + return toUrlQueryString(null); + } + + /** + * Convert the instance into URL query string. + * + * @param prefix prefix of the query string + * @return URL query string + */ + public String toUrlQueryString(String prefix) { + String suffix = ""; + String containerSuffix = ""; + String containerPrefix = ""; + if (prefix == null) { + // style=form, explode=true, e.g. /pet?name=cat&type=manx + prefix = ""; + } else { + // deepObject style e.g. /pet?id[name]=cat&id[type]=manx + prefix = prefix + "["; + suffix = "]"; + containerSuffix = "]"; + containerPrefix = "["; + } + + StringJoiner joiner = new StringJoiner("&"); + + // add `object` to the URL query string + if (getObject() != null) { + joiner.add(getObject().toUrlQueryString(prefix + "object" + suffix)); + } + + // add `userset` to the URL query string + if (getUserset() != null) { + joiner.add(getUserset().toUrlQueryString(prefix + "userset" + suffix)); + } + + return joiner.toString(); + } +} diff --git a/src/main/java/dev/openfga/sdk/api/model/TypedWildcard.java b/src/main/java/dev/openfga/sdk/api/model/TypedWildcard.java new file mode 100644 index 0000000..0c6e04e --- /dev/null +++ b/src/main/java/dev/openfga/sdk/api/model/TypedWildcard.java @@ -0,0 +1,139 @@ +/* + * OpenFGA + * A high performance and flexible authorization/permission engine built for developers and inspired by Google Zanzibar. + * + * The version of the OpenAPI document: 0.1 + * Contact: community@openfga.dev + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +package dev.openfga.sdk.api.model; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.Objects; +import java.util.StringJoiner; + +/** + * Type bound public access. Normally represented using the `<type>:*` syntax `employee:*` represents every object of type `employee`, including those not currently present in the system See https://openfga.dev/docs/concepts#what-is-type-bound-public-access + */ +@JsonPropertyOrder({TypedWildcard.JSON_PROPERTY_TYPE}) +public class TypedWildcard { + public static final String JSON_PROPERTY_TYPE = "type"; + private String type; + + public TypedWildcard() {} + + public TypedWildcard type(String type) { + this.type = type; + return this; + } + + /** + * Get type + * @return type + **/ + @javax.annotation.Nonnull + @JsonProperty(JSON_PROPERTY_TYPE) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getType() { + return type; + } + + @JsonProperty(JSON_PROPERTY_TYPE) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setType(String type) { + this.type = type; + } + + /** + * Return true if this TypedWildcard object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + TypedWildcard typedWildcard = (TypedWildcard) o; + return Objects.equals(this.type, typedWildcard.type); + } + + @Override + public int hashCode() { + return Objects.hash(type); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class TypedWildcard {\n"); + sb.append(" type: ").append(toIndentedString(type)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + /** + * Convert the instance into URL query string. + * + * @return URL query string + */ + public String toUrlQueryString() { + return toUrlQueryString(null); + } + + /** + * Convert the instance into URL query string. + * + * @param prefix prefix of the query string + * @return URL query string + */ + public String toUrlQueryString(String prefix) { + String suffix = ""; + String containerSuffix = ""; + String containerPrefix = ""; + if (prefix == null) { + // style=form, explode=true, e.g. /pet?name=cat&type=manx + prefix = ""; + } else { + // deepObject style e.g. /pet?id[name]=cat&id[type]=manx + prefix = prefix + "["; + suffix = "]"; + containerSuffix = "]"; + containerPrefix = "["; + } + + StringJoiner joiner = new StringJoiner("&"); + + // add `type` to the URL query string + if (getType() != null) { + joiner.add(String.format( + "%stype%s=%s", + prefix, + suffix, + URLEncoder.encode(String.valueOf(getType()), StandardCharsets.UTF_8) + .replaceAll("\\+", "%20"))); + } + + return joiner.toString(); + } +} diff --git a/src/main/java/dev/openfga/sdk/api/model/UnprocessableContentErrorCode.java b/src/main/java/dev/openfga/sdk/api/model/UnprocessableContentErrorCode.java new file mode 100644 index 0000000..eebd428 --- /dev/null +++ b/src/main/java/dev/openfga/sdk/api/model/UnprocessableContentErrorCode.java @@ -0,0 +1,67 @@ +/* + * OpenFGA + * A high performance and flexible authorization/permission engine built for developers and inspired by Google Zanzibar. + * + * The version of the OpenAPI document: 0.1 + * Contact: community@openfga.dev + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +package dev.openfga.sdk.api.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Gets or Sets UnprocessableContentErrorCode + */ +public enum UnprocessableContentErrorCode { + NO_THROTTLED_ERROR_CODE("no_throttled_error_code"), + + THROTTLED_TIMEOUT_ERROR("throttled_timeout_error"), + + UNKNOWN_DEFAULT_OPEN_API("unknown_default_open_api"); + + private String value; + + UnprocessableContentErrorCode(String value) { + this.value = value; + } + + @JsonValue + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static UnprocessableContentErrorCode fromValue(String value) { + for (UnprocessableContentErrorCode b : UnprocessableContentErrorCode.values()) { + if (b.value.equals(value)) { + return b; + } + } + return UNKNOWN_DEFAULT_OPEN_API; + } + + /** + * Convert the instance into URL query string. + * + * @param prefix prefix of the query string + * @return URL query string + */ + public String toUrlQueryString(String prefix) { + if (prefix == null) { + prefix = ""; + } + + return String.format("%s=%s", prefix, this.toString()); + } +} diff --git a/src/main/java/dev/openfga/sdk/api/model/UnprocessableContentMessageResponse.java b/src/main/java/dev/openfga/sdk/api/model/UnprocessableContentMessageResponse.java new file mode 100644 index 0000000..9b70791 --- /dev/null +++ b/src/main/java/dev/openfga/sdk/api/model/UnprocessableContentMessageResponse.java @@ -0,0 +1,180 @@ +/* + * OpenFGA + * A high performance and flexible authorization/permission engine built for developers and inspired by Google Zanzibar. + * + * The version of the OpenAPI document: 0.1 + * Contact: community@openfga.dev + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +package dev.openfga.sdk.api.model; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.Objects; +import java.util.StringJoiner; + +/** + * UnprocessableContentMessageResponse + */ +@JsonPropertyOrder({ + UnprocessableContentMessageResponse.JSON_PROPERTY_CODE, + UnprocessableContentMessageResponse.JSON_PROPERTY_MESSAGE +}) +public class UnprocessableContentMessageResponse { + public static final String JSON_PROPERTY_CODE = "code"; + private UnprocessableContentErrorCode code = UnprocessableContentErrorCode.NO_THROTTLED_ERROR_CODE; + + public static final String JSON_PROPERTY_MESSAGE = "message"; + private String message; + + public UnprocessableContentMessageResponse() {} + + public UnprocessableContentMessageResponse code(UnprocessableContentErrorCode code) { + this.code = code; + return this; + } + + /** + * Get code + * @return code + **/ + @javax.annotation.Nullable + @JsonProperty(JSON_PROPERTY_CODE) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public UnprocessableContentErrorCode getCode() { + return code; + } + + @JsonProperty(JSON_PROPERTY_CODE) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setCode(UnprocessableContentErrorCode code) { + this.code = code; + } + + public UnprocessableContentMessageResponse message(String message) { + this.message = message; + return this; + } + + /** + * Get message + * @return message + **/ + @javax.annotation.Nullable + @JsonProperty(JSON_PROPERTY_MESSAGE) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public String getMessage() { + return message; + } + + @JsonProperty(JSON_PROPERTY_MESSAGE) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setMessage(String message) { + this.message = message; + } + + /** + * Return true if this UnprocessableContentMessageResponse object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + UnprocessableContentMessageResponse unprocessableContentMessageResponse = + (UnprocessableContentMessageResponse) o; + return Objects.equals(this.code, unprocessableContentMessageResponse.code) + && Objects.equals(this.message, unprocessableContentMessageResponse.message); + } + + @Override + public int hashCode() { + return Objects.hash(code, message); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class UnprocessableContentMessageResponse {\n"); + sb.append(" code: ").append(toIndentedString(code)).append("\n"); + sb.append(" message: ").append(toIndentedString(message)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + /** + * Convert the instance into URL query string. + * + * @return URL query string + */ + public String toUrlQueryString() { + return toUrlQueryString(null); + } + + /** + * Convert the instance into URL query string. + * + * @param prefix prefix of the query string + * @return URL query string + */ + public String toUrlQueryString(String prefix) { + String suffix = ""; + String containerSuffix = ""; + String containerPrefix = ""; + if (prefix == null) { + // style=form, explode=true, e.g. /pet?name=cat&type=manx + prefix = ""; + } else { + // deepObject style e.g. /pet?id[name]=cat&id[type]=manx + prefix = prefix + "["; + suffix = "]"; + containerSuffix = "]"; + containerPrefix = "["; + } + + StringJoiner joiner = new StringJoiner("&"); + + // add `code` to the URL query string + if (getCode() != null) { + joiner.add(String.format( + "%scode%s=%s", + prefix, + suffix, + URLEncoder.encode(String.valueOf(getCode()), StandardCharsets.UTF_8) + .replaceAll("\\+", "%20"))); + } + + // add `message` to the URL query string + if (getMessage() != null) { + joiner.add(String.format( + "%smessage%s=%s", + prefix, + suffix, + URLEncoder.encode(String.valueOf(getMessage()), StandardCharsets.UTF_8) + .replaceAll("\\+", "%20"))); + } + + return joiner.toString(); + } +} diff --git a/src/main/java/dev/openfga/sdk/api/model/User.java b/src/main/java/dev/openfga/sdk/api/model/User.java new file mode 100644 index 0000000..eaf20a1 --- /dev/null +++ b/src/main/java/dev/openfga/sdk/api/model/User.java @@ -0,0 +1,196 @@ +/* + * OpenFGA + * A high performance and flexible authorization/permission engine built for developers and inspired by Google Zanzibar. + * + * The version of the OpenAPI document: 0.1 + * Contact: community@openfga.dev + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +package dev.openfga.sdk.api.model; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import java.util.Objects; +import java.util.StringJoiner; + +/** + * User. Represents any possible value for a user (subject or principal). Can be a: - Specific user object e.g.: 'user:will', 'folder:marketing', 'org:contoso', ...) - Specific userset (e.g. 'group:engineering#member') - Public-typed wildcard (e.g. 'user:*') See https://openfga.dev/docs/concepts#what-is-a-user + */ +@JsonPropertyOrder({User.JSON_PROPERTY_OBJECT, User.JSON_PROPERTY_USERSET, User.JSON_PROPERTY_WILDCARD}) +public class User { + public static final String JSON_PROPERTY_OBJECT = "object"; + private FgaObject _object; + + public static final String JSON_PROPERTY_USERSET = "userset"; + private UsersetUser userset; + + public static final String JSON_PROPERTY_WILDCARD = "wildcard"; + private TypedWildcard wildcard; + + public User() {} + + public User _object(FgaObject _object) { + this._object = _object; + return this; + } + + /** + * Get _object + * @return _object + **/ + @javax.annotation.Nullable + @JsonProperty(JSON_PROPERTY_OBJECT) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public FgaObject getObject() { + return _object; + } + + @JsonProperty(JSON_PROPERTY_OBJECT) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setObject(FgaObject _object) { + this._object = _object; + } + + public User userset(UsersetUser userset) { + this.userset = userset; + return this; + } + + /** + * Get userset + * @return userset + **/ + @javax.annotation.Nullable + @JsonProperty(JSON_PROPERTY_USERSET) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public UsersetUser getUserset() { + return userset; + } + + @JsonProperty(JSON_PROPERTY_USERSET) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setUserset(UsersetUser userset) { + this.userset = userset; + } + + public User wildcard(TypedWildcard wildcard) { + this.wildcard = wildcard; + return this; + } + + /** + * Get wildcard + * @return wildcard + **/ + @javax.annotation.Nullable + @JsonProperty(JSON_PROPERTY_WILDCARD) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public TypedWildcard getWildcard() { + return wildcard; + } + + @JsonProperty(JSON_PROPERTY_WILDCARD) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setWildcard(TypedWildcard wildcard) { + this.wildcard = wildcard; + } + + /** + * Return true if this User object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + User user = (User) o; + return Objects.equals(this._object, user._object) + && Objects.equals(this.userset, user.userset) + && Objects.equals(this.wildcard, user.wildcard); + } + + @Override + public int hashCode() { + return Objects.hash(_object, userset, wildcard); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class User {\n"); + sb.append(" _object: ").append(toIndentedString(_object)).append("\n"); + sb.append(" userset: ").append(toIndentedString(userset)).append("\n"); + sb.append(" wildcard: ").append(toIndentedString(wildcard)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + /** + * Convert the instance into URL query string. + * + * @return URL query string + */ + public String toUrlQueryString() { + return toUrlQueryString(null); + } + + /** + * Convert the instance into URL query string. + * + * @param prefix prefix of the query string + * @return URL query string + */ + public String toUrlQueryString(String prefix) { + String suffix = ""; + String containerSuffix = ""; + String containerPrefix = ""; + if (prefix == null) { + // style=form, explode=true, e.g. /pet?name=cat&type=manx + prefix = ""; + } else { + // deepObject style e.g. /pet?id[name]=cat&id[type]=manx + prefix = prefix + "["; + suffix = "]"; + containerSuffix = "]"; + containerPrefix = "["; + } + + StringJoiner joiner = new StringJoiner("&"); + + // add `object` to the URL query string + if (getObject() != null) { + joiner.add(getObject().toUrlQueryString(prefix + "object" + suffix)); + } + + // add `userset` to the URL query string + if (getUserset() != null) { + joiner.add(getUserset().toUrlQueryString(prefix + "userset" + suffix)); + } + + // add `wildcard` to the URL query string + if (getWildcard() != null) { + joiner.add(getWildcard().toUrlQueryString(prefix + "wildcard" + suffix)); + } + + return joiner.toString(); + } +} diff --git a/src/main/java/dev/openfga/sdk/api/model/UserTypeFilter.java b/src/main/java/dev/openfga/sdk/api/model/UserTypeFilter.java new file mode 100644 index 0000000..3be5dc5 --- /dev/null +++ b/src/main/java/dev/openfga/sdk/api/model/UserTypeFilter.java @@ -0,0 +1,175 @@ +/* + * OpenFGA + * A high performance and flexible authorization/permission engine built for developers and inspired by Google Zanzibar. + * + * The version of the OpenAPI document: 0.1 + * Contact: community@openfga.dev + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +package dev.openfga.sdk.api.model; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.Objects; +import java.util.StringJoiner; + +/** + * UserTypeFilter + */ +@JsonPropertyOrder({UserTypeFilter.JSON_PROPERTY_TYPE, UserTypeFilter.JSON_PROPERTY_RELATION}) +public class UserTypeFilter { + public static final String JSON_PROPERTY_TYPE = "type"; + private String type; + + public static final String JSON_PROPERTY_RELATION = "relation"; + private String relation; + + public UserTypeFilter() {} + + public UserTypeFilter type(String type) { + this.type = type; + return this; + } + + /** + * Get type + * @return type + **/ + @javax.annotation.Nonnull + @JsonProperty(JSON_PROPERTY_TYPE) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getType() { + return type; + } + + @JsonProperty(JSON_PROPERTY_TYPE) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setType(String type) { + this.type = type; + } + + public UserTypeFilter relation(String relation) { + this.relation = relation; + return this; + } + + /** + * Get relation + * @return relation + **/ + @javax.annotation.Nullable + @JsonProperty(JSON_PROPERTY_RELATION) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public String getRelation() { + return relation; + } + + @JsonProperty(JSON_PROPERTY_RELATION) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setRelation(String relation) { + this.relation = relation; + } + + /** + * Return true if this UserTypeFilter object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + UserTypeFilter userTypeFilter = (UserTypeFilter) o; + return Objects.equals(this.type, userTypeFilter.type) && Objects.equals(this.relation, userTypeFilter.relation); + } + + @Override + public int hashCode() { + return Objects.hash(type, relation); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class UserTypeFilter {\n"); + sb.append(" type: ").append(toIndentedString(type)).append("\n"); + sb.append(" relation: ").append(toIndentedString(relation)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + /** + * Convert the instance into URL query string. + * + * @return URL query string + */ + public String toUrlQueryString() { + return toUrlQueryString(null); + } + + /** + * Convert the instance into URL query string. + * + * @param prefix prefix of the query string + * @return URL query string + */ + public String toUrlQueryString(String prefix) { + String suffix = ""; + String containerSuffix = ""; + String containerPrefix = ""; + if (prefix == null) { + // style=form, explode=true, e.g. /pet?name=cat&type=manx + prefix = ""; + } else { + // deepObject style e.g. /pet?id[name]=cat&id[type]=manx + prefix = prefix + "["; + suffix = "]"; + containerSuffix = "]"; + containerPrefix = "["; + } + + StringJoiner joiner = new StringJoiner("&"); + + // add `type` to the URL query string + if (getType() != null) { + joiner.add(String.format( + "%stype%s=%s", + prefix, + suffix, + URLEncoder.encode(String.valueOf(getType()), StandardCharsets.UTF_8) + .replaceAll("\\+", "%20"))); + } + + // add `relation` to the URL query string + if (getRelation() != null) { + joiner.add(String.format( + "%srelation%s=%s", + prefix, + suffix, + URLEncoder.encode(String.valueOf(getRelation()), StandardCharsets.UTF_8) + .replaceAll("\\+", "%20"))); + } + + return joiner.toString(); + } +} diff --git a/src/main/java/dev/openfga/sdk/api/model/UsersetUser.java b/src/main/java/dev/openfga/sdk/api/model/UsersetUser.java new file mode 100644 index 0000000..e2ae901 --- /dev/null +++ b/src/main/java/dev/openfga/sdk/api/model/UsersetUser.java @@ -0,0 +1,213 @@ +/* + * OpenFGA + * A high performance and flexible authorization/permission engine built for developers and inspired by Google Zanzibar. + * + * The version of the OpenAPI document: 0.1 + * Contact: community@openfga.dev + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +package dev.openfga.sdk.api.model; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.Objects; +import java.util.StringJoiner; + +/** + * Userset. A set or group of users, represented in the `<type>:<id>#<relation>` format `group:fga#member` represents all members of group FGA, not to be confused by `group:fga` which represents the group itself as a specific object. See: https://openfga.dev/docs/modeling/building-blocks/usersets#what-is-a-userset + */ +@JsonPropertyOrder({UsersetUser.JSON_PROPERTY_TYPE, UsersetUser.JSON_PROPERTY_ID, UsersetUser.JSON_PROPERTY_RELATION}) +public class UsersetUser { + public static final String JSON_PROPERTY_TYPE = "type"; + private String type; + + public static final String JSON_PROPERTY_ID = "id"; + private String id; + + public static final String JSON_PROPERTY_RELATION = "relation"; + private String relation; + + public UsersetUser() {} + + public UsersetUser type(String type) { + this.type = type; + return this; + } + + /** + * Get type + * @return type + **/ + @javax.annotation.Nonnull + @JsonProperty(JSON_PROPERTY_TYPE) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getType() { + return type; + } + + @JsonProperty(JSON_PROPERTY_TYPE) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setType(String type) { + this.type = type; + } + + public UsersetUser id(String id) { + this.id = id; + return this; + } + + /** + * Get id + * @return id + **/ + @javax.annotation.Nonnull + @JsonProperty(JSON_PROPERTY_ID) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getId() { + return id; + } + + @JsonProperty(JSON_PROPERTY_ID) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setId(String id) { + this.id = id; + } + + public UsersetUser relation(String relation) { + this.relation = relation; + return this; + } + + /** + * Get relation + * @return relation + **/ + @javax.annotation.Nonnull + @JsonProperty(JSON_PROPERTY_RELATION) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getRelation() { + return relation; + } + + @JsonProperty(JSON_PROPERTY_RELATION) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setRelation(String relation) { + this.relation = relation; + } + + /** + * Return true if this UsersetUser object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + UsersetUser usersetUser = (UsersetUser) o; + return Objects.equals(this.type, usersetUser.type) + && Objects.equals(this.id, usersetUser.id) + && Objects.equals(this.relation, usersetUser.relation); + } + + @Override + public int hashCode() { + return Objects.hash(type, id, relation); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class UsersetUser {\n"); + sb.append(" type: ").append(toIndentedString(type)).append("\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" relation: ").append(toIndentedString(relation)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + /** + * Convert the instance into URL query string. + * + * @return URL query string + */ + public String toUrlQueryString() { + return toUrlQueryString(null); + } + + /** + * Convert the instance into URL query string. + * + * @param prefix prefix of the query string + * @return URL query string + */ + public String toUrlQueryString(String prefix) { + String suffix = ""; + String containerSuffix = ""; + String containerPrefix = ""; + if (prefix == null) { + // style=form, explode=true, e.g. /pet?name=cat&type=manx + prefix = ""; + } else { + // deepObject style e.g. /pet?id[name]=cat&id[type]=manx + prefix = prefix + "["; + suffix = "]"; + containerSuffix = "]"; + containerPrefix = "["; + } + + StringJoiner joiner = new StringJoiner("&"); + + // add `type` to the URL query string + if (getType() != null) { + joiner.add(String.format( + "%stype%s=%s", + prefix, + suffix, + URLEncoder.encode(String.valueOf(getType()), StandardCharsets.UTF_8) + .replaceAll("\\+", "%20"))); + } + + // add `id` to the URL query string + if (getId() != null) { + joiner.add(String.format( + "%sid%s=%s", + prefix, + suffix, + URLEncoder.encode(String.valueOf(getId()), StandardCharsets.UTF_8) + .replaceAll("\\+", "%20"))); + } + + // add `relation` to the URL query string + if (getRelation() != null) { + joiner.add(String.format( + "%srelation%s=%s", + prefix, + suffix, + URLEncoder.encode(String.valueOf(getRelation()), StandardCharsets.UTF_8) + .replaceAll("\\+", "%20"))); + } + + return joiner.toString(); + } +} diff --git a/src/test/java/dev/openfga/sdk/api/client/OpenFgaClientTest.java b/src/test/java/dev/openfga/sdk/api/client/OpenFgaClientTest.java index 92e9c72..c14b36d 100644 --- a/src/test/java/dev/openfga/sdk/api/client/OpenFgaClientTest.java +++ b/src/test/java/dev/openfga/sdk/api/client/OpenFgaClientTest.java @@ -26,6 +26,7 @@ import dev.openfga.sdk.errors.*; import java.net.http.HttpClient; import java.time.Duration; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; @@ -51,7 +52,8 @@ public class OpenFgaClientTest { private static final String DEFAULT_USER = "user:81684243-9356-4421-8fbf-a4f8d36aa31b"; private static final String DEFAULT_RELATION = "reader"; private static final String DEFAULT_TYPE = "document"; - private static final String DEFAULT_OBJECT = "document:budget"; + private static final String DEFAULT_ID = "budget"; + private static final String DEFAULT_OBJECT = DEFAULT_TYPE + ":" + DEFAULT_ID; private static final String DEFAULT_SCHEMA_VERSION = "1.1"; private static final String EMPTY_RESPONSE_BODY = "{}"; private static final ClientRelationshipCondition DEFAULT_CONDITION = @@ -2327,6 +2329,51 @@ public void listRelations_contextAndContextualTuples() throws Exception { assertTrue(response.getRelations().isEmpty()); } + /** + * Test list users + */ + @Test + public void listUsersTest() throws Exception { + // Given + String postPath = String.format("https://api.fga.example/stores/%s/list-users", DEFAULT_STORE_ID); + String expectedBody = String.format( + "{\"authorization_model_id\":\"%s\",\"object\":{\"type\":\"%s\",\"id\":\"%s\"},\"relation\":\"%s\",\"user_filters\":[{\"type\":\"user\",\"relation\":null},{\"type\":\"team\",\"relation\":\"member\"}],\"contextual_tuples\":[],\"context\":null}", + DEFAULT_AUTH_MODEL_ID, DEFAULT_TYPE, DEFAULT_ID, DEFAULT_RELATION); + mockHttpClient + .onPost(postPath) + .withBody(is(expectedBody)) + .doReturn( + 200, + "{\"excluded_users\":null,\"users\":[{\"object\":{\"id\":\"81684243-9356-4421-8fbf-a4f8d36aa31b\",\"type\":\"user\"}},{\"userset\":{\"id\":\"fga\",\"relation\":\"member\",\"type\":\"team\"}},{\"wildcard\":{\"type\":\"user\"}}]}"); + + ClientListUsersRequest request = new ClientListUsersRequest() + ._object(new FgaObject().type(DEFAULT_TYPE).id(DEFAULT_ID)) + .relation(DEFAULT_RELATION) + .userFilters(new ArrayList<>() { + { + add(new UserTypeFilter().type("user")); + add(new UserTypeFilter().type("team").relation("member")); + } + }); + + // When + ClientListUsersResponse response = fga.listUsers(request).get(); + + // Then + mockHttpClient.verify().post(postPath).withBody(is(expectedBody)).called(1); + + assertEquals( + List.of( + new User()._object(new FgaObject().type("user").id("81684243-9356-4421-8fbf-a4f8d36aa31b")), + new User() + .userset( + new UsersetUser().type("team").id("fga").relation("member")), + new User().wildcard(new TypedWildcard().type("user"))), + response.getUsers()); + + assertNull(response.getExcludedUsers()); + } + /** * Read assertions for an authorization model ID. */ From 6b38a68c7e3aa28685e48a216a7e83d7c4a752bd Mon Sep 17 00:00:00 2001 From: Ewan Harris Date: Wed, 1 May 2024 15:40:13 +0100 Subject: [PATCH 2/2] chore: update model id environment variable --- .../src/main/java/dev/openfga/sdk/example/Example1.java | 2 +- .../src/main/kotlin/dev/openfga/sdk/example/KotlinExample1.kt | 2 +- .../java/dev/openfga/sdk/example/Example1.java | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/example/example1/src/main/java/dev/openfga/sdk/example/Example1.java b/example/example1/src/main/java/dev/openfga/sdk/example/Example1.java index d17c42a..efbb7ba 100644 --- a/example/example1/src/main/java/dev/openfga/sdk/example/Example1.java +++ b/example/example1/src/main/java/dev/openfga/sdk/example/Example1.java @@ -29,7 +29,7 @@ public void run(String apiUrl) throws Exception { .apiUrl(apiUrl) // required, e.g. https://api.fga.example .storeId(System.getenv("FGA_STORE_ID")) // not needed when calling `CreateStore` or `ListStores` .authorizationModelId( - System.getenv("FGA_AUTHORIZATION_MODEL_ID")) // Optional, can be overridden per request + System.getenv("FGA_MODEL_ID")) // Optional, can be overridden per request .credentials(credentials); var fgaClient = new OpenFgaClient(configuration); diff --git a/example/example1/src/main/kotlin/dev/openfga/sdk/example/KotlinExample1.kt b/example/example1/src/main/kotlin/dev/openfga/sdk/example/KotlinExample1.kt index 8dd22de..ee28726 100644 --- a/example/example1/src/main/kotlin/dev/openfga/sdk/example/KotlinExample1.kt +++ b/example/example1/src/main/kotlin/dev/openfga/sdk/example/KotlinExample1.kt @@ -30,7 +30,7 @@ internal class KotlinExample1 { .apiUrl(System.getenv("FGA_API_URL")) // required, e.g. https://api.fga.example .storeId(System.getenv("FGA_STORE_ID")) // not needed when calling `CreateStore` or `ListStores` .authorizationModelId( - System.getenv("FGA_AUTHORIZATION_MODEL_ID") + System.getenv("FGA_MODEL_ID") ) // Optional, can be overridden per request .credentials(credentials) val fgaClient = OpenFgaClient(configuration) diff --git a/src/test-integration/java/dev/openfga/sdk/example/Example1.java b/src/test-integration/java/dev/openfga/sdk/example/Example1.java index d17c42a..3d3d7af 100644 --- a/src/test-integration/java/dev/openfga/sdk/example/Example1.java +++ b/src/test-integration/java/dev/openfga/sdk/example/Example1.java @@ -28,8 +28,7 @@ public void run(String apiUrl) throws Exception { var configuration = new ClientConfiguration() .apiUrl(apiUrl) // required, e.g. https://api.fga.example .storeId(System.getenv("FGA_STORE_ID")) // not needed when calling `CreateStore` or `ListStores` - .authorizationModelId( - System.getenv("FGA_AUTHORIZATION_MODEL_ID")) // Optional, can be overridden per request + .authorizationModelId(System.getenv("FGA_MODEL_ID")) // Optional, can be overridden per request .credentials(credentials); var fgaClient = new OpenFgaClient(configuration);