diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index b929a17..1259d81 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -61,4 +61,4 @@ By submitting an issue to this repository, you agree to the terms within the [Op > A clear and concise description of what you expected to happen. ### Additional context -> Add any other context about the problem here. \ No newline at end of file +> Add any other context about the problem here. diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml new file mode 100644 index 0000000..af577f3 --- /dev/null +++ b/.github/dependabot.yaml @@ -0,0 +1,18 @@ +version: 2 +updates: + - package-ecosystem: "nuget" + directory: "/" + schedule: + interval: "monthly" + groups: + dependencies: + patterns: + - "*" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "monthly" + groups: + dependencies: + patterns: + - "*" diff --git a/.openapi-generator/FILES b/.openapi-generator/FILES index c3f6e41..b233f85 100644 --- a/.openapi-generator/FILES +++ b/.openapi-generator/FILES @@ -3,6 +3,7 @@ .github/CODEOWNERS .github/ISSUE_TEMPLATE/bug_report.md .github/ISSUE_TEMPLATE/feature_request.md +.github/dependabot.yaml .github/workflows/main.yaml .github/workflows/semgrep.yaml .gitignore @@ -14,18 +15,24 @@ OpenFga.Sdk.sln README.md VERSION.txt assets/FGAIcon.png +docs/AbortedMessageResponse.md docs/Any.md docs/Assertion.md +docs/AssertionTupleKey.md docs/AuthorizationModel.md docs/CheckRequest.md +docs/CheckRequestTupleKey.md docs/CheckResponse.md docs/Computed.md +docs/Condition.md +docs/ConditionParamTypeRef.md docs/ContextualTupleKeys.md docs/CreateStoreRequest.md docs/CreateStoreResponse.md docs/Difference.md docs/ErrorCode.md docs/ExpandRequest.md +docs/ExpandRequestTupleKey.md docs/ExpandResponse.md docs/GetStoreResponse.md docs/InternalErrorCode.md @@ -38,6 +45,7 @@ docs/Metadata.md docs/Node.md docs/Nodes.md docs/NotFoundErrorCode.md +docs/NullValue.md docs/ObjectRelation.md docs/OpenFgaApi.md docs/PathUnknownErrorMessageResponse.md @@ -46,18 +54,21 @@ docs/ReadAuthorizationModelResponse.md docs/ReadAuthorizationModelsResponse.md docs/ReadChangesResponse.md docs/ReadRequest.md +docs/ReadRequestTupleKey.md docs/ReadResponse.md docs/RelationMetadata.md docs/RelationReference.md +docs/RelationshipCondition.md docs/Status.md docs/Store.md docs/Tuple.md docs/TupleChange.md docs/TupleKey.md -docs/TupleKeys.md +docs/TupleKeyWithoutCondition.md docs/TupleOperation.md docs/TupleToUserset.md docs/TypeDefinition.md +docs/TypeName.md docs/Users.md docs/Userset.md docs/UsersetTree.md @@ -69,6 +80,12 @@ docs/WriteAssertionsRequest.md docs/WriteAuthorizationModelRequest.md docs/WriteAuthorizationModelResponse.md docs/WriteRequest.md +docs/WriteRequestDeletes.md +docs/WriteRequestWrites.md +example/Example1/Example1.cs +example/Example1/Example1.csproj +example/Makefile +example/README.md src/OpenFga.Sdk.Test/Api/OpenFgaApiTests.cs src/OpenFga.Sdk.Test/Client/OpenFgaClientTests.cs src/OpenFga.Sdk.Test/Models/ModelTests.cs @@ -105,7 +122,9 @@ src/OpenFga.Sdk/Client/Model/ClientReadOptions.cs src/OpenFga.Sdk/Client/Model/ClientReadRequest.cs src/OpenFga.Sdk/Client/Model/ClientRequestOptions.cs src/OpenFga.Sdk/Client/Model/ClientRequestOptsWithAuthZModelId.cs +src/OpenFga.Sdk/Client/Model/ClientRequestOptsWithStoreId.cs src/OpenFga.Sdk/Client/Model/ClientTupleKey.cs +src/OpenFga.Sdk/Client/Model/ClientTupleKeyWithoutCondition.cs src/OpenFga.Sdk/Client/Model/ClientWriteAssertionsOptions.cs src/OpenFga.Sdk/Client/Model/ClientWriteAssertionsRequest.cs src/OpenFga.Sdk/Client/Model/ClientWriteAuthorizationModelRequest.cs @@ -114,6 +133,7 @@ src/OpenFga.Sdk/Client/Model/ClientWriteRequest.cs src/OpenFga.Sdk/Client/Model/ClientWriteResponse.cs src/OpenFga.Sdk/Client/Model/ClientWriteStatus.cs src/OpenFga.Sdk/Client/Model/RetryParams.cs +src/OpenFga.Sdk/Client/Model/StoreIdOptions.cs src/OpenFga.Sdk/Configuration/Configuration.cs src/OpenFga.Sdk/Configuration/Credentials.cs src/OpenFga.Sdk/Exceptions/ApiAuthenticationError.cs @@ -128,19 +148,25 @@ src/OpenFga.Sdk/Exceptions/Parsers/RateLimitParser.cs src/OpenFga.Sdk/Exceptions/RateLimitExceededError.cs src/OpenFga.Sdk/Exceptions/RequiredParamError.cs src/OpenFga.Sdk/Exceptions/ValidationError.cs +src/OpenFga.Sdk/Model/AbortedMessageResponse.cs src/OpenFga.Sdk/Model/AbstractOpenAPISchema.cs src/OpenFga.Sdk/Model/Any.cs src/OpenFga.Sdk/Model/Assertion.cs +src/OpenFga.Sdk/Model/AssertionTupleKey.cs src/OpenFga.Sdk/Model/AuthorizationModel.cs src/OpenFga.Sdk/Model/CheckRequest.cs +src/OpenFga.Sdk/Model/CheckRequestTupleKey.cs src/OpenFga.Sdk/Model/CheckResponse.cs src/OpenFga.Sdk/Model/Computed.cs +src/OpenFga.Sdk/Model/Condition.cs +src/OpenFga.Sdk/Model/ConditionParamTypeRef.cs src/OpenFga.Sdk/Model/ContextualTupleKeys.cs src/OpenFga.Sdk/Model/CreateStoreRequest.cs src/OpenFga.Sdk/Model/CreateStoreResponse.cs src/OpenFga.Sdk/Model/Difference.cs src/OpenFga.Sdk/Model/ErrorCode.cs src/OpenFga.Sdk/Model/ExpandRequest.cs +src/OpenFga.Sdk/Model/ExpandRequestTupleKey.cs src/OpenFga.Sdk/Model/ExpandResponse.cs src/OpenFga.Sdk/Model/GetStoreResponse.cs src/OpenFga.Sdk/Model/InternalErrorCode.cs @@ -154,6 +180,7 @@ src/OpenFga.Sdk/Model/Metadata.cs src/OpenFga.Sdk/Model/Node.cs src/OpenFga.Sdk/Model/Nodes.cs src/OpenFga.Sdk/Model/NotFoundErrorCode.cs +src/OpenFga.Sdk/Model/NullValue.cs src/OpenFga.Sdk/Model/ObjectRelation.cs src/OpenFga.Sdk/Model/PathUnknownErrorMessageResponse.cs src/OpenFga.Sdk/Model/ReadAssertionsResponse.cs @@ -161,18 +188,21 @@ src/OpenFga.Sdk/Model/ReadAuthorizationModelResponse.cs src/OpenFga.Sdk/Model/ReadAuthorizationModelsResponse.cs src/OpenFga.Sdk/Model/ReadChangesResponse.cs src/OpenFga.Sdk/Model/ReadRequest.cs +src/OpenFga.Sdk/Model/ReadRequestTupleKey.cs src/OpenFga.Sdk/Model/ReadResponse.cs src/OpenFga.Sdk/Model/RelationMetadata.cs src/OpenFga.Sdk/Model/RelationReference.cs +src/OpenFga.Sdk/Model/RelationshipCondition.cs src/OpenFga.Sdk/Model/Status.cs src/OpenFga.Sdk/Model/Store.cs src/OpenFga.Sdk/Model/Tuple.cs src/OpenFga.Sdk/Model/TupleChange.cs src/OpenFga.Sdk/Model/TupleKey.cs -src/OpenFga.Sdk/Model/TupleKeys.cs +src/OpenFga.Sdk/Model/TupleKeyWithoutCondition.cs src/OpenFga.Sdk/Model/TupleOperation.cs src/OpenFga.Sdk/Model/TupleToUserset.cs src/OpenFga.Sdk/Model/TypeDefinition.cs +src/OpenFga.Sdk/Model/TypeName.cs src/OpenFga.Sdk/Model/Users.cs src/OpenFga.Sdk/Model/Userset.cs src/OpenFga.Sdk/Model/UsersetTree.cs @@ -184,4 +214,6 @@ src/OpenFga.Sdk/Model/WriteAssertionsRequest.cs src/OpenFga.Sdk/Model/WriteAuthorizationModelRequest.cs src/OpenFga.Sdk/Model/WriteAuthorizationModelResponse.cs src/OpenFga.Sdk/Model/WriteRequest.cs +src/OpenFga.Sdk/Model/WriteRequestDeletes.cs +src/OpenFga.Sdk/Model/WriteRequestWrites.cs src/OpenFga.Sdk/OpenFga.Sdk.csproj diff --git a/CHANGELOG.md b/CHANGELOG.md index d902d71..849ca0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,60 @@ # Changelog +## v0.3.0 + +### [0.3.0](https://github.com/openfga/dotnet-sdk/compare/v0.2.5...v0.3.0) (2023-12-20) +- feat!: initial support for conditions +- feat!: allow overriding storeId per request (#33) +- feat: support specifying a port and path for the API (You can now set the `ApiUrl` to something like: `https://api.fga.exampleL8080/some_path`) +- feat: validate that store id and auth model id in ulid format (#23) +- fix: exception when using the same configuration with multiple clients (#26) +- fix: `OpenFgaClient.ReadLatestAuthorizationModel` can now return a null if no model has ever been created in that store +- fix: `OpenFgaClient.Read` and `OpenFgaClient.ReadChanges` now allow a null body +- chore!: use latest API interfaces +- chore: dependency updates + +BREAKING CHANGES: +Note: This release comes with substantial breaking changes, especially to the interfaces due to the protobuf changes in the last release. + +While the http interfaces did not break (you can still use `v0.2.5` SDK with a `v1.3.8+` server), +the grpc interface did and this caused a few changes in the interfaces of the SDK. + +If you are using `OpenFgaClient`, the changes required should be smaller, if you are using `OpenFgaApi` a bit more changes will be needed. + +You will have to modify some parts of your code, but we hope this will be to the better as a lot of the parameters are now correctly marked as required, +and so the Pointer-to-String conversion is no longer needed. + +Some of the changes to expect: + +- When initializing a client, please use `ApiUrl`. The separate `ApiScheme` and `ApiHost` fields have been deprecated +```csharp +var configuration = new ClientConfiguration() { + ApiUrl = Environment.GetEnvironmentVariable("FGA_API_URL"), // required, e.g. https://api.fga.example + StoreId = Environment.GetEnvironmentVariable("FGA_STORE_ID"), // not needed when calling `CreateStore` or `ListStores` + AuthorizationModelId = Environment.GetEnvironmentVariable("FGA_AUTHORIZATION_MODEL_ID"), // Optional, can be overridden per request +}; +var fgaClient = new OpenFgaClient(configuration); +``` +- `OpenFgaApi` now requires `storeId` as first param when needed +- `Configuration` no longer accepts `storeId` (`ClientConfiguration` is not affected) +- The following request interfaces changed: + - `CheckRequest`: the `TupleKey` field is now of interface `CheckRequestTupleKey`, you can also now pass in `Context` + - `ExpandRequest`: the `TupleKey` field is now of interface `ExpandRequestTupleKey` + - `ReadRequest`: the `TupleKey` field is now of interface `ReadRequestTupleKey` + - `WriteRequest`: now takes `WriteRequestWrites` and `WriteRequestDeletes`, the latter of which accepts `TupleKeyWithoutCondition` + - And more +- The following interfaces had fields that were pointers are are now the direct value: + - `CreateStoreResponse` + - `GetStoreResponse` + - `ListStoresResponse` + - `ListObjectsResponse` + - `ReadChangesResponse` + - `ReadResponse` + - `AuthorizationModel` + - And more + +Take a look at https://github.com/openfga/dotnet-sdk/commit/fa43463ded102df3f660bae6d741e1a8c1dea090 for more model changes. + ## v0.2.5 ### [0.2.5](https://github.com/openfga/dotnet-sdk/compare/v0.2.4...v0.2.5) (2023-12-01) diff --git a/README.md b/README.md index 5a174e5..cf13bb0 100644 --- a/README.md +++ b/README.md @@ -108,10 +108,9 @@ namespace Example { public static async Task Main() { try { var configuration = new ClientConfiguration() { - ApiScheme = Environment.GetEnvironmentVariable("OPENFGA_API_SCHEME"), // optional, defaults to "https" - ApiHost = Environment.GetEnvironmentVariable("OPENFGA_API_HOST"), // required, define without the scheme (e.g. api.fga.example instead of https://api.fga.example) - StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), // not needed when calling `CreateStore` or `ListStores` - AuthorizationModelId = Environment.GetEnvironmentVariable("OPENFGA_AUTHORIZATION_MODEL_ID"), // Optional, can be overridden per request + ApiUrl = Environment.GetEnvironmentVariable("FGA_API_URL") ?? "http://localhost:8080", // required, e.g. https://api.fga.example + StoreId = Environment.GetEnvironmentVariable("FGA_STORE_ID"), // not needed when calling `CreateStore` or `ListStores` + AuthorizationModelId = Environment.GetEnvironmentVariable("FGA_AUTHORIZATION_MODEL_ID"), // Optional, can be overridden per request }; var fgaClient = new OpenFgaClient(configuration); var response = await fgaClient.ReadAuthorizationModels(); @@ -135,14 +134,13 @@ namespace Example { public static async Task Main() { try { var configuration = new ClientConfiguration() { - ApiScheme = Environment.GetEnvironmentVariable("OPENFGA_API_SCHEME"), // optional, defaults to "https" - ApiHost = Environment.GetEnvironmentVariable("OPENFGA_API_HOST"), // required, define without the scheme (e.g. api.fga.example instead of https://api.fga.example) - StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), // not needed when calling `CreateStore` or `ListStores` - AuthorizationModelId = Environment.GetEnvironmentVariable("OPENFGA_AUTHORIZATION_MODEL_ID"), // Optional, can be overridden per request + ApiUrl = Environment.GetEnvironmentVariable("FGA_API_URL") ?? "http://localhost:8080", // required, e.g. https://api.fga.example + StoreId = Environment.GetEnvironmentVariable("FGA_STORE_ID"), // not needed when calling `CreateStore` or `ListStores` + AuthorizationModelId = Environment.GetEnvironmentVariable("FGA_AUTHORIZATION_MODEL_ID"), // Optional, can be overridden per request Credentials = new Credentials() { Method = CredentialsMethod.ApiToken, Config = new CredentialsConfig() { - ApiToken = Environment.GetEnvironmentVariable("OPENFGA_API_TOKEN"), // will be passed as the "Authorization: Bearer ${ApiToken}" request header + ApiToken = Environment.GetEnvironmentVariable("FGA_API_TOKEN"), // will be passed as the "Authorization: Bearer ${ApiToken}" request header } } }; @@ -168,17 +166,16 @@ namespace Example { public static async Task Main() { try { var configuration = new ClientConfiguration() { - ApiScheme = Environment.GetEnvironmentVariable("OPENFGA_API_SCHEME"), // optional, defaults to "https" - ApiHost = Environment.GetEnvironmentVariable("OPENFGA_API_HOST"), // required, define without the scheme (e.g. api.fga.example instead of https://api.fga.example) - StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), // not needed when calling `CreateStore` or `ListStores` - AuthorizationModelId = Environment.GetEnvironmentVariable("OPENFGA_AUTHORIZATION_MODEL_ID"), // Optional, can be overridden per request + ApiUrl = Environment.GetEnvironmentVariable("FGA_API_URL") ?? "http://localhost:8080", // required, e.g. https://api.fga.example + StoreId = Environment.GetEnvironmentVariable("FGA_STORE_ID"), // not needed when calling `CreateStore` or `ListStores` + AuthorizationModelId = Environment.GetEnvironmentVariable("FGA_AUTHORIZATION_MODEL_ID"), // Optional, can be overridden per request Credentials = new Credentials() { Method = CredentialsMethod.ClientCredentials, Config = new CredentialsConfig() { - ApiTokenIssuer = Environment.GetEnvironmentVariable("OPENFGA_API_TOKEN_ISSUER"), - ApiAudience = Environment.GetEnvironmentVariable("OPENFGA_API_AUDIENCE"), - ClientId = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_ID"), - ClientSecret = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_SECRET"), + ApiTokenIssuer = Environment.GetEnvironmentVariable("FGA_API_TOKEN_ISSUER"), + ApiAudience = Environment.GetEnvironmentVariable("FGA_API_AUDIENCE"), + ClientId = Environment.GetEnvironmentVariable("FGA_CLIENT_ID"), + ClientSecret = Environment.GetEnvironmentVariable("FGA_CLIENT_SECRET"), } } }; @@ -465,7 +462,7 @@ var body = new ClientWriteRequest() { Object = "document:budget", } }, - Deletes = new List { + Deletes = new List { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "writer", @@ -500,7 +497,7 @@ var body = new ClientWriteRequest() { Object = "document:budget", } }, - Deletes = new List { + Deletes = new List { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "writer", @@ -768,18 +765,24 @@ await fgaClient.WriteAssertions(body, options); ### Models + - [Model.AbortedMessageResponse](docs/AbortedMessageResponse.md) - [Model.Any](docs/Any.md) - [Model.Assertion](docs/Assertion.md) + - [Model.AssertionTupleKey](docs/AssertionTupleKey.md) - [Model.AuthorizationModel](docs/AuthorizationModel.md) - [Model.CheckRequest](docs/CheckRequest.md) + - [Model.CheckRequestTupleKey](docs/CheckRequestTupleKey.md) - [Model.CheckResponse](docs/CheckResponse.md) - [Model.Computed](docs/Computed.md) + - [Model.Condition](docs/Condition.md) + - [Model.ConditionParamTypeRef](docs/ConditionParamTypeRef.md) - [Model.ContextualTupleKeys](docs/ContextualTupleKeys.md) - [Model.CreateStoreRequest](docs/CreateStoreRequest.md) - [Model.CreateStoreResponse](docs/CreateStoreResponse.md) - [Model.Difference](docs/Difference.md) - [Model.ErrorCode](docs/ErrorCode.md) - [Model.ExpandRequest](docs/ExpandRequest.md) + - [Model.ExpandRequestTupleKey](docs/ExpandRequestTupleKey.md) - [Model.ExpandResponse](docs/ExpandResponse.md) - [Model.GetStoreResponse](docs/GetStoreResponse.md) - [Model.InternalErrorCode](docs/InternalErrorCode.md) @@ -792,6 +795,7 @@ await fgaClient.WriteAssertions(body, options); - [Model.Node](docs/Node.md) - [Model.Nodes](docs/Nodes.md) - [Model.NotFoundErrorCode](docs/NotFoundErrorCode.md) + - [Model.NullValue](docs/NullValue.md) - [Model.ObjectRelation](docs/ObjectRelation.md) - [Model.PathUnknownErrorMessageResponse](docs/PathUnknownErrorMessageResponse.md) - [Model.ReadAssertionsResponse](docs/ReadAssertionsResponse.md) @@ -799,18 +803,21 @@ await fgaClient.WriteAssertions(body, options); - [Model.ReadAuthorizationModelsResponse](docs/ReadAuthorizationModelsResponse.md) - [Model.ReadChangesResponse](docs/ReadChangesResponse.md) - [Model.ReadRequest](docs/ReadRequest.md) + - [Model.ReadRequestTupleKey](docs/ReadRequestTupleKey.md) - [Model.ReadResponse](docs/ReadResponse.md) - [Model.RelationMetadata](docs/RelationMetadata.md) - [Model.RelationReference](docs/RelationReference.md) + - [Model.RelationshipCondition](docs/RelationshipCondition.md) - [Model.Status](docs/Status.md) - [Model.Store](docs/Store.md) - [Model.Tuple](docs/Tuple.md) - [Model.TupleChange](docs/TupleChange.md) - [Model.TupleKey](docs/TupleKey.md) - - [Model.TupleKeys](docs/TupleKeys.md) + - [Model.TupleKeyWithoutCondition](docs/TupleKeyWithoutCondition.md) - [Model.TupleOperation](docs/TupleOperation.md) - [Model.TupleToUserset](docs/TupleToUserset.md) - [Model.TypeDefinition](docs/TypeDefinition.md) + - [Model.TypeName](docs/TypeName.md) - [Model.Users](docs/Users.md) - [Model.Userset](docs/Userset.md) - [Model.UsersetTree](docs/UsersetTree.md) @@ -822,6 +829,8 @@ await fgaClient.WriteAssertions(body, options); - [Model.WriteAuthorizationModelRequest](docs/WriteAuthorizationModelRequest.md) - [Model.WriteAuthorizationModelResponse](docs/WriteAuthorizationModelResponse.md) - [Model.WriteRequest](docs/WriteRequest.md) + - [Model.WriteRequestDeletes](docs/WriteRequestDeletes.md) + - [Model.WriteRequestWrites](docs/WriteRequestWrites.md) diff --git a/docs/AbortedMessageResponse.md b/docs/AbortedMessageResponse.md new file mode 100644 index 0000000..5958c7f --- /dev/null +++ b/docs/AbortedMessageResponse.md @@ -0,0 +1,11 @@ +# OpenFga.Sdk.Model.AbortedMessageResponse + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Code** | **string** | | [optional] +**Message** | **string** | | [optional] + +[[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) + diff --git a/docs/Assertion.md b/docs/Assertion.md index f6f8cad..2a6031b 100644 --- a/docs/Assertion.md +++ b/docs/Assertion.md @@ -4,7 +4,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**TupleKey** | [**TupleKey**](TupleKey.md) | | +**TupleKey** | [**AssertionTupleKey**](AssertionTupleKey.md) | | **Expectation** | **bool** | | [[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) diff --git a/docs/AssertionTupleKey.md b/docs/AssertionTupleKey.md new file mode 100644 index 0000000..a0e582c --- /dev/null +++ b/docs/AssertionTupleKey.md @@ -0,0 +1,12 @@ +# OpenFga.Sdk.Model.AssertionTupleKey + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Object** | **string** | | +**Relation** | **string** | | +**User** | **string** | | + +[[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) + diff --git a/docs/AuthorizationModel.md b/docs/AuthorizationModel.md index 7150850..4c1d4f0 100644 --- a/docs/AuthorizationModel.md +++ b/docs/AuthorizationModel.md @@ -4,9 +4,10 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**Id** | **string** | | [optional] +**Id** | **string** | | **SchemaVersion** | **string** | | -**TypeDefinitions** | [**List<TypeDefinition>**](TypeDefinition.md) | | [optional] +**TypeDefinitions** | [**List<TypeDefinition>**](TypeDefinition.md) | | +**Conditions** | [**Dictionary<string, Condition>**](Condition.md) | | [optional] [[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) diff --git a/docs/CheckRequest.md b/docs/CheckRequest.md index b795ce7..fa521aa 100644 --- a/docs/CheckRequest.md +++ b/docs/CheckRequest.md @@ -4,10 +4,11 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**TupleKey** | [**TupleKey**](TupleKey.md) | | +**TupleKey** | [**CheckRequestTupleKey**](CheckRequestTupleKey.md) | | **ContextualTuples** | [**ContextualTupleKeys**](ContextualTupleKeys.md) | | [optional] **AuthorizationModelId** | **string** | | [optional] **Trace** | **bool** | Defaults to false. Making it true has performance implications. | [optional] [readonly] +**Context** | **Object** | Additional request context that will be used to evaluate any ABAC conditions encountered in the query evaluation. | [optional] [[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) diff --git a/docs/CheckRequestTupleKey.md b/docs/CheckRequestTupleKey.md new file mode 100644 index 0000000..b0d237c --- /dev/null +++ b/docs/CheckRequestTupleKey.md @@ -0,0 +1,12 @@ +# OpenFga.Sdk.Model.CheckRequestTupleKey + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**User** | **string** | | +**Relation** | **string** | | +**Object** | **string** | | + +[[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) + diff --git a/docs/Computed.md b/docs/Computed.md index c44486c..2401e8d 100644 --- a/docs/Computed.md +++ b/docs/Computed.md @@ -4,7 +4,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**Userset** | **string** | | [optional] +**Userset** | **string** | | [[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) diff --git a/docs/Condition.md b/docs/Condition.md new file mode 100644 index 0000000..7f072d9 --- /dev/null +++ b/docs/Condition.md @@ -0,0 +1,12 @@ +# OpenFga.Sdk.Model.Condition + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | | +**Expression** | **string** | A Google CEL expression, expressed as a string. | +**Parameters** | [**Dictionary<string, ConditionParamTypeRef>**](ConditionParamTypeRef.md) | A map of parameter names to the parameter's defined type reference. | [optional] + +[[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) + diff --git a/docs/ConditionParamTypeRef.md b/docs/ConditionParamTypeRef.md new file mode 100644 index 0000000..451b611 --- /dev/null +++ b/docs/ConditionParamTypeRef.md @@ -0,0 +1,11 @@ +# OpenFga.Sdk.Model.ConditionParamTypeRef + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**TypeName** | **TypeName** | | +**GenericTypes** | [**List<ConditionParamTypeRef>**](ConditionParamTypeRef.md) | | [optional] + +[[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) + diff --git a/docs/CreateStoreResponse.md b/docs/CreateStoreResponse.md index 4e78a89..245cd0f 100644 --- a/docs/CreateStoreResponse.md +++ b/docs/CreateStoreResponse.md @@ -4,10 +4,10 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**Id** | **string** | | [optional] -**Name** | **string** | | [optional] -**CreatedAt** | **DateTime** | | [optional] -**UpdatedAt** | **DateTime** | | [optional] +**Id** | **string** | | +**Name** | **string** | | +**CreatedAt** | **DateTime** | | +**UpdatedAt** | **DateTime** | | [[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) diff --git a/docs/ExpandRequest.md b/docs/ExpandRequest.md index ae0d88a..c7c8ea7 100644 --- a/docs/ExpandRequest.md +++ b/docs/ExpandRequest.md @@ -4,7 +4,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**TupleKey** | [**TupleKey**](TupleKey.md) | | +**TupleKey** | [**ExpandRequestTupleKey**](ExpandRequestTupleKey.md) | | **AuthorizationModelId** | **string** | | [optional] [[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) diff --git a/docs/ExpandRequestTupleKey.md b/docs/ExpandRequestTupleKey.md new file mode 100644 index 0000000..aae8051 --- /dev/null +++ b/docs/ExpandRequestTupleKey.md @@ -0,0 +1,11 @@ +# OpenFga.Sdk.Model.ExpandRequestTupleKey + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Relation** | **string** | | +**Object** | **string** | | + +[[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) + diff --git a/docs/GetStoreResponse.md b/docs/GetStoreResponse.md index 49ae4e9..97a32bd 100644 --- a/docs/GetStoreResponse.md +++ b/docs/GetStoreResponse.md @@ -4,10 +4,11 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**Id** | **string** | | [optional] -**Name** | **string** | | [optional] -**CreatedAt** | **DateTime** | | [optional] -**UpdatedAt** | **DateTime** | | [optional] +**Id** | **string** | | +**Name** | **string** | | +**CreatedAt** | **DateTime** | | +**UpdatedAt** | **DateTime** | | +**DeletedAt** | **DateTime** | | [optional] [[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) diff --git a/docs/ListObjectsRequest.md b/docs/ListObjectsRequest.md index ef95303..1faa768 100644 --- a/docs/ListObjectsRequest.md +++ b/docs/ListObjectsRequest.md @@ -9,6 +9,7 @@ Name | Type | Description | Notes **Relation** | **string** | | **User** | **string** | | **ContextualTuples** | [**ContextualTupleKeys**](ContextualTupleKeys.md) | | [optional] +**Context** | **Object** | Additional request context that will be used to evaluate any ABAC conditions encountered in the query evaluation. | [optional] [[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) diff --git a/docs/ListObjectsResponse.md b/docs/ListObjectsResponse.md index 22eb972..a11862d 100644 --- a/docs/ListObjectsResponse.md +++ b/docs/ListObjectsResponse.md @@ -4,7 +4,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**Objects** | **List<string>** | | [optional] +**Objects** | **List<string>** | | [[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) diff --git a/docs/ListStoresResponse.md b/docs/ListStoresResponse.md index 590bcd4..6e0cb73 100644 --- a/docs/ListStoresResponse.md +++ b/docs/ListStoresResponse.md @@ -4,8 +4,8 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**Stores** | [**List<Store>**](Store.md) | | [optional] -**ContinuationToken** | **string** | The continuation token will be empty if there are no more stores. | [optional] +**Stores** | [**List<Store>**](Store.md) | | +**ContinuationToken** | **string** | The continuation token will be empty if there are no more stores. | [[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) diff --git a/docs/Node.md b/docs/Node.md index b895877..fd6279e 100644 --- a/docs/Node.md +++ b/docs/Node.md @@ -4,7 +4,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**Name** | **string** | | [optional] +**Name** | **string** | | **Leaf** | [**Leaf**](Leaf.md) | | [optional] **Difference** | [**UsersetTreeDifference**](UsersetTreeDifference.md) | | [optional] **Union** | [**Nodes**](Nodes.md) | | [optional] diff --git a/docs/Nodes.md b/docs/Nodes.md index 994226b..94a8fd4 100644 --- a/docs/Nodes.md +++ b/docs/Nodes.md @@ -4,7 +4,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**_Nodes** | [**List<Node>**](Node.md) | | [optional] +**_Nodes** | [**List<Node>**](Node.md) | | [[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) diff --git a/docs/NullValue.md b/docs/NullValue.md new file mode 100644 index 0000000..6306a4f --- /dev/null +++ b/docs/NullValue.md @@ -0,0 +1,10 @@ +# OpenFga.Sdk.Model.NullValue +`NullValue` is a singleton enumeration to represent the null value for the `Value` type union. The JSON representation for `NullValue` is JSON `null`. - NULL_VALUE: Null value. + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- + +[[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) + diff --git a/docs/OpenFgaApi.md b/docs/OpenFgaApi.md index ff35b80..61487e5 100644 --- a/docs/OpenFgaApi.md +++ b/docs/OpenFgaApi.md @@ -27,7 +27,7 @@ Method | HTTP request | Description 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. 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. 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 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. ### Example ```csharp @@ -94,6 +94,7 @@ Name | Type | Description | Notes | **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. | - | | **500** | Request failed due to internal server error. | - | [[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) @@ -169,6 +170,7 @@ Name | Type | Description | Notes | **201** | 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. | - | | **500** | Request failed due to internal server error. | - | [[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) @@ -243,6 +245,7 @@ void (empty response body) | **204** | 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. | - | | **500** | Request failed due to internal server error. | - | [[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) @@ -320,6 +323,7 @@ Name | Type | Description | Notes | **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. | - | | **500** | Request failed due to internal server error. | - | [[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) @@ -395,6 +399,7 @@ Name | Type | Description | Notes | **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. | - | | **500** | Request failed due to internal server error. | - | [[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) @@ -405,7 +410,7 @@ Name | Type | Description | Notes 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. 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 `:` (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 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 `:` (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 ```csharp @@ -472,6 +477,7 @@ Name | Type | Description | Notes | **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. | - | | **500** | Request failed due to internal server error. | - | [[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) @@ -549,6 +555,7 @@ Name | Type | Description | Notes | **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. | - | | **500** | Request failed due to internal server error. | - | [[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) @@ -626,6 +633,7 @@ Name | Type | Description | Notes | **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. | - | | **500** | Request failed due to internal server error. | - | [[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) @@ -703,6 +711,7 @@ Name | Type | Description | Notes | **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. | - | | **500** | Request failed due to internal server error. | - | [[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) @@ -780,6 +789,7 @@ Name | Type | Description | Notes | **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. | - | | **500** | Request failed due to internal server error. | - | [[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) @@ -859,6 +869,7 @@ Name | Type | Description | Notes | **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. | - | | **500** | Request failed due to internal server error. | - | [[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) @@ -869,7 +880,7 @@ Name | Type | Description | Notes Return a list of all the tuple changes -The ReadChanges API will return a paginated list of tuple changes (additions and deletions) that occurred in a given store, sorted by ascending time. The response will include a continuation token that is used to get the next set of changes. If there are no changes after the provided continuation token, the same token will be returned in order for it to be used when new changes are recorded. If the store never had any tuples added or removed, this token will be empty. You can use the `type` parameter to only get the list of tuple changes that affect objects of that type. +The ReadChanges API will return a paginated list of tuple changes (additions and deletions) that occurred in a given store, sorted by ascending time. The response will include a continuation token that is used to get the next set of changes. If there are no changes after the provided continuation token, the same token will be returned in order for it to be used when new changes are recorded. If the store never had any tuples added or removed, this token will be empty. You can use the `type` parameter to only get the list of tuple changes that affect objects of that type. When reading a write tuple change, if it was conditioned, the condition will be returned. When reading a delete tuple change, the condition will NOT be returned regardless of whether it was originally conditioned or not. ### Example ```csharp @@ -940,6 +951,7 @@ Name | Type | Description | Notes | **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. | - | | **500** | Request failed due to internal server error. | - | [[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) @@ -950,7 +962,7 @@ Name | Type | Description | Notes 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 while `deletes` removes existing tuples. The API is not idempotent: if, later on, you try to add the same tuple, 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 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\" } ] } } ``` ### Example ```csharp @@ -1017,6 +1029,7 @@ Name | Type | Description | Notes | **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. | - | | **500** | Request failed due to internal server error. | - | [[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) @@ -1095,6 +1108,7 @@ void (empty response body) | **204** | 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. | - | | **500** | Request failed due to internal server error. | - | [[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) @@ -1172,6 +1186,7 @@ Name | Type | Description | Notes | **201** | 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. | - | | **500** | Request failed due to internal server error. | - | [[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) diff --git a/docs/ReadAssertionsResponse.md b/docs/ReadAssertionsResponse.md index c3318b2..00f7dd1 100644 --- a/docs/ReadAssertionsResponse.md +++ b/docs/ReadAssertionsResponse.md @@ -4,7 +4,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**AuthorizationModelId** | **string** | | [optional] +**AuthorizationModelId** | **string** | | **Assertions** | [**List<Assertion>**](Assertion.md) | | [optional] [[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) diff --git a/docs/ReadAuthorizationModelsResponse.md b/docs/ReadAuthorizationModelsResponse.md index eb1e014..9bb67ff 100644 --- a/docs/ReadAuthorizationModelsResponse.md +++ b/docs/ReadAuthorizationModelsResponse.md @@ -4,7 +4,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**AuthorizationModels** | [**List<AuthorizationModel>**](AuthorizationModel.md) | | [optional] +**AuthorizationModels** | [**List<AuthorizationModel>**](AuthorizationModel.md) | | **ContinuationToken** | **string** | The continuation token will be empty if there are no more models. | [optional] [[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) diff --git a/docs/ReadChangesResponse.md b/docs/ReadChangesResponse.md index 3c054ab..93a31c6 100644 --- a/docs/ReadChangesResponse.md +++ b/docs/ReadChangesResponse.md @@ -4,7 +4,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**Changes** | [**List<TupleChange>**](TupleChange.md) | | [optional] +**Changes** | [**List<TupleChange>**](TupleChange.md) | | **ContinuationToken** | **string** | The continuation token will be identical if there are no new changes. | [optional] [[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) diff --git a/docs/ReadRequest.md b/docs/ReadRequest.md index 25d1d87..f097748 100644 --- a/docs/ReadRequest.md +++ b/docs/ReadRequest.md @@ -4,7 +4,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**TupleKey** | [**TupleKey**](TupleKey.md) | | [optional] +**TupleKey** | [**ReadRequestTupleKey**](ReadRequestTupleKey.md) | | [optional] **PageSize** | **int** | | [optional] **ContinuationToken** | **string** | | [optional] diff --git a/docs/ReadRequestTupleKey.md b/docs/ReadRequestTupleKey.md new file mode 100644 index 0000000..6193588 --- /dev/null +++ b/docs/ReadRequestTupleKey.md @@ -0,0 +1,12 @@ +# OpenFga.Sdk.Model.ReadRequestTupleKey + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**User** | **string** | | [optional] +**Relation** | **string** | | [optional] +**Object** | **string** | | [optional] + +[[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) + diff --git a/docs/ReadResponse.md b/docs/ReadResponse.md index e0e8eab..b0d89fc 100644 --- a/docs/ReadResponse.md +++ b/docs/ReadResponse.md @@ -4,8 +4,8 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**Tuples** | [**List<Tuple>**](Tuple.md) | | [optional] -**ContinuationToken** | **string** | The continuation token will be empty if there are no more tuples. | [optional] +**Tuples** | [**List<Tuple>**](Tuple.md) | | +**ContinuationToken** | **string** | The continuation token will be empty if there are no more tuples. | [[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) diff --git a/docs/RelationReference.md b/docs/RelationReference.md index 3207b85..6759c17 100644 --- a/docs/RelationReference.md +++ b/docs/RelationReference.md @@ -8,6 +8,7 @@ Name | Type | Description | Notes **Type** | **string** | | **Relation** | **string** | | [optional] **Wildcard** | **Object** | | [optional] +**Condition** | **string** | The name of a condition that is enforced over the allowed relation. | [optional] [[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) diff --git a/docs/RelationshipCondition.md b/docs/RelationshipCondition.md new file mode 100644 index 0000000..8831e52 --- /dev/null +++ b/docs/RelationshipCondition.md @@ -0,0 +1,11 @@ +# OpenFga.Sdk.Model.RelationshipCondition + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | A reference (by name) of the relationship condition defined in the authorization model. | +**Context** | **Object** | Additional context/data to persist along with the condition. The keys must match the parameters defined by the condition, and the value types must match the parameter type definitions. | [optional] + +[[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) + diff --git a/docs/Store.md b/docs/Store.md index a59ccb6..4c8f308 100644 --- a/docs/Store.md +++ b/docs/Store.md @@ -4,10 +4,10 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**Id** | **string** | | [optional] -**Name** | **string** | | [optional] -**CreatedAt** | **DateTime** | | [optional] -**UpdatedAt** | **DateTime** | | [optional] +**Id** | **string** | | +**Name** | **string** | | +**CreatedAt** | **DateTime** | | +**UpdatedAt** | **DateTime** | | **DeletedAt** | **DateTime** | | [optional] [[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) diff --git a/docs/Tuple.md b/docs/Tuple.md index 8892185..4d06d41 100644 --- a/docs/Tuple.md +++ b/docs/Tuple.md @@ -4,8 +4,8 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**Key** | [**TupleKey**](TupleKey.md) | | [optional] -**Timestamp** | **DateTime** | | [optional] +**Key** | [**TupleKey**](TupleKey.md) | | +**Timestamp** | **DateTime** | | [[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) diff --git a/docs/TupleChange.md b/docs/TupleChange.md index e375e59..e9310ef 100644 --- a/docs/TupleChange.md +++ b/docs/TupleChange.md @@ -4,9 +4,9 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**TupleKey** | [**TupleKey**](TupleKey.md) | | [optional] -**Operation** | **TupleOperation** | | [optional] -**Timestamp** | **DateTime** | | [optional] +**TupleKey** | [**TupleKey**](TupleKey.md) | | +**Operation** | **TupleOperation** | | +**Timestamp** | **DateTime** | | [[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) diff --git a/docs/TupleKey.md b/docs/TupleKey.md index b20fb33..b02567a 100644 --- a/docs/TupleKey.md +++ b/docs/TupleKey.md @@ -4,9 +4,10 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**Object** | **string** | | [optional] -**Relation** | **string** | | [optional] -**User** | **string** | | [optional] +**User** | **string** | | +**Relation** | **string** | | +**Object** | **string** | | +**Condition** | [**RelationshipCondition**](RelationshipCondition.md) | | [optional] [[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) diff --git a/docs/TupleKeyWithoutCondition.md b/docs/TupleKeyWithoutCondition.md new file mode 100644 index 0000000..1e096ac --- /dev/null +++ b/docs/TupleKeyWithoutCondition.md @@ -0,0 +1,12 @@ +# OpenFga.Sdk.Model.TupleKeyWithoutCondition + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**User** | **string** | | +**Relation** | **string** | | +**Object** | **string** | | + +[[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) + diff --git a/docs/TupleToUserset.md b/docs/TupleToUserset.md index f88a210..0f248d9 100644 --- a/docs/TupleToUserset.md +++ b/docs/TupleToUserset.md @@ -4,8 +4,8 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**Tupleset** | [**ObjectRelation**](ObjectRelation.md) | | [optional] -**ComputedUserset** | [**ObjectRelation**](ObjectRelation.md) | | [optional] +**Tupleset** | [**ObjectRelation**](ObjectRelation.md) | | +**ComputedUserset** | [**ObjectRelation**](ObjectRelation.md) | | [[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) diff --git a/docs/TupleKeys.md b/docs/TypeName.md similarity index 71% rename from docs/TupleKeys.md rename to docs/TypeName.md index c5715a4..6560737 100644 --- a/docs/TupleKeys.md +++ b/docs/TypeName.md @@ -1,10 +1,9 @@ -# OpenFga.Sdk.Model.TupleKeys +# OpenFga.Sdk.Model.TypeName ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**_TupleKeys** | [**List<TupleKey>**](TupleKey.md) | | [[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) diff --git a/docs/Users.md b/docs/Users.md index 3a11630..1f02d07 100644 --- a/docs/Users.md +++ b/docs/Users.md @@ -4,7 +4,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**_Users** | **List<string>** | | [optional] +**_Users** | **List<string>** | | [[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) diff --git a/docs/UsersetTreeDifference.md b/docs/UsersetTreeDifference.md index b0909e1..2628832 100644 --- a/docs/UsersetTreeDifference.md +++ b/docs/UsersetTreeDifference.md @@ -4,8 +4,8 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**Base** | [**Node**](Node.md) | | [optional] -**Subtract** | [**Node**](Node.md) | | [optional] +**Base** | [**Node**](Node.md) | | +**Subtract** | [**Node**](Node.md) | | [[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) diff --git a/docs/UsersetTreeTupleToUserset.md b/docs/UsersetTreeTupleToUserset.md index 40c868c..d764784 100644 --- a/docs/UsersetTreeTupleToUserset.md +++ b/docs/UsersetTreeTupleToUserset.md @@ -4,8 +4,8 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**Tupleset** | **string** | | [optional] -**Computed** | [**List<Computed>**](Computed.md) | | [optional] +**Tupleset** | **string** | | +**Computed** | [**List<Computed>**](Computed.md) | | [[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) diff --git a/docs/Usersets.md b/docs/Usersets.md index 4b2839e..550a394 100644 --- a/docs/Usersets.md +++ b/docs/Usersets.md @@ -4,7 +4,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**Child** | [**List<Userset>**](Userset.md) | | [optional] +**Child** | [**List<Userset>**](Userset.md) | | [[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) diff --git a/docs/WriteAuthorizationModelRequest.md b/docs/WriteAuthorizationModelRequest.md index 93ccbea..5e56085 100644 --- a/docs/WriteAuthorizationModelRequest.md +++ b/docs/WriteAuthorizationModelRequest.md @@ -5,7 +5,8 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **TypeDefinitions** | [**List<TypeDefinition>**](TypeDefinition.md) | | -**SchemaVersion** | **string** | | [optional] +**SchemaVersion** | **string** | | +**Conditions** | [**Dictionary<string, Condition>**](Condition.md) | | [optional] [[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) diff --git a/docs/WriteAuthorizationModelResponse.md b/docs/WriteAuthorizationModelResponse.md index e8f199e..2f5b4bf 100644 --- a/docs/WriteAuthorizationModelResponse.md +++ b/docs/WriteAuthorizationModelResponse.md @@ -4,7 +4,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**AuthorizationModelId** | **string** | | [optional] +**AuthorizationModelId** | **string** | | [[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) diff --git a/docs/WriteRequest.md b/docs/WriteRequest.md index 02eda1c..9be4c1a 100644 --- a/docs/WriteRequest.md +++ b/docs/WriteRequest.md @@ -4,8 +4,8 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**Writes** | [**TupleKeys**](TupleKeys.md) | | [optional] -**Deletes** | [**TupleKeys**](TupleKeys.md) | | [optional] +**Writes** | [**WriteRequestWrites**](WriteRequestWrites.md) | | [optional] +**Deletes** | [**WriteRequestDeletes**](WriteRequestDeletes.md) | | [optional] **AuthorizationModelId** | **string** | | [optional] [[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) diff --git a/docs/WriteRequestDeletes.md b/docs/WriteRequestDeletes.md new file mode 100644 index 0000000..1b604e0 --- /dev/null +++ b/docs/WriteRequestDeletes.md @@ -0,0 +1,10 @@ +# OpenFga.Sdk.Model.WriteRequestDeletes + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**TupleKeys** | [**List<TupleKeyWithoutCondition>**](TupleKeyWithoutCondition.md) | | + +[[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) + diff --git a/docs/WriteRequestWrites.md b/docs/WriteRequestWrites.md new file mode 100644 index 0000000..10810ee --- /dev/null +++ b/docs/WriteRequestWrites.md @@ -0,0 +1,10 @@ +# OpenFga.Sdk.Model.WriteRequestWrites + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**TupleKeys** | [**List<TupleKey>**](TupleKey.md) | | + +[[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) + diff --git a/example/Example1/Example1.cs b/example/Example1/Example1.cs new file mode 100644 index 0000000..7bf7a18 --- /dev/null +++ b/example/Example1/Example1.cs @@ -0,0 +1,241 @@ +using OpenFga.Sdk.Client; +using OpenFga.Sdk.Client.Model; +using OpenFga.Sdk.Configuration; +using OpenFga.Sdk.Exceptions; +using OpenFga.Sdk.Model; +using System.Diagnostics; + +namespace Example1; + +public class Example1 { + public static async Task Main() { + try { + var credentials = new Credentials(); + if (Environment.GetEnvironmentVariable("FGA_CLIENT_ID") != null) { + credentials.Method = CredentialsMethod.ClientCredentials; + credentials.Config = new CredentialsConfig() { + ApiAudience = Environment.GetEnvironmentVariable("FGA_API_AUDIENCE"), + ApiTokenIssuer = Environment.GetEnvironmentVariable("FGA_TOKEN_ISSUER"), + ClientId = Environment.GetEnvironmentVariable("FGA_CLIENT_ID"), + ClientSecret = Environment.GetEnvironmentVariable("FGA_CLIENT_SECRET") + }; + } + + var configuration = new ClientConfiguration { + ApiUrl = Environment.GetEnvironmentVariable("FGA_API_URL") ?? "http://localhost:8080", // required, e.g. https://api.fga.example + StoreId = Environment.GetEnvironmentVariable("FGA_STORE_ID"), // not needed when calling `CreateStore` or `ListStores` + AuthorizationModelId = Environment.GetEnvironmentVariable("FGA_AUTHORIZATION_MODEL_ID"), // Optional, can be overridden per request + Credentials = credentials + }; + var fgaClient = new OpenFgaClient(configuration); + + // ListStores + Console.WriteLine("Listing Stores"); + var stores1 = await fgaClient.ListStores(); + Console.WriteLine("Stores Count: " + stores1.Stores?.Count()); + + // CreateStore + Console.WriteLine("Creating Test Store"); + var store = await fgaClient.CreateStore(new ClientCreateStoreRequest {Name = "Test Store"}); + Console.WriteLine("Test Store ID: " + store.Id); + + // Set the store id + fgaClient.StoreId = store.Id; + + // ListStores after Create + Console.WriteLine("Listing Stores"); + var stores = await fgaClient.ListStores(); + Console.WriteLine("Stores Count: " + stores.Stores?.Count()); + + // GetStore + Console.WriteLine("Getting Current Store"); + var currentStore = await fgaClient.GetStore(); + Console.WriteLine("Current Store Name: " + currentStore.Name); + + // ReadAuthorizationModels + Console.WriteLine("Reading Authorization Models"); + var models = await fgaClient.ReadAuthorizationModels(); + Console.WriteLine("Models Count: " + models.AuthorizationModels?.Count()); + + // ReadLatestAuthorizationModel + var latestAauthorizationModel = await fgaClient.ReadLatestAuthorizationModel(); + if (latestAauthorizationModel != null) { + Console.WriteLine("Latest Authorization Model ID " + latestAauthorizationModel.AuthorizationModel.Id); + } + else { + Console.WriteLine("Latest Authorization Model not found"); + } + + // WriteAuthorizationModel + Console.WriteLine("Writing an Authorization Model"); + var body = new ClientWriteAuthorizationModelRequest { + SchemaVersion = "1.1", + TypeDefinitions = new List { + new() { + Type = "user", + Relations = new Dictionary() + }, + new() { + Type = "document", + Relations = new Dictionary { + { + "writer", new Userset { + This = new object() + } + }, { + "viewer", + new Userset { + Union = new Usersets { + Child = new List { + new() { + This = new object() + }, + new() { + ComputedUserset = new ObjectRelation { + Relation = "writer" + } + } + } + } + } + } + }, + Metadata = new Metadata { + Relations = new Dictionary { + { + "writer", new RelationMetadata { + DirectlyRelatedUserTypes = new List { + new() {Type = "user"}, + new() {Type = "user", Condition = "ViewCountLessThan200"} + } + } + }, { + "viewer", new RelationMetadata { + DirectlyRelatedUserTypes = new List { + new() {Type = "user"} + } + } + } + } + } + } + }, + Conditions = new Dictionary { + ["ViewCountLessThan200"] = new Condition() { + Name = "ViewCountLessThan200", + Expression = "ViewCount < 200", + Parameters = new Dictionary { + ["ViewCount"] = new ConditionParamTypeRef { + TypeName = TypeName.INT + }, + ["Type"] = new ConditionParamTypeRef { + TypeName = TypeName.STRING + }, + ["Name"] = new ConditionParamTypeRef { + TypeName = TypeName.STRING + } + } + } + } + }; + var authorizationModel = await fgaClient.WriteAuthorizationModel(body); + Console.WriteLine("Authorization Model ID " + authorizationModel.AuthorizationModelId); + + // ReadAuthorizationModels - after Write + Console.WriteLine("Reading Authorization Models"); + models = await fgaClient.ReadAuthorizationModels(); + Console.WriteLine("Models Count: " + models.AuthorizationModels?.Count()); + + // ReadLatestAuthorizationModel - after Write + latestAauthorizationModel = await fgaClient.ReadLatestAuthorizationModel(); + Console.WriteLine("Latest Authorization Model ID " + latestAauthorizationModel.AuthorizationModel.Id); + + // Set the model ID + fgaClient.AuthorizationModelId = latestAauthorizationModel.AuthorizationModel.Id; + + // Write + Console.WriteLine("Writing Tuples"); + await fgaClient.Write(new ClientWriteRequest { + Writes = new List { + new() { + User = "user:anne", + Relation = "writer", + Object = "document:roadmap", + Condition = new RelationshipCondition() { + Name = "ViewCountLessThan200", + Context = new { Name = "Roadmap", Type = "document" } + } + } + } + }, new ClientWriteOptions { + AuthorizationModelId = authorizationModel.AuthorizationModelId + }); + Console.WriteLine("Done Writing Tuples"); + + // Read + Console.WriteLine("Reading Tuples"); + var readTuples = await fgaClient.Read(); + Console.WriteLine("Read Tuples" + readTuples.ToJson()); + + // ReadChanges + Console.WriteLine("Reading Tuple Changess"); + var readChangesTuples = await fgaClient.ReadChanges(); + Console.WriteLine("Read Changes Tuples" + readChangesTuples.ToJson()); + + // Check + Console.WriteLine("Checking for access"); + try { + var failingCheckResponse = await fgaClient.Check(new ClientCheckRequest { + User = "user:anne", + Relation = "viewer", + Object = "document:roadmap" + }); + Console.WriteLine("Allowed: " + failingCheckResponse.Allowed); + } + catch (Exception e) { + Console.WriteLine("Failed due to: " + e.Message); + } + + // Checking for access with context + Console.WriteLine("Checking for access with context"); + var checkResponse = await fgaClient.Check(new ClientCheckRequest { + User = "user:anne", + Relation = "viewer", + Object = "document:roadmap", + Context = new { ViewCount = 100 } + }); + Console.WriteLine("Allowed: " + checkResponse.Allowed); + + // WriteAssertions + await fgaClient.WriteAssertions(new List() { + new ClientAssertion() { + User = "user:carl", + Relation = "writer", + Object = "document:budget", + Expectation = true, + }, + new ClientAssertion() { + User = "user:anne", + Relation = "viewer", + Object = "document:roadmap", + Expectation = false, + } + }); + Console.WriteLine("Assertions updated"); + + // ReadAssertions + Console.WriteLine("Reading Assertions"); + var assertions = await fgaClient.ReadAssertions(); + Console.WriteLine("Assertions " + assertions.ToJson()); + + // DeleteStore + Console.WriteLine("Deleting Current Store"); + await fgaClient.DeleteStore(); + Console.WriteLine("Deleted Store: " + currentStore.Name); + } + catch (ApiException e) { + Console.WriteLine("Error: " + e); + Debug.Print("Error: " + e); + } + } +} \ No newline at end of file diff --git a/example/Example1/Example1.csproj b/example/Example1/Example1.csproj new file mode 100644 index 0000000..4e2bebc --- /dev/null +++ b/example/Example1/Example1.csproj @@ -0,0 +1,23 @@ + + + + Exe + net6.0 + enable + enable + Linux + + + + + all + + + + + + + + + + diff --git a/example/Makefile b/example/Makefile new file mode 100644 index 0000000..1a906e0 --- /dev/null +++ b/example/Makefile @@ -0,0 +1,17 @@ +all: build + +project_name=Example1 +openfga_version=latest + +restore: + dotnet restore "${project_name}/${project_name}.csproj" + +build: restore + dotnet build "${project_name}/${project_name}.csproj" -c Release -o "${project_name}/bin" + +run: + sh -c "${project_name}/bin/${project_name}" + +run-openfga: + docker pull docker.io/openfga/openfga:${openfga_version} && \ + docker run -p 8080:8080 docker.io/openfga/openfga:${openfga_version} diff --git a/example/README.md b/example/README.md new file mode 100644 index 0000000..5f7c7a2 --- /dev/null +++ b/example/README.md @@ -0,0 +1,45 @@ +## Examples of using the OpenFGA .NET SDK + +A set of Examples on how to call the OpenFGA .NET SDK + +### Examples +Example 1: +A bare bones example. It creates a store, and runs a set of calls against it including creating a model, writing tuples and checking for access. + + +### Running the Examples + +Prerequisites: +- `docker` +- `make` +- `.net` sdk + +#### Run using a published SDK + +Steps +1. Clone/Copy the example folder +2. Run `make` to build the project +3. If you have an OpenFGA server running, you can use it, otherwise run `make run-openfga` to spin up an instance (you'll need to switch to a different terminal after - don't forget to close it when done) +4. Run `make run` to run the example + +#### Run using a local unpublished SDK build + +Steps +1. Build the SDK +2. In the Example project file (e.g. `Example1.csproj`), comment out the part that specifies the remote SDK, e.g. +```xml + + all + +``` +and replace it with one pointing to the local dll +```xml + + + ..\..\src\OpenFga.Sdk\bin\Debug\net6.0\OpenFga.Sdk.dll + + +``` +3. Run `make` to build the project +4. If you have an OpenFGA server running, you can use it, otherwise run `make run-openfga` to spin up an instance (you'll need to switch to a different terminal after - don't forget to close it when done) +5. Run `make run` to run the example \ No newline at end of file diff --git a/src/OpenFga.Sdk.Test/Api/OpenFgaApiTests.cs b/src/OpenFga.Sdk.Test/Api/OpenFgaApiTests.cs index bc3820a..395f031 100644 --- a/src/OpenFga.Sdk.Test/Api/OpenFgaApiTests.cs +++ b/src/OpenFga.Sdk.Test/Api/OpenFgaApiTests.cs @@ -39,8 +39,8 @@ public class OpenFgaApiTests : IDisposable { private readonly Configuration.Configuration _config; public OpenFgaApiTests() { - _storeId = "6c181474-aaa1-4df7-8929-6e7b3a992754-test"; - _config = new Configuration.Configuration() { StoreId = _storeId, ApiHost = _host }; + _storeId = "01H0H015178Y2V4CX10C2KGHF4"; + _config = new Configuration.Configuration() { ApiHost = _host }; } private HttpResponseMessage GetCheckResponse(CheckResponse content, bool shouldRetry = false) { @@ -90,10 +90,10 @@ public async void StoreIdRequiredWhenNeeded() { // /// [Fact] public void ValidHostRequired() { - var config = new Configuration.Configuration() { StoreId = _storeId }; + var config = new Configuration.Configuration() { }; void ActionMissingHost() => config.IsValid(); var exception = Assert.Throws(ActionMissingHost); - Assert.Equal("Required parameter ApiHost was not defined when calling Configuration.", exception.Message); + Assert.Equal("Required parameter ApiUrl was not defined when calling Configuration.", exception.Message); } // /// @@ -101,10 +101,10 @@ public void ValidHostRequired() { // /// [Fact] public void ValidHostWellFormed() { - var config = new Configuration.Configuration() { StoreId = _storeId, ApiHost = "https://api.fga.example" }; + var config = new Configuration.Configuration() { ApiHost = "https://api.fga.example" }; void ActionMalformedHost() => config.IsValid(); var exception = Assert.Throws(ActionMalformedHost); - Assert.Equal("Configuration.ApiScheme (https) and Configuration.ApiHost (https://api.fga.example) do not form a valid URI (https://https://api.fga.example)", exception.Message); + Assert.Equal("Configuration.ApiUrl (https://https://api.fga.example) does not form a valid URI (https://https://api.fga.example)", exception.Message); } /// @@ -113,7 +113,6 @@ public void ValidHostWellFormed() { [Fact] public void ApiTokenRequired() { var missingApiTokenConfig = new Configuration.Configuration() { - StoreId = _storeId, ApiHost = _host, Credentials = new Credentials() { Method = CredentialsMethod.ApiToken, @@ -133,7 +132,6 @@ void ActionMissingApiToken() => [Fact] public void ValidApiTokenIssuerWellFormed() { var config = new Configuration.Configuration() { - StoreId = _storeId, ApiHost = _host, Credentials = new Credentials() { Method = CredentialsMethod.ClientCredentials, @@ -157,7 +155,6 @@ public void ValidApiTokenIssuerWellFormed() { public async Task ApiTokenSentInHeader() { var mockHandler = new Mock(MockBehavior.Strict); var config = new Configuration.Configuration() { - StoreId = _storeId, ApiHost = _host, Credentials = new Credentials() { Method = CredentialsMethod.ApiToken, @@ -169,7 +166,7 @@ public async Task ApiTokenSentInHeader() { var readAuthorizationModelsMockExpression = ItExpr.Is(req => req.RequestUri.ToString() - .StartsWith($"{config.BasePath}/stores/{config.StoreId}/authorization-models") && + .StartsWith($"{config.BasePath}/stores/{_storeId}/authorization-models") && req.Method == HttpMethod.Get && req.Headers.Contains("Authorization") && req.Headers.Authorization.Equals(new AuthenticationHeaderValue("Bearer", "some-token"))); @@ -189,7 +186,7 @@ public async Task ApiTokenSentInHeader() { var httpClient = new HttpClient(mockHandler.Object); var openFga = new OpenFgaApi(config, httpClient); - var response = await openFga.ReadAuthorizationModels(null, null); + var response = await openFga.ReadAuthorizationModels(_storeId, null, null); mockHandler.Protected().Verify( "SendAsync", @@ -329,7 +326,7 @@ public async Task ExchangeCredentialsTest() { var readAuthorizationModelsMockExpression = ItExpr.Is(req => req.RequestUri.ToString() - .StartsWith($"{config.BasePath}/stores/{config.StoreId}/authorization-models") && + .StartsWith($"{config.BasePath}/stores/{_storeId}/authorization-models") && req.Method == HttpMethod.Get && req.Headers.Contains("Authorization") && req.Headers.Authorization.Equals(new AuthenticationHeaderValue("Bearer", "some-token"))); @@ -353,8 +350,8 @@ public async Task ExchangeCredentialsTest() { var httpClient = new HttpClient(mockHandler.Object); var openFgaApi = new OpenFgaApi(config, httpClient); - var response = await openFgaApi.ReadAuthorizationModels(null, null); - var response2 = await openFgaApi.ReadAuthorizationModels(null, null); + var response = await openFgaApi.ReadAuthorizationModels(_storeId, null, null); + var response2 = await openFgaApi.ReadAuthorizationModels(_storeId, null, null); mockHandler.Protected().Verify( "SendAsync", @@ -374,7 +371,7 @@ public async Task ExchangeCredentialsTest() { "SendAsync", Times.Exactly(0), ItExpr.Is(req => - req.RequestUri == new Uri($"{config.BasePath}/stores/{config.StoreId}/check") && + req.RequestUri == new Uri($"{config.BasePath}/stores/{_storeId}/check") && req.Method == HttpMethod.Post), ItExpr.IsAny() ); @@ -386,7 +383,6 @@ public async Task ExchangeCredentialsTest() { [Fact] public async Task ExchangeCredentialsAfterExpiryTest() { var config = new Configuration.Configuration() { - StoreId = _storeId, ApiHost = _host, Credentials = new Credentials() { Method = CredentialsMethod.ClientCredentials, @@ -427,7 +423,7 @@ public async Task ExchangeCredentialsAfterExpiryTest() { var readAuthorizationModelsMockExpression = ItExpr.Is(req => req.RequestUri.ToString() - .StartsWith($"{config.BasePath}/stores/{config.StoreId}/authorization-models") && + .StartsWith($"{config.BasePath}/stores/{_storeId}/authorization-models") && req.Method == HttpMethod.Get && req.Headers.Contains("Authorization") && req.Headers.Authorization.Equals(new AuthenticationHeaderValue("Bearer", "some-token"))); @@ -451,8 +447,8 @@ public async Task ExchangeCredentialsAfterExpiryTest() { var httpClient = new HttpClient(mockHandler.Object); var openFgaApi = new OpenFgaApi(config, httpClient); - var response = await openFgaApi.ReadAuthorizationModels(null, null); - var response2 = await openFgaApi.ReadAuthorizationModels(null, null); + var response = await openFgaApi.ReadAuthorizationModels(_storeId, null, null); + var response2 = await openFgaApi.ReadAuthorizationModels(_storeId, null, null); mockHandler.Protected().Verify( "SendAsync", @@ -472,25 +468,12 @@ public async Task ExchangeCredentialsAfterExpiryTest() { "SendAsync", Times.Exactly(0), ItExpr.Is(req => - req.RequestUri == new Uri($"{config.BasePath}/stores/{config.StoreId}/check") && + req.RequestUri == new Uri($"{config.BasePath}/stores/{_storeId}/check") && req.Method == HttpMethod.Post), ItExpr.IsAny() ); } - /// - /// Test that updating StoreId after initialization works - /// - [Fact] - public void UpdateStoreIdTest() { - var config = new Configuration.Configuration() { ApiHost = _host }; - var openFgaApi = new OpenFgaApi(config); - Assert.Null(openFgaApi.StoreId); - var storeId = "some-id"; - openFgaApi.StoreId = storeId; - Assert.Equal(storeId, openFgaApi.StoreId); - } - /** * Errors */ @@ -504,7 +487,7 @@ public async Task FgaApiValidationErrorTest() { .Setup>( "SendAsync", ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/check") && req.Method == HttpMethod.Post), ItExpr.IsAny() ) @@ -517,19 +500,26 @@ public async Task FgaApiValidationErrorTest() { var openFgaApi = new OpenFgaApi(_config, httpClient); - var body = new CheckRequest { TupleKey = new TupleKey("document:roadmap", "viewer", "user:81684243-9356-4421-8fbf-a4f8d36aa31b"), AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1" }; + var body = new CheckRequest { + TupleKey = new CheckRequestTupleKey() { + User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation = "viewer", + Object = "document:roadmap" + }, + AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1" + }; - Task BadRequestError() => openFgaApi.Check(body); + Task BadRequestError() => openFgaApi.Check(_storeId, body); var error = await Assert.ThrowsAsync(BadRequestError); Assert.Equal(error.Method, HttpMethod.Post); Assert.Equal("Check", error.ApiName); - Assert.Equal(_config.StoreId, error.StoreId); + Assert.Equal(_storeId, error.StoreId); mockHandler.Protected().Verify( "SendAsync", Times.Exactly(1), ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/check") && req.Method == HttpMethod.Post), ItExpr.IsAny() ); @@ -545,7 +535,7 @@ public async Task FgaApiInternalErrorTest() { .SetupSequence>( "SendAsync", ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/check") && req.Method == HttpMethod.Post), ItExpr.IsAny() ) @@ -559,26 +549,32 @@ public async Task FgaApiInternalErrorTest() { var httpClient = new HttpClient(mockHandler.Object); var config = new Configuration.Configuration() { - StoreId = _storeId, ApiHost = _host, MaxRetry = 1, }; var openFgaApi = new OpenFgaApi(config, httpClient); - var body = new CheckRequest(new TupleKey("document:roadmap", "viewer", "user:81684243-9356-4421-8fbf-a4f8d36aa31b")); + var body = new CheckRequest { + TupleKey = new CheckRequestTupleKey() { + User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation = "viewer", + Object = "document:roadmap" + }, + AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1" + }; - Task InternalApiError() => openFgaApi.Check(body); + Task InternalApiError() => openFgaApi.Check(_storeId, body); var error = await Assert.ThrowsAsync(InternalApiError); Assert.Equal(error.Method, HttpMethod.Post); Assert.Equal("Check", error.ApiName); - Assert.Equal($"{_config.BasePath}/stores/{_config.StoreId}/check", error.RequestUrl); - Assert.Equal(_config.StoreId, error.StoreId); + Assert.Equal($"{_config.BasePath}/stores/{_storeId}/check", error.RequestUrl); + Assert.Equal(_storeId, error.StoreId); mockHandler.Protected().Verify( "SendAsync", Times.Exactly(2), ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/check") && req.Method == HttpMethod.Post), ItExpr.IsAny() ); @@ -595,7 +591,7 @@ public async Task FgaApiInternalErrorRetrySuccessTest() { .SetupSequence>( "SendAsync", ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/check") && req.Method == HttpMethod.Post), ItExpr.IsAny() ) @@ -611,15 +607,21 @@ public async Task FgaApiInternalErrorRetrySuccessTest() { var openFgaApi = new OpenFgaApi(_config, httpClient); - var body = new CheckRequest(new TupleKey("document:roadmap", "viewer", "user:81684243-9356-4421-8fbf-a4f8d36aa31b")); + var body = new CheckRequest { + TupleKey = new CheckRequestTupleKey() { + User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation = "viewer", + Object = "document:roadmap" + } + }; - var response = await openFgaApi.Check(body); + var response = await openFgaApi.Check(_storeId, body); mockHandler.Protected().Verify( "SendAsync", Times.Exactly(3), ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/check") && req.Method == HttpMethod.Post), ItExpr.IsAny() ); @@ -638,7 +640,7 @@ public async Task FgaNotFoundErrorTest() { .Setup>( "SendAsync", ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/check") && req.Method == HttpMethod.Post), ItExpr.IsAny() ) @@ -650,20 +652,26 @@ public async Task FgaNotFoundErrorTest() { var openFgaApi = new OpenFgaApi(_config, httpClient); - var body = new CheckRequest(new TupleKey("document:roadmap", "viewer", "user:81684243-9356-4421-8fbf-a4f8d36aa31b")); + var body = new CheckRequest { + TupleKey = new CheckRequestTupleKey() { + User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation = "viewer", + Object = "document:roadmap" + } + }; - Task ApiError() => openFgaApi.Check(body); + Task ApiError() => openFgaApi.Check(_storeId, body); var error = await Assert.ThrowsAsync(ApiError); Assert.Equal(error.Method, HttpMethod.Post); Assert.Equal("Check", error.ApiName); - Assert.Equal($"{_config.BasePath}/stores/{_config.StoreId}/check", error.RequestUrl); - Assert.Equal(_config.StoreId, error.StoreId); + Assert.Equal($"{_config.BasePath}/stores/{_storeId}/check", error.RequestUrl); + Assert.Equal(_storeId, error.StoreId); mockHandler.Protected().Verify( "SendAsync", Times.Exactly(1), ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/check") && req.Method == HttpMethod.Post), ItExpr.IsAny() ); @@ -679,7 +687,7 @@ public async Task FgaApiErrorTest() { .Setup>( "SendAsync", ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/check") && req.Method == HttpMethod.Post), ItExpr.IsAny() ) @@ -691,20 +699,26 @@ public async Task FgaApiErrorTest() { var openFgaApi = new OpenFgaApi(_config, httpClient); - var body = new CheckRequest(new TupleKey("document:roadmap", "viewer", "user:81684243-9356-4421-8fbf-a4f8d36aa31b")); + var body = new CheckRequest { + TupleKey = new CheckRequestTupleKey() { + User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation = "viewer", + Object = "document:roadmap" + } + }; - Task ApiError() => openFgaApi.Check(body); + Task ApiError() => openFgaApi.Check(_storeId, body); var error = await Assert.ThrowsAsync(ApiError); Assert.Equal(error.Method, HttpMethod.Post); Assert.Equal("Check", error.ApiName); - Assert.Equal($"{_config.BasePath}/stores/{_config.StoreId}/check", error.RequestUrl); - Assert.Equal(_config.StoreId, error.StoreId); + Assert.Equal($"{_config.BasePath}/stores/{_storeId}/check", error.RequestUrl); + Assert.Equal(_storeId, error.StoreId); mockHandler.Protected().Verify( "SendAsync", Times.Exactly(1), ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/check") && req.Method == HttpMethod.Post), ItExpr.IsAny() ); @@ -720,7 +734,7 @@ public async Task FgaApiRateLimitExceededErrorTest() { .SetupSequence>( "SendAsync", ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/check") && req.Method == HttpMethod.Post), ItExpr.IsAny() ) @@ -739,9 +753,15 @@ public async Task FgaApiRateLimitExceededErrorTest() { }; var openFgaApi = new OpenFgaApi(config, httpClient); - var body = new CheckRequest(new TupleKey("document:roadmap", "viewer", "user:81684243-9356-4421-8fbf-a4f8d36aa31b")); + var body = new CheckRequest { + TupleKey = new CheckRequestTupleKey() { + User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation = "viewer", + Object = "document:roadmap" + } + }; - Task RateLimitExceededError() => openFgaApi.Check(body); + Task RateLimitExceededError() => openFgaApi.Check(_storeId, body); var error = await Assert.ThrowsAsync(RateLimitExceededError); Assert.Equal("Rate Limit Error for POST Check with API limit of 2 requests per Second.", error.Message); Assert.Equal(100, error.ResetInMs); @@ -749,13 +769,13 @@ public async Task FgaApiRateLimitExceededErrorTest() { Assert.Equal("Second", error.LimitUnit.ToString()); Assert.Equal(error.Method, HttpMethod.Post); Assert.Equal("Check", error.ApiName); - Assert.Equal(_config.StoreId, error.StoreId); + Assert.Equal(_storeId, error.StoreId); mockHandler.Protected().Verify( "SendAsync", Times.Exactly(6), ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/check") && req.Method == HttpMethod.Post), ItExpr.IsAny() ); @@ -770,7 +790,7 @@ public async Task FgaApiRateLimitExceededErrorRetrySuccessTest() { .SetupSequence>( "SendAsync", ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/check") && req.Method == HttpMethod.Post), ItExpr.IsAny() ) @@ -782,14 +802,20 @@ public async Task FgaApiRateLimitExceededErrorRetrySuccessTest() { var openFgaApi = new OpenFgaApi(_config, httpClient); - var body = new CheckRequest(new TupleKey("document:roadmap", "viewer", "user:81684243-9356-4421-8fbf-a4f8d36aa31b")); + var body = new CheckRequest { + TupleKey = new CheckRequestTupleKey() { + User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation = "viewer", + Object = "document:roadmap" + } + }; - var response = await openFgaApi.Check(body); + var response = await openFgaApi.Check(_storeId, body); mockHandler.Protected().Verify( "SendAsync", Times.Exactly(3), ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/check") && req.Method == HttpMethod.Post), ItExpr.IsAny() ); @@ -808,7 +834,7 @@ public async Task RetryOnRateLimitTest() { .SetupSequence>( "SendAsync", ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/check") && req.Method == HttpMethod.Post), ItExpr.IsAny() ) @@ -825,15 +851,21 @@ public async Task RetryOnRateLimitTest() { }; var openFgaApi = new OpenFgaApi(config, httpClient); - var body = new CheckRequest(new TupleKey("document:roadmap", "viewer", "user:81684243-9356-4421-8fbf-a4f8d36aa31b")); + var body = new CheckRequest { + TupleKey = new CheckRequestTupleKey() { + User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation = "viewer", + Object = "document:roadmap" + } + }; - await openFgaApi.Check(body); + await openFgaApi.Check(_storeId, body); mockHandler.Protected().Verify( "SendAsync", Times.Exactly(3), ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/check") && req.Method == HttpMethod.Post), ItExpr.IsAny() ); @@ -855,7 +887,7 @@ public async Task ReadAuthorizationModelsTest() { "SendAsync", ItExpr.Is(req => req.RequestUri.ToString() - .StartsWith($"{_config.BasePath}/stores/{_config.StoreId}/authorization-models") && + .StartsWith($"{_config.BasePath}/stores/{_storeId}/authorization-models") && req.Method == HttpMethod.Get), ItExpr.IsAny() ) @@ -869,14 +901,14 @@ public async Task ReadAuthorizationModelsTest() { var httpClient = new HttpClient(mockHandler.Object); var openFgaApi = new OpenFgaApi(_config, httpClient); - var response = await openFgaApi.ReadAuthorizationModels(null, null); + var response = await openFgaApi.ReadAuthorizationModels(_storeId, null, null); mockHandler.Protected().Verify( "SendAsync", Times.Exactly(1), ItExpr.Is(req => req.RequestUri.ToString() - .StartsWith($"{_config.BasePath}/stores/{_config.StoreId}/authorization-models") && + .StartsWith($"{_config.BasePath}/stores/{_storeId}/authorization-models") && req.Method == HttpMethod.Get), ItExpr.IsAny() ); @@ -952,7 +984,7 @@ public async Task WriteAuthorizationModelTest() { .Setup>( "SendAsync", ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/authorization-models") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/authorization-models") && req.Method == HttpMethod.Post), ItExpr.IsAny() ) @@ -965,13 +997,13 @@ public async Task WriteAuthorizationModelTest() { var httpClient = new HttpClient(mockHandler.Object); var openFgaApi = new OpenFgaApi(_config, httpClient); - var response = await openFgaApi.WriteAuthorizationModel(body); + var response = await openFgaApi.WriteAuthorizationModel(_storeId, body); mockHandler.Protected().Verify( "SendAsync", Times.Exactly(1), ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/authorization-models") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/authorization-models") && req.Method == HttpMethod.Post), ItExpr.IsAny() ); @@ -992,7 +1024,7 @@ public async Task ReadAuthorizationModelTest() { "SendAsync", ItExpr.Is(req => req.RequestUri == - new Uri($"{_config.BasePath}/stores/{_config.StoreId}/authorization-models/{authorizationModelId}") && + new Uri($"{_config.BasePath}/stores/{_storeId}/authorization-models/{authorizationModelId}") && req.Method == HttpMethod.Get), ItExpr.IsAny() ) @@ -1007,14 +1039,14 @@ public async Task ReadAuthorizationModelTest() { var httpClient = new HttpClient(mockHandler.Object); var openFgaApi = new OpenFgaApi(_config, httpClient); - var response = await openFgaApi.ReadAuthorizationModel(authorizationModelId); + var response = await openFgaApi.ReadAuthorizationModel(_storeId, authorizationModelId); mockHandler.Protected().Verify( "SendAsync", Times.Exactly(1), ItExpr.Is(req => req.RequestUri == - new Uri($"{_config.BasePath}/stores/{_config.StoreId}/authorization-models/{authorizationModelId}") && + new Uri($"{_config.BasePath}/stores/{_storeId}/authorization-models/{authorizationModelId}") && req.Method == HttpMethod.Get), ItExpr.IsAny() ); @@ -1033,7 +1065,7 @@ public async Task CheckTest() { .Setup>( "SendAsync", ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/check") && req.Method == HttpMethod.Post), ItExpr.IsAny() ) @@ -1045,14 +1077,22 @@ public async Task CheckTest() { var httpClient = new HttpClient(mockHandler.Object); var openFgaApi = new OpenFgaApi(_config, httpClient); - var body = new CheckRequest { TupleKey = new TupleKey("document:roadmap", "viewer", "user:81684243-9356-4421-8fbf-a4f8d36aa31b"), AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1" }; - var response = await openFgaApi.Check(body); + var body = new CheckRequest { + TupleKey = new CheckRequestTupleKey() { + User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation = "viewer", + Object = "document:roadmap" + }, + AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1" + }; + + var response = await openFgaApi.Check(_storeId, body); mockHandler.Protected().Verify( "SendAsync", Times.Exactly(1), ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/check") && req.Method == HttpMethod.Post), ItExpr.IsAny() ); @@ -1071,7 +1111,7 @@ public async Task WriteWriteTest() { .Setup>( "SendAsync", ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/write") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/write") && req.Method == HttpMethod.Post), ItExpr.IsAny() ) @@ -1084,16 +1124,20 @@ public async Task WriteWriteTest() { var openFgaApi = new OpenFgaApi(_config, httpClient); var body = new WriteRequest { - Writes = new TupleKeys(new List { new("document:roadmap", "viewer", "user:81684243-9356-4421-8fbf-a4f8d36aa31b") }), + Writes = new WriteRequestWrites(new List { new () { + User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation = "viewer", + Object = "document:roadmap" + } }), AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1" }; - var response = await openFgaApi.Write(body); + var response = await openFgaApi.Write(_storeId, body); mockHandler.Protected().Verify( "SendAsync", Times.Exactly(1), ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/write") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/write") && req.Method == HttpMethod.Post), ItExpr.IsAny() ); @@ -1109,7 +1153,7 @@ public async Task WriteDeleteTest() { .Setup>( "SendAsync", ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/write") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/write") && req.Method == HttpMethod.Post), ItExpr.IsAny() ) @@ -1122,16 +1166,20 @@ public async Task WriteDeleteTest() { var openFgaApi = new OpenFgaApi(_config, httpClient); var body = new WriteRequest { - Deletes = new TupleKeys(new List { new("document:roadmap", "viewer", "user:81684243-9356-4421-8fbf-a4f8d36aa31b") }), + Deletes = new WriteRequestDeletes(new List { new () { + User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation = "viewer", + Object = "document:roadmap" + } }), AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1" }; - var response = await openFgaApi.Write(body); + var response = await openFgaApi.Write(_storeId, body); mockHandler.Protected().Verify( "SendAsync", Times.Exactly(1), ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/write") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/write") && req.Method == HttpMethod.Post), ItExpr.IsAny() ); @@ -1147,7 +1195,7 @@ public async Task WriteMixedWithAuthorizationModelIdTest() { .Setup>( "SendAsync", ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/write") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/write") && req.Method == HttpMethod.Post), ItExpr.IsAny() ) @@ -1159,17 +1207,25 @@ public async Task WriteMixedWithAuthorizationModelIdTest() { var httpClient = new HttpClient(mockHandler.Object); var openFgaApi = new OpenFgaApi(_config, httpClient); - var body = new WriteRequest( - new TupleKeys(new List { new("document:roadmap", "writer", "user:81684243-9356-4421-8fbf-a4f8d36aa31b") }), - new TupleKeys(new List { new("document:roadmap", "viewer", "user:81684243-9356-4421-8fbf-a4f8d36aa31b") }), - "01GXSA8YR785C4FYS3C0RTG7B1"); - var response = await openFgaApi.Write(body); + var body = new WriteRequest { + Writes = new WriteRequestWrites(new List { new () { + User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation = "writer", + Object = "document:roadmap" + }, new () { + User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation = "viewer", + Object = "document:roadmap" + } }), + AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1" + }; + var response = await openFgaApi.Write(_storeId, body); mockHandler.Protected().Verify( "SendAsync", Times.Exactly(1), ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/write") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/write") && req.Method == HttpMethod.Post), ItExpr.IsAny() ); @@ -1188,7 +1244,7 @@ public async Task ExpandTest() { .Setup>( "SendAsync", ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/expand") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/expand") && req.Method == HttpMethod.Post), ItExpr.IsAny() ) @@ -1200,14 +1256,14 @@ public async Task ExpandTest() { var httpClient = new HttpClient(mockHandler.Object); var openFgaApi = new OpenFgaApi(_config, httpClient); - var body = new ExpandRequest { TupleKey = new TupleKey(_object: "document:roadmap", relation: "viewer"), AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1" }; - var response = await openFgaApi.Expand(body); + var body = new ExpandRequest { TupleKey = new ExpandRequestTupleKey(_object: "document:roadmap", relation: "viewer"), AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1" }; + var response = await openFgaApi.Expand(_storeId, body); mockHandler.Protected().Verify( "SendAsync", Times.Exactly(1), ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/expand") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/expand") && req.Method == HttpMethod.Post), ItExpr.IsAny() ); @@ -1250,7 +1306,7 @@ public async Task ExpandComplexResponseTest() { .Setup>( "SendAsync", ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/expand") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/expand") && req.Method == HttpMethod.Post), ItExpr.IsAny() ) @@ -1262,14 +1318,14 @@ public async Task ExpandComplexResponseTest() { var httpClient = new HttpClient(mockHandler.Object); var openFgaApi = new OpenFgaApi(_config, httpClient); - var body = new ExpandRequest(new TupleKey(_object: "document:roadmap", relation: "viewer")); - var response = await openFgaApi.Expand(body); + var body = new ExpandRequest(new ExpandRequestTupleKey(_object: "document:roadmap", relation: "viewer")); + var response = await openFgaApi.Expand(_storeId, body); mockHandler.Protected().Verify( "SendAsync", Times.Exactly(1), ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/expand") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/expand") && req.Method == HttpMethod.Post), ItExpr.IsAny() ); @@ -1289,7 +1345,7 @@ public async Task ListObjectsTest() { .Setup>( "SendAsync", ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/list-objects") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/list-objects") && req.Method == HttpMethod.Post), ItExpr.IsAny() ) @@ -1313,13 +1369,13 @@ public async Task ListObjectsTest() { } } }; - var response = await openFgaApi.ListObjects(body); + var response = await openFgaApi.ListObjects(_storeId, body); mockHandler.Protected().Verify( "SendAsync", Times.Exactly(1), ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/list-objects") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/list-objects") && req.Method == HttpMethod.Post), ItExpr.IsAny() ); @@ -1337,14 +1393,18 @@ public async Task ReadTest() { var mockHandler = new Mock(MockBehavior.Strict); var expectedResponse = new ReadResponse() { Tuples = new List() { - new(new TupleKey("document:roadmap", "viewer", "user:81684243-9356-4421-8fbf-a4f8d36aa31b"), DateTime.Now) + new(new TupleKey { + User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation = "viewer", + Object = "document:roadmap" + }, DateTime.Now) } }; mockHandler.Protected() .Setup>( "SendAsync", ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/read") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/read") && req.Method == HttpMethod.Post), ItExpr.IsAny() ) @@ -1356,14 +1416,20 @@ public async Task ReadTest() { var httpClient = new HttpClient(mockHandler.Object); var openFgaApi = new OpenFgaApi(_config, httpClient); - var body = new ReadRequest { TupleKey = new TupleKey("document:roadmap", "viewer", "user:81684243-9356-4421-8fbf-a4f8d36aa31b") }; - var response = await openFgaApi.Read(body); + var body = new ReadRequest { + TupleKey = new ReadRequestTupleKey { + User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation = "viewer", + Object = "document:roadmap" + }, + }; + var response = await openFgaApi.Read(_storeId, body); mockHandler.Protected().Verify( "SendAsync", Times.Exactly(1), ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/read") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/read") && req.Method == HttpMethod.Post), ItExpr.IsAny() ); @@ -1381,14 +1447,18 @@ public async Task ReadEmptyTest() { var mockHandler = new Mock(MockBehavior.Strict); var expectedResponse = new ReadResponse() { Tuples = new List() { - new(new TupleKey("document:roadmap", "viewer", "user:81684243-9356-4421-8fbf-a4f8d36aa31b"), DateTime.Now) + new(new TupleKey { + User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation = "viewer", + Object = "document:roadmap" + }, DateTime.Now) } }; mockHandler.Protected() .Setup>( "SendAsync", ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/read") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/read") && req.Method == HttpMethod.Post), ItExpr.IsAny() ) @@ -1401,13 +1471,13 @@ public async Task ReadEmptyTest() { var openFgaApi = new OpenFgaApi(_config, httpClient); var body = new ReadRequest { }; - var response = await openFgaApi.Read(body); + var response = await openFgaApi.Read(_storeId, body); mockHandler.Protected().Verify( "SendAsync", Times.Exactly(1), ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/read") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/read") && req.Method == HttpMethod.Post), ItExpr.IsAny() ); @@ -1425,7 +1495,11 @@ public async Task ReadChangesTest() { var mockHandler = new Mock(MockBehavior.Strict); var expectedResponse = new ReadChangesResponse() { Changes = new List() { - new(new TupleKey("document:roadmap", "viewer", "user:81684243-9356-4421-8fbf-a4f8d36aa31b"), TupleOperation.WRITE, DateTime.Now), + new(new TupleKey { + User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation = "viewer", + Object = "document:roadmap" + }, TupleOperation.WRITE, DateTime.Now), }, ContinuationToken = "eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==" }; @@ -1434,7 +1508,7 @@ public async Task ReadChangesTest() { "SendAsync", ItExpr.Is(req => req.RequestUri.ToString() - .StartsWith($"{_config.BasePath}/stores/{_config.StoreId}/changes") && + .StartsWith($"{_config.BasePath}/stores/{_storeId}/changes") && req.Method == HttpMethod.Get), ItExpr.IsAny() ) @@ -1449,14 +1523,14 @@ public async Task ReadChangesTest() { var type = "repo"; var pageSize = 25; var continuationToken = "eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ=="; - var response = await openFgaApi.ReadChanges(type, pageSize, continuationToken); + var response = await openFgaApi.ReadChanges(_storeId, type, pageSize, continuationToken); mockHandler.Protected().Verify( "SendAsync", Times.Exactly(1), ItExpr.Is(req => req.RequestUri.ToString() - .StartsWith($"{_config.BasePath}/stores/{_config.StoreId}/changes") && + .StartsWith($"{_config.BasePath}/stores/{_storeId}/changes") && req.Method == HttpMethod.Get), ItExpr.IsAny() ); @@ -1478,7 +1552,7 @@ public async Task WriteAssertionsTest() { "SendAsync", ItExpr.Is(req => req.RequestUri == - new Uri($"{_config.BasePath}/stores/{_config.StoreId}/assertions/{authorizationModelId}") && + new Uri($"{_config.BasePath}/stores/{_storeId}/assertions/{authorizationModelId}") && req.Method == HttpMethod.Put), ItExpr.IsAny() ) @@ -1489,17 +1563,23 @@ public async Task WriteAssertionsTest() { var httpClient = new HttpClient(mockHandler.Object); var openFgaApi = new OpenFgaApi(_config, httpClient); - var body = new WriteAssertionsRequest(assertions: new List() { - new(new TupleKey("document:roadmap", "viewer", "user:81684243-9356-4421-8fbf-a4f8d36aa31b"), true) - }); - await openFgaApi.WriteAssertions(authorizationModelId, body); + var body = new WriteAssertionsRequest { + Assertions = new List { + new (new AssertionTupleKey { + User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation = "viewer", + Object = "document:roadmap" + }) + }, + }; + await openFgaApi.WriteAssertions(_storeId, authorizationModelId, body); mockHandler.Protected().Verify( "SendAsync", Times.Exactly(1), ItExpr.Is(req => req.RequestUri == - new Uri($"{_config.BasePath}/stores/{_config.StoreId}/assertions/{authorizationModelId}") && + new Uri($"{_config.BasePath}/stores/{_storeId}/assertions/{authorizationModelId}") && req.Method == HttpMethod.Put), ItExpr.IsAny() ); @@ -1518,7 +1598,7 @@ public async Task ReadAssertionsTest() { "SendAsync", ItExpr.Is(req => req.RequestUri == - new Uri($"{_config.BasePath}/stores/{_config.StoreId}/assertions/{authorizationModelId}") && + new Uri($"{_config.BasePath}/stores/{_storeId}/assertions/{authorizationModelId}") && req.Method == HttpMethod.Get), ItExpr.IsAny() ) @@ -1531,14 +1611,14 @@ public async Task ReadAssertionsTest() { var httpClient = new HttpClient(mockHandler.Object); var openFgaApi = new OpenFgaApi(_config, httpClient); - var response = await openFgaApi.ReadAssertions(authorizationModelId); + var response = await openFgaApi.ReadAssertions(_storeId, authorizationModelId); mockHandler.Protected().Verify( "SendAsync", Times.Exactly(1), ItExpr.Is(req => req.RequestUri == - new Uri($"{_config.BasePath}/stores/{_config.StoreId}/assertions/{authorizationModelId}") && + new Uri($"{_config.BasePath}/stores/{_storeId}/assertions/{authorizationModelId}") && req.Method == HttpMethod.Get), ItExpr.IsAny() ); diff --git a/src/OpenFga.Sdk.Test/Client/OpenFgaClientTests.cs b/src/OpenFga.Sdk.Test/Client/OpenFgaClientTests.cs index 9a416ee..1a12d45 100644 --- a/src/OpenFga.Sdk.Test/Client/OpenFgaClientTests.cs +++ b/src/OpenFga.Sdk.Test/Client/OpenFgaClientTests.cs @@ -33,12 +33,12 @@ namespace OpenFga.Sdk.Test.Client; public class OpenFgaClientTests { private readonly string _storeId; - private readonly string _host = "api.fga.example"; + private readonly string _apiUrl = "https://api.fga.example"; private readonly ClientConfiguration _config; public OpenFgaClientTests() { - _storeId = "6c181474-aaa1-4df7-8929-6e7b3a992754-test"; - _config = new ClientConfiguration() { StoreId = _storeId, ApiHost = _host }; + _storeId = "01H0H015178Y2V4CX10C2KGHF4"; + _config = new ClientConfiguration() { StoreId = _storeId, ApiUrl = _apiUrl }; } private HttpResponseMessage GetCheckResponse(CheckResponse content, bool shouldRetry = false) { @@ -62,12 +62,83 @@ public void Dispose() { // Cleanup when everything is done. } + /// + /// Test StoreId validation + /// + [Fact] + public async Task ConfigurationInValidStoreIdTest() { + var config = new ClientConfiguration() { + ApiUrl = _apiUrl, + StoreId = "invalid-format" + }; + void ActionInvalidId() => config.IsValid(); + var exception = Assert.Throws(ActionInvalidId); + Assert.Equal("StoreId is not in a valid ulid format", exception.Message); + } + + /// + /// Test Auth Model ID validation + /// + [Fact] + public async Task ConfigurationInValidAuthorizationModelIdTest() { + var config = new ClientConfiguration() { + ApiUrl = _apiUrl, + StoreId = _config.StoreId, + AuthorizationModelId = "invalid-format" + }; + void ActionInvalidId() => new OpenFgaClient(config); + var exception = Assert.Throws(ActionInvalidId); + Assert.Equal("AuthorizationModelId is not in a valid ulid format", exception.Message); + } + + /// + /// Test Auth Model ID validation + /// + [Fact] + public async Task ConfigurationInValidAuthModelIdInOptionsTest() { + var config = new ClientConfiguration() { + ApiUrl = _apiUrl, + StoreId = _config.StoreId, + }; + var openFgaClient = new OpenFgaClient(config); + + async Task ActionMissingStoreId() => await openFgaClient.ReadAuthorizationModel(new ClientReadAuthorizationModelOptions() { + AuthorizationModelId = "invalid-format" + }); + var exception = await Assert.ThrowsAsync(ActionMissingStoreId); + Assert.Equal("AuthorizationModelId is not in a valid ulid format", exception.Message); + } + + /// + /// Test that updating StoreId after initialization works + /// + [Fact] + public void UpdateStoreIdTest() { + var config = new ClientConfiguration() { ApiUrl = _apiUrl }; + var fgaClient = new OpenFgaClient(config); + Assert.Null(fgaClient.StoreId); + var storeId = "some-id"; + fgaClient.StoreId = storeId; + Assert.Equal(storeId, fgaClient.StoreId); + } + + /// + /// Test that updating AuthorizationModelId after initialization works + /// + [Fact] + public void UpdateAuthorizationModelIdTest() { + var config = new ClientConfiguration() { ApiUrl = _apiUrl }; + var fgaClient = new OpenFgaClient(config); + Assert.Null(fgaClient.AuthorizationModelId); + var modelId = "some-id"; + fgaClient.AuthorizationModelId = modelId; + Assert.Equal(modelId, fgaClient.AuthorizationModelId); + } /********** * Stores * **********/ - /// /// Test ListStores /// @@ -467,6 +538,7 @@ public async Task ReadAuthorizationModelModelIdInConfigTest() { var httpClient = new HttpClient(mockHandler.Object); var fgaClient = new OpenFgaClient(new ClientConfiguration(_config) { + StoreId = _storeId, AuthorizationModelId = authorizationModelId, }, httpClient); @@ -544,7 +616,11 @@ public async Task ReadChangesTest() { var mockHandler = new Mock(MockBehavior.Strict); var expectedResponse = new ReadChangesResponse() { Changes = new List() { - new(new TupleKey("document:roadmap", "viewer", "user:81684243-9356-4421-8fbf-a4f8d36aa31b"), + new(new TupleKey { + User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation = "viewer", + Object = "document:roadmap" + }, TupleOperation.WRITE, DateTime.Now), }, ContinuationToken = @@ -599,7 +675,11 @@ public async Task ReadTest() { var mockHandler = new Mock(MockBehavior.Strict); var expectedResponse = new ReadResponse() { Tuples = new List() { - new(new TupleKey("document:roadmap", "viewer", "user:81684243-9356-4421-8fbf-a4f8d36aa31b"), + new(new TupleKey { + User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation = "viewer", + Object = "document:roadmap" + }, DateTime.Now) } }; @@ -651,7 +731,11 @@ public async Task ReadEmptyTest() { var mockHandler = new Mock(MockBehavior.Strict); var expectedResponse = new ReadResponse() { Tuples = new List() { - new(new TupleKey("document:roadmap", "viewer", "user:81684243-9356-4421-8fbf-a4f8d36aa31b"), + new(new TupleKey { + User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation = "viewer", + Object = "document:roadmap" + }, DateTime.Now) } }; @@ -811,7 +895,7 @@ public async Task WriteMixedWithAuthorizationModelIdTest() { Object = "document:roadmap", }, }, - Deletes = new List { + Deletes = new List { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "writer", @@ -876,7 +960,7 @@ public async Task WriteNonTransactionTest() { Object = "document:budget", } }, - Deletes = new List { + Deletes = new List { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "writer", @@ -939,8 +1023,13 @@ public async Task CheckTest() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "editor", Object = "document:roadmap", + Condition = new RelationshipCondition() { + Name = "ViewCountLessThan200", + Context = new { Name = "Roadmap", Type = "document" } + } } }, + Context = new { ViewCount = 100 } }; var options = new ClientCheckOptions { }; var response = await fgaClient.Check(body, options); diff --git a/src/OpenFga.Sdk.Test/OpenFga.Sdk.Test.csproj b/src/OpenFga.Sdk.Test/OpenFga.Sdk.Test.csproj index 2f12130..3c5cc51 100644 --- a/src/OpenFga.Sdk.Test/OpenFga.Sdk.Test.csproj +++ b/src/OpenFga.Sdk.Test/OpenFga.Sdk.Test.csproj @@ -11,8 +11,8 @@ all all - all - + all + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/OpenFga.Sdk/Api/OpenFgaApi.cs b/src/OpenFga.Sdk/Api/OpenFgaApi.cs index bbdb8e1..de5eade 100644 --- a/src/OpenFga.Sdk/Api/OpenFgaApi.cs +++ b/src/OpenFga.Sdk/Api/OpenFgaApi.cs @@ -21,14 +21,6 @@ public class OpenFgaApi : IDisposable { private Configuration.Configuration _configuration; private ApiClient.ApiClient _apiClient; - /// - /// Store ID - /// - public string? StoreId { - get => _configuration.StoreId; - set => _configuration.StoreId = value; - } - /// /// Initializes a new instance of the class. /// @@ -38,25 +30,28 @@ public OpenFgaApi( Configuration.Configuration configuration, HttpClient? httpClient = null ) { + configuration.IsValid(); this._configuration = configuration; this._apiClient = new ApiClient.ApiClient(_configuration, httpClient); } /// - /// 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. 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. 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. + /// 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. /// /// Thrown when fails to make API call + /// /// /// Cancellation Token to cancel the request. /// Task of CheckResponse - public async Task Check(CheckRequest body, CancellationToken cancellationToken = default) { + public async Task Check(string storeId, CheckRequest body, CancellationToken cancellationToken = default) { var pathParams = new Dictionary { }; - if (string.IsNullOrWhiteSpace(_configuration.StoreId)) { - throw new FgaRequiredParamError("Check", nameof(_configuration.StoreId)); + if (string.IsNullOrWhiteSpace(storeId)) { + throw new FgaRequiredParamError("Check", "StoreId"); } - pathParams.Add("store_id", _configuration.StoreId); - + if (storeId != null) { + pathParams.Add("store_id", storeId.ToString()); + } var queryParams = new Dictionary(); var requestBuilder = new RequestBuilder { @@ -101,16 +96,18 @@ public async Task CreateStore(CreateStoreRequest body, Canc /// Delete a store Delete an OpenFGA store. This does not delete the data associated with the store, like tuples or authorization models. /// /// Thrown when fails to make API call + /// /// Cancellation Token to cancel the request. /// Task of void - public async Task DeleteStore(CancellationToken cancellationToken = default) { + public async Task DeleteStore(string storeId, CancellationToken cancellationToken = default) { var pathParams = new Dictionary { }; - if (string.IsNullOrWhiteSpace(_configuration.StoreId)) { - throw new FgaRequiredParamError("DeleteStore", nameof(_configuration.StoreId)); + if (string.IsNullOrWhiteSpace(storeId)) { + throw new FgaRequiredParamError("DeleteStore", "StoreId"); } - pathParams.Add("store_id", _configuration.StoreId); - + if (storeId != null) { + pathParams.Add("store_id", storeId.ToString()); + } var queryParams = new Dictionary(); var requestBuilder = new RequestBuilder { @@ -129,17 +126,19 @@ await this._apiClient.SendRequestAsync(requestBuilder, /// Expand all relationships in userset tree format, and following userset rewrite rules. Useful to reason about and debug a certain relationship The Expand API will return all users and usersets that have certain relationship with an object in a certain store. This is different from the `/stores/{store_id}/read` API in that both users and computed usersets are returned. Body parameters `tuple_key.object` and `tuple_key.relation` are all required. The response will return a tree whose leaves are the specific users and usersets. Union, intersection and difference operator are located in the intermediate nodes. ## Example To expand all users that have the `reader` relationship with object `document:2021-budget`, use the Expand API with the following request body ```json { \"tuple_key\": { \"object\": \"document:2021-budget\", \"relation\": \"reader\" }, \"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\" } ``` OpenFGA's response will be a userset tree of the users and usersets that have read access to the document. ```json { \"tree\":{ \"root\":{ \"type\":\"document:2021-budget#reader\", \"union\":{ \"nodes\":[ { \"type\":\"document:2021-budget#reader\", \"leaf\":{ \"users\":{ \"users\":[ \"user:bob\" ] } } }, { \"type\":\"document:2021-budget#reader\", \"leaf\":{ \"computed\":{ \"userset\":\"document:2021-budget#writer\" } } } ] } } } } ``` The caller can then call expand API for the `writer` relationship for the `document:2021-budget`. /// /// Thrown when fails to make API call + /// /// /// Cancellation Token to cancel the request. /// Task of ExpandResponse - public async Task Expand(ExpandRequest body, CancellationToken cancellationToken = default) { + public async Task Expand(string storeId, ExpandRequest body, CancellationToken cancellationToken = default) { var pathParams = new Dictionary { }; - if (string.IsNullOrWhiteSpace(_configuration.StoreId)) { - throw new FgaRequiredParamError("Expand", nameof(_configuration.StoreId)); + if (string.IsNullOrWhiteSpace(storeId)) { + throw new FgaRequiredParamError("Expand", "StoreId"); } - pathParams.Add("store_id", _configuration.StoreId); - + if (storeId != null) { + pathParams.Add("store_id", storeId.ToString()); + } var queryParams = new Dictionary(); var requestBuilder = new RequestBuilder { @@ -159,16 +158,18 @@ public async Task Expand(ExpandRequest body, CancellationToken c /// Get a store Returns an OpenFGA store by its identifier /// /// Thrown when fails to make API call + /// /// Cancellation Token to cancel the request. /// Task of GetStoreResponse - public async Task GetStore(CancellationToken cancellationToken = default) { + public async Task GetStore(string storeId, CancellationToken cancellationToken = default) { var pathParams = new Dictionary { }; - if (string.IsNullOrWhiteSpace(_configuration.StoreId)) { - throw new FgaRequiredParamError("GetStore", nameof(_configuration.StoreId)); + if (string.IsNullOrWhiteSpace(storeId)) { + throw new FgaRequiredParamError("GetStore", "StoreId"); } - pathParams.Add("store_id", _configuration.StoreId); - + if (storeId != null) { + pathParams.Add("store_id", storeId.ToString()); + } var queryParams = new Dictionary(); var requestBuilder = new RequestBuilder { @@ -184,20 +185,22 @@ public async Task GetStore(CancellationToken cancellationToken } /// - /// 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. 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. + /// 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. /// /// Thrown when fails to make API call + /// /// /// Cancellation Token to cancel the request. /// Task of ListObjectsResponse - public async Task ListObjects(ListObjectsRequest body, CancellationToken cancellationToken = default) { + public async Task ListObjects(string storeId, ListObjectsRequest body, CancellationToken cancellationToken = default) { var pathParams = new Dictionary { }; - if (string.IsNullOrWhiteSpace(_configuration.StoreId)) { - throw new FgaRequiredParamError("ListObjects", nameof(_configuration.StoreId)); + if (string.IsNullOrWhiteSpace(storeId)) { + throw new FgaRequiredParamError("ListObjects", "StoreId"); } - pathParams.Add("store_id", _configuration.StoreId); - + if (storeId != null) { + pathParams.Add("store_id", storeId.ToString()); + } var queryParams = new Dictionary(); var requestBuilder = new RequestBuilder { @@ -248,17 +251,19 @@ public async Task ListObjects(ListObjectsRequest body, Canc /// 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. 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`). /// /// Thrown when fails to make API call + /// /// /// Cancellation Token to cancel the request. /// Task of ReadResponse - public async Task Read(ReadRequest body, CancellationToken cancellationToken = default) { + public async Task Read(string storeId, ReadRequest body, CancellationToken cancellationToken = default) { var pathParams = new Dictionary { }; - if (string.IsNullOrWhiteSpace(_configuration.StoreId)) { - throw new FgaRequiredParamError("Read", nameof(_configuration.StoreId)); + if (string.IsNullOrWhiteSpace(storeId)) { + throw new FgaRequiredParamError("Read", "StoreId"); } - pathParams.Add("store_id", _configuration.StoreId); - + if (storeId != null) { + pathParams.Add("store_id", storeId.ToString()); + } var queryParams = new Dictionary(); var requestBuilder = new RequestBuilder { @@ -278,17 +283,19 @@ public async Task Read(ReadRequest body, CancellationToken cancell /// Read assertions for an authorization model ID The ReadAssertions API will return, for a given authorization model id, all the assertions stored for it. An assertion is an object that contains a tuple key, and the expectation of whether a call to the Check API of that tuple key will return true or false. /// /// Thrown when fails to make API call + /// /// /// Cancellation Token to cancel the request. /// Task of ReadAssertionsResponse - public async Task ReadAssertions(string authorizationModelId, CancellationToken cancellationToken = default) { + public async Task ReadAssertions(string storeId, string authorizationModelId, CancellationToken cancellationToken = default) { var pathParams = new Dictionary { }; - if (string.IsNullOrWhiteSpace(_configuration.StoreId)) { - throw new FgaRequiredParamError("ReadAssertions", nameof(_configuration.StoreId)); + if (string.IsNullOrWhiteSpace(storeId)) { + throw new FgaRequiredParamError("ReadAssertions", "StoreId"); } - pathParams.Add("store_id", _configuration.StoreId); - + if (storeId != null) { + pathParams.Add("store_id", storeId.ToString()); + } if (authorizationModelId != null) { pathParams.Add("authorization_model_id", authorizationModelId.ToString()); } @@ -310,17 +317,19 @@ public async Task ReadAssertions(string authorizationMod /// Return a particular version of an authorization model The ReadAuthorizationModel API returns an authorization model by its identifier. The response will return the authorization model for the particular version. ## Example To retrieve the authorization model with ID `01G5JAVJ41T49E9TT3SKVS7X1J` for the store, call the GET authorization-models by ID API with `01G5JAVJ41T49E9TT3SKVS7X1J` as the `id` path parameter. The API will return: ```json { \"authorization_model\":{ \"id\":\"01G5JAVJ41T49E9TT3SKVS7X1J\", \"type_definitions\":[ { \"type\":\"user\" }, { \"type\":\"document\", \"relations\":{ \"reader\":{ \"union\":{ \"child\":[ { \"this\":{} }, { \"computedUserset\":{ \"object\":\"\", \"relation\":\"writer\" } } ] } }, \"writer\":{ \"this\":{} } } } ] } } ``` In the above example, there are 2 types (`user` and `document`). The `document` type has 2 relations (`writer` and `reader`). /// /// Thrown when fails to make API call + /// /// /// Cancellation Token to cancel the request. /// Task of ReadAuthorizationModelResponse - public async Task ReadAuthorizationModel(string id, CancellationToken cancellationToken = default) { + public async Task ReadAuthorizationModel(string storeId, string id, CancellationToken cancellationToken = default) { var pathParams = new Dictionary { }; - if (string.IsNullOrWhiteSpace(_configuration.StoreId)) { - throw new FgaRequiredParamError("ReadAuthorizationModel", nameof(_configuration.StoreId)); + if (string.IsNullOrWhiteSpace(storeId)) { + throw new FgaRequiredParamError("ReadAuthorizationModel", "StoreId"); } - pathParams.Add("store_id", _configuration.StoreId); - + if (storeId != null) { + pathParams.Add("store_id", storeId.ToString()); + } if (id != null) { pathParams.Add("id", id.ToString()); } @@ -342,18 +351,20 @@ public async Task ReadAuthorizationModel(string /// Return all the authorization models for a particular store The ReadAuthorizationModels API will return all the authorization models for a certain store. OpenFGA's response will contain an array of all authorization models, sorted in descending order of creation. ## Example Assume that a store's authorization model has been configured twice. To get all the authorization models that have been created in this store, call GET authorization-models. The API will return a response that looks like: ```json { \"authorization_models\": [ { \"id\": \"01G50QVV17PECNVAHX1GG4Y5NC\", \"type_definitions\": [...] }, { \"id\": \"01G4ZW8F4A07AKQ8RHSVG9RW04\", \"type_definitions\": [...] }, ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` If there are no more authorization models available, the `continuation_token` field will be empty ```json { \"authorization_models\": [ { \"id\": \"01G50QVV17PECNVAHX1GG4Y5NC\", \"type_definitions\": [...] }, { \"id\": \"01G4ZW8F4A07AKQ8RHSVG9RW04\", \"type_definitions\": [...] }, ], \"continuation_token\": \"\" } ``` /// /// Thrown when fails to make API call + /// /// (optional) /// (optional) /// Cancellation Token to cancel the request. /// Task of ReadAuthorizationModelsResponse - public async Task ReadAuthorizationModels(int? pageSize = default(int?), string? continuationToken = default(string?), CancellationToken cancellationToken = default) { + public async Task ReadAuthorizationModels(string storeId, int? pageSize = default(int?), string? continuationToken = default(string?), CancellationToken cancellationToken = default) { var pathParams = new Dictionary { }; - if (string.IsNullOrWhiteSpace(_configuration.StoreId)) { - throw new FgaRequiredParamError("ReadAuthorizationModels", nameof(_configuration.StoreId)); + if (string.IsNullOrWhiteSpace(storeId)) { + throw new FgaRequiredParamError("ReadAuthorizationModels", "StoreId"); } - pathParams.Add("store_id", _configuration.StoreId); - + if (storeId != null) { + pathParams.Add("store_id", storeId.ToString()); + } var queryParams = new Dictionary(); if (pageSize != null) { queryParams.Add("page_size", pageSize.ToString()); @@ -375,22 +386,24 @@ public async Task ReadAuthorizationModel(string } /// - /// Return a list of all the tuple changes The ReadChanges API will return a paginated list of tuple changes (additions and deletions) that occurred in a given store, sorted by ascending time. The response will include a continuation token that is used to get the next set of changes. If there are no changes after the provided continuation token, the same token will be returned in order for it to be used when new changes are recorded. If the store never had any tuples added or removed, this token will be empty. You can use the `type` parameter to only get the list of tuple changes that affect objects of that type. + /// Return a list of all the tuple changes The ReadChanges API will return a paginated list of tuple changes (additions and deletions) that occurred in a given store, sorted by ascending time. The response will include a continuation token that is used to get the next set of changes. If there are no changes after the provided continuation token, the same token will be returned in order for it to be used when new changes are recorded. If the store never had any tuples added or removed, this token will be empty. You can use the `type` parameter to only get the list of tuple changes that affect objects of that type. When reading a write tuple change, if it was conditioned, the condition will be returned. When reading a delete tuple change, the condition will NOT be returned regardless of whether it was originally conditioned or not. /// /// Thrown when fails to make API call + /// /// (optional) /// (optional) /// (optional) /// Cancellation Token to cancel the request. /// Task of ReadChangesResponse - public async Task ReadChanges(string? type = default(string?), int? pageSize = default(int?), string? continuationToken = default(string?), CancellationToken cancellationToken = default) { + public async Task ReadChanges(string storeId, string? type = default(string?), int? pageSize = default(int?), string? continuationToken = default(string?), CancellationToken cancellationToken = default) { var pathParams = new Dictionary { }; - if (string.IsNullOrWhiteSpace(_configuration.StoreId)) { - throw new FgaRequiredParamError("ReadChanges", nameof(_configuration.StoreId)); + if (string.IsNullOrWhiteSpace(storeId)) { + throw new FgaRequiredParamError("ReadChanges", "StoreId"); } - pathParams.Add("store_id", _configuration.StoreId); - + if (storeId != null) { + pathParams.Add("store_id", storeId.ToString()); + } var queryParams = new Dictionary(); if (type != null) { queryParams.Add("type", type.ToString()); @@ -415,20 +428,22 @@ public async Task ReadAuthorizationModel(string } /// - /// 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 while `deletes` removes existing tuples. The API is not idempotent: if, later on, you try to add the same tuple, 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\" } ] } } ``` + /// 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\" } ] } } ``` /// /// Thrown when fails to make API call + /// /// /// Cancellation Token to cancel the request. /// Task of Object - public async Task Write(WriteRequest body, CancellationToken cancellationToken = default) { + public async Task Write(string storeId, WriteRequest body, CancellationToken cancellationToken = default) { var pathParams = new Dictionary { }; - if (string.IsNullOrWhiteSpace(_configuration.StoreId)) { - throw new FgaRequiredParamError("Write", nameof(_configuration.StoreId)); + if (string.IsNullOrWhiteSpace(storeId)) { + throw new FgaRequiredParamError("Write", "StoreId"); } - pathParams.Add("store_id", _configuration.StoreId); - + if (storeId != null) { + pathParams.Add("store_id", storeId.ToString()); + } var queryParams = new Dictionary(); var requestBuilder = new RequestBuilder { @@ -448,18 +463,20 @@ public async Task Write(WriteRequest body, CancellationToken cancellatio /// Upsert assertions for an authorization model ID The WriteAssertions API will upsert new assertions for an authorization model id, or overwrite the existing ones. An assertion is an object that contains a tuple key, and the expectation of whether a call to the Check API of that tuple key will return true or false. /// /// Thrown when fails to make API call + /// /// /// /// Cancellation Token to cancel the request. /// Task of void - public async Task WriteAssertions(string authorizationModelId, WriteAssertionsRequest body, CancellationToken cancellationToken = default) { + public async Task WriteAssertions(string storeId, string authorizationModelId, WriteAssertionsRequest body, CancellationToken cancellationToken = default) { var pathParams = new Dictionary { }; - if (string.IsNullOrWhiteSpace(_configuration.StoreId)) { - throw new FgaRequiredParamError("WriteAssertions", nameof(_configuration.StoreId)); + if (string.IsNullOrWhiteSpace(storeId)) { + throw new FgaRequiredParamError("WriteAssertions", "StoreId"); } - pathParams.Add("store_id", _configuration.StoreId); - + if (storeId != null) { + pathParams.Add("store_id", storeId.ToString()); + } if (authorizationModelId != null) { pathParams.Add("authorization_model_id", authorizationModelId.ToString()); } @@ -482,17 +499,19 @@ await this._apiClient.SendRequestAsync(requestBuilder, /// Create a new authorization model The WriteAuthorizationModel API will add a new authorization model to a store. Each item in the `type_definitions` array is a type definition as specified in the field `type_definition`. The response will return the authorization model's ID in the `id` field. ## Example To add an authorization model with `user` and `document` type definitions, call POST authorization-models API with the body: ```json { \"type_definitions\":[ { \"type\":\"user\" }, { \"type\":\"document\", \"relations\":{ \"reader\":{ \"union\":{ \"child\":[ { \"this\":{} }, { \"computedUserset\":{ \"object\":\"\", \"relation\":\"writer\" } } ] } }, \"writer\":{ \"this\":{} } } } ] } ``` OpenFGA's response will include the version id for this authorization model, which will look like ``` {\"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\"} ``` /// /// Thrown when fails to make API call + /// /// /// Cancellation Token to cancel the request. /// Task of WriteAuthorizationModelResponse - public async Task WriteAuthorizationModel(WriteAuthorizationModelRequest body, CancellationToken cancellationToken = default) { + public async Task WriteAuthorizationModel(string storeId, WriteAuthorizationModelRequest body, CancellationToken cancellationToken = default) { var pathParams = new Dictionary { }; - if (string.IsNullOrWhiteSpace(_configuration.StoreId)) { - throw new FgaRequiredParamError("WriteAuthorizationModel", nameof(_configuration.StoreId)); + if (string.IsNullOrWhiteSpace(storeId)) { + throw new FgaRequiredParamError("WriteAuthorizationModel", "StoreId"); } - pathParams.Add("store_id", _configuration.StoreId); - + if (storeId != null) { + pathParams.Add("store_id", storeId.ToString()); + } var queryParams = new Dictionary(); var requestBuilder = new RequestBuilder { diff --git a/src/OpenFga.Sdk/ApiClient/ApiClient.cs b/src/OpenFga.Sdk/ApiClient/ApiClient.cs index 044d829..c73224d 100644 --- a/src/OpenFga.Sdk/ApiClient/ApiClient.cs +++ b/src/OpenFga.Sdk/ApiClient/ApiClient.cs @@ -40,7 +40,7 @@ public ApiClient(Configuration.Configuration configuration, HttpClient? userHttp switch (_configuration.Credentials.Method) { case CredentialsMethod.ApiToken: - _configuration.DefaultHeaders.Add("Authorization", $"Bearer {_configuration.Credentials.Config!.ApiToken}"); + _configuration.DefaultHeaders["Authorization"] = $"Bearer {_configuration.Credentials.Config!.ApiToken}"; _baseClient = new BaseClient(_configuration, userHttpClient); break; case CredentialsMethod.ClientCredentials: @@ -71,7 +71,7 @@ public async Task SendRequestAsync(RequestBuilder requestBuilder, string a var token = await _oauth2Client.GetAccessTokenAsync(); if (!string.IsNullOrEmpty(token)) { - additionalHeaders.Add("Authorization", $"Bearer {token}"); + additionalHeaders["Authorization"] = $"Bearer {token}"; } } catch (ApiException e) { @@ -98,7 +98,7 @@ public async Task SendRequestAsync(RequestBuilder requestBuilder, string apiName var token = await _oauth2Client.GetAccessTokenAsync(); if (!string.IsNullOrEmpty(token)) { - additionalHeaders.Add("Authorization", $"Bearer {token}"); + additionalHeaders["Authorization"] = $"Bearer {token}"; } } catch (ApiException e) { diff --git a/src/OpenFga.Sdk/Client/Client.cs b/src/OpenFga.Sdk/Client/Client.cs index 7b6cf88..f00f9a8 100644 --- a/src/OpenFga.Sdk/Client/Client.cs +++ b/src/OpenFga.Sdk/Client/Client.cs @@ -31,6 +31,7 @@ public OpenFgaClient( ClientConfiguration configuration, HttpClient? httpClient = null ) { + configuration.IsValid(); _configuration = configuration; api = new OpenFgaApi(_configuration, httpClient); } @@ -53,8 +54,26 @@ public string? AuthorizationModelId { public void Dispose() => api.Dispose(); - private string? GetAuthorizationModelId(AuthorizationModelIdOptions? options) => - options?.AuthorizationModelId ?? AuthorizationModelId; + private string GetStoreId(StoreIdOptions? options) { + var storeId = options?.StoreId ?? StoreId; + if (storeId == null) { + throw new FgaRequiredParamError("ClientConfiguration", "StoreId"); + } + else if (!ClientConfiguration.IsWellFormedUlidString(storeId)) { + throw new FgaValidationError("StoreId is not in a valid ulid format"); + } + + return storeId; + } + + private string? GetAuthorizationModelId(AuthorizationModelIdOptions? options) { + var authorizationModelId = options?.AuthorizationModelId ?? AuthorizationModelId; + if (authorizationModelId != null && authorizationModelId != "" && !ClientConfiguration.IsWellFormedUlidString(authorizationModelId)) { + throw new FgaValidationError("AuthorizationModelId is not in a valid ulid format"); + } + + return authorizationModelId; + } /********** * Stores * @@ -78,14 +97,14 @@ public async Task CreateStore(ClientCreateStoreRequest body /** * GetStore - Get information about the current store */ - public async Task GetStore(ClientRequestOptions? options = default, CancellationToken cancellationToken = default) => - await api.GetStore(cancellationToken); + public async Task GetStore(IClientRequestOptionsWithStoreId? options = default, CancellationToken cancellationToken = default) => + await api.GetStore(GetStoreId(options), cancellationToken); /** * DeleteStore - Delete a store */ - public async Task DeleteStore(ClientRequestOptions? options = default, CancellationToken cancellationToken = default) => - await api.DeleteStore(cancellationToken); + public async Task DeleteStore(IClientRequestOptionsWithStoreId? options = default, CancellationToken cancellationToken = default) => + await api.DeleteStore(GetStoreId(options), cancellationToken); /************************ * Authorization Models * @@ -97,15 +116,15 @@ public async Task DeleteStore(ClientRequestOptions? options = default, Cancellat public async Task ReadAuthorizationModels( IClientReadAuthorizationModelsOptions? options = default, CancellationToken cancellationToken = default) => - await api.ReadAuthorizationModels(options?.PageSize, options?.ContinuationToken, cancellationToken); + await api.ReadAuthorizationModels(GetStoreId(options), options?.PageSize, options?.ContinuationToken, cancellationToken); /** * WriteAuthorizationModel - Create a new version of the authorization model */ public async Task WriteAuthorizationModel(ClientWriteAuthorizationModelRequest body, - ClientRequestOptions? options = default, + IClientRequestOptionsWithStoreId? options = default, CancellationToken cancellationToken = default) => - await api.WriteAuthorizationModel(body, cancellationToken); + await api.WriteAuthorizationModel(GetStoreId(options), body, cancellationToken); /** * ReadAuthorizationModel - Read the current authorization model @@ -118,18 +137,23 @@ public async Task ReadAuthorizationModel( throw new FgaRequiredParamError("ClientConfiguration", "AuthorizationModelId"); } - return await api.ReadAuthorizationModel(authorizationModelId, cancellationToken); + return await api.ReadAuthorizationModel(GetStoreId(options), authorizationModelId, cancellationToken); } /** * ReadLatestAuthorizationModel - Read the latest authorization model for the current store */ - public async Task ReadLatestAuthorizationModel( + public async Task ReadLatestAuthorizationModel( IClientRequestOptionsWithAuthZModelId? options = default, CancellationToken cancellationToken = default) { var response = - await ReadAuthorizationModels(new ClientReadAuthorizationModelsOptions { PageSize = 1 }, cancellationToken); - return new ReadAuthorizationModelResponse { AuthorizationModel = response.AuthorizationModels?[0] }; + await ReadAuthorizationModels(new ClientReadAuthorizationModelsOptions { StoreId = options?.StoreId, PageSize = 1 }, cancellationToken); + + if (response.AuthorizationModels.Count > 0) { + return new ReadAuthorizationModelResponse { AuthorizationModel = response.AuthorizationModels?[0] }; + } + + return null; } /*********************** @@ -139,21 +163,22 @@ public async Task ReadLatestAuthorizationModel( /** * Read Changes - Read the list of historical relationship tuple writes and deletes */ - public async Task ReadChanges(ClientReadChangesRequest body, + public async Task ReadChanges(ClientReadChangesRequest? body = default, IClientReadChangesOptions? options = default, CancellationToken cancellationToken = default) => - await api.ReadChanges(body.Type, options?.PageSize, options?.ContinuationToken, cancellationToken); + await api.ReadChanges(GetStoreId(options), body?.Type, options?.PageSize, options?.ContinuationToken, cancellationToken); /** * Read - Read tuples previously written to the store (does not evaluate) */ - public async Task Read(ClientReadRequest body, IClientReadOptions? options = default, + public async Task Read(ClientReadRequest? body = default, IClientReadOptions? options = default, CancellationToken cancellationToken = default) { - TupleKey tupleKey = null; + ReadRequestTupleKey tupleKey = null; if (body != null && (body.User != null || body.Relation != null || body.Object != null)) { tupleKey = body; } return await api.Read( + GetStoreId(options), new ReadRequest { TupleKey = tupleKey, PageSize = options?.PageSize, @@ -178,13 +203,13 @@ public async Task Write(ClientWriteRequest body, IClientWri AuthorizationModelId = authorizationModelId }; if (body.Writes?.Count > 0) { - requestBody.Writes = new TupleKeys(body.Writes.ConvertAll(key => key.ToTupleKey())); + requestBody.Writes = new WriteRequestWrites(body.Writes.ConvertAll(key => key.ToTupleKey())); } if (body.Deletes?.Count > 0) { - requestBody.Deletes = new TupleKeys(body.Deletes.ConvertAll(key => key.ToTupleKey())); + requestBody.Deletes = new WriteRequestDeletes(body.Deletes.ConvertAll(key => key.ToTupleKeyWithoutCondition())); } - await api.Write(requestBody, cancellationToken); + await api.Write(GetStoreId(options), requestBody, cancellationToken); return new ClientWriteResponse { Writes = body.Writes?.ConvertAll(tupleKey => @@ -197,8 +222,10 @@ public async Task Write(ClientWriteRequest body, IClientWri }; } + var clientWriteOpts = new ClientWriteOptions() { StoreId = StoreId, AuthorizationModelId = authorizationModelId }; + var writeChunks = body.Writes?.Chunk(maxPerChunk).ToList() ?? new List(); - var deleteChunks = body.Deletes?.Chunk(maxPerChunk).ToList() ?? new List(); + var deleteChunks = body.Deletes?.Chunk(maxPerChunk).ToList() ?? new List(); var writeResponses = new ConcurrentBag(); var deleteResponses = new ConcurrentBag(); @@ -206,7 +233,7 @@ await Parallel.ForEachAsync(writeChunks, new ParallelOptions { MaxDegreeOfParallelism = maxParallelReqs }, async (request, token) => { var writes = request.ToList(); try { - await this.Write(new ClientWriteRequest() { Writes = writes }, new ClientWriteOptions() { AuthorizationModelId = authorizationModelId }, cancellationToken); + await this.Write(new ClientWriteRequest() { Writes = writes }, clientWriteOpts, cancellationToken); foreach (var tupleKey in writes) { writeResponses.Add(new ClientWriteSingleResponse { @@ -230,7 +257,7 @@ await Parallel.ForEachAsync(deleteChunks, new ParallelOptions { MaxDegreeOfParallelism = maxParallelReqs }, async (request, token) => { var deletes = request.ToList(); try { - await this.Write(new ClientWriteRequest() { Deletes = deletes }, new ClientWriteOptions() { AuthorizationModelId = authorizationModelId }, cancellationToken); + await this.Write(new ClientWriteRequest() { Deletes = deletes }, clientWriteOpts, cancellationToken); foreach (var tupleKey in deletes) { deleteResponses.Add(new ClientWriteSingleResponse { @@ -263,7 +290,7 @@ public async Task WriteTuples(List body, IC /** * DeleteTuples - Utility method to delete tuples, wraps Write */ - public async Task DeleteTuples(List body, IClientWriteOptions? options = default, + public async Task DeleteTuples(List body, IClientWriteOptions? options = default, CancellationToken cancellationToken = default) => await Write(new ClientWriteRequest { Deletes = body }, options, cancellationToken); @@ -278,13 +305,15 @@ public async Task Check(IClientCheckRequest body, IClientRequestOptionsWithAuthZModelId? options = default, CancellationToken cancellationToken = default) => await api.Check( + GetStoreId(options), new CheckRequest { - TupleKey = new TupleKey { User = body.User, Relation = body.Relation, Object = body.Object }, + TupleKey = new CheckRequestTupleKey { User = body.User, Relation = body.Relation, Object = body.Object }, ContextualTuples = new ContextualTupleKeys { TupleKeys = body.ContextualTuples?.ConvertAll(tupleKey => tupleKey.ToTupleKey()) ?? new List() }, + Context = body.Context, AuthorizationModelId = GetAuthorizationModelId(options) }, cancellationToken); @@ -321,8 +350,9 @@ public async Task Expand(IClientExpandRequest body, IClientRequestOptionsWithAuthZModelId? options = default, CancellationToken cancellationToken = default) => await api.Expand( + GetStoreId(options), new ExpandRequest { - TupleKey = new TupleKey { Relation = body.Relation, Object = body.Object }, + TupleKey = new ExpandRequestTupleKey { Relation = body.Relation, Object = body.Object }, AuthorizationModelId = GetAuthorizationModelId(options) }, cancellationToken); @@ -332,7 +362,7 @@ await api.Expand( public async Task ListObjects(IClientListObjectsRequest body, IClientRequestOptionsWithAuthZModelId? options = default, CancellationToken cancellationToken = default) => - await api.ListObjects(new ListObjectsRequest { + await api.ListObjects(GetStoreId(options), new ListObjectsRequest { User = body.User, Relation = body.Relation, Type = body.Type, @@ -341,6 +371,7 @@ await api.ListObjects(new ListObjectsRequest { TupleKeys = body.ContextualTuples?.ConvertAll(tupleKey => tupleKey.ToTupleKey()) ?? new List() }, + Context = body.Context, AuthorizationModelId = GetAuthorizationModelId(options) }); @@ -362,7 +393,8 @@ public async Task ListRelations(IClientListRelationsReque User = body.User, Relation = relation, Object = body.Object, - ContextualTuples = body.ContextualTuples + ContextualTuples = body.ContextualTuples, + Context = body.Context }); } @@ -392,7 +424,7 @@ public async Task ReadAssertions(IClientReadAssertionsOp throw new FgaRequiredParamError("ClientConfiguration", "AuthorizationModelId"); } - return await api.ReadAssertions(authorizationModelId, cancellationToken); + return await api.ReadAssertions(GetStoreId(options), authorizationModelId, cancellationToken); } /** @@ -411,7 +443,7 @@ public async Task WriteAssertions(List body, for (var index = 0; index < body.Count; index++) { var assertion = body[index]; assertions.Add(new Assertion { - TupleKey = new TupleKey { + TupleKey = new AssertionTupleKey { User = assertion.User, Relation = assertion.Relation, Object = assertion.Object @@ -420,7 +452,7 @@ public async Task WriteAssertions(List body, }); } - await api.WriteAssertions(authorizationModelId, + await api.WriteAssertions(GetStoreId(options), authorizationModelId, new WriteAssertionsRequest { Assertions = assertions }, cancellationToken); } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Client/ClientConfiguration.cs b/src/OpenFga.Sdk/Client/ClientConfiguration.cs index 451d312..1cc562c 100644 --- a/src/OpenFga.Sdk/Client/ClientConfiguration.cs +++ b/src/OpenFga.Sdk/Client/ClientConfiguration.cs @@ -12,6 +12,8 @@ using OpenFga.Sdk.Client.Model; +using OpenFga.Sdk.Exceptions; +using System.Text.RegularExpressions; namespace OpenFga.Sdk.Client; @@ -19,15 +21,21 @@ public class ClientConfiguration : Configuration.Configuration { public ClientConfiguration(Configuration.Configuration config) { ApiScheme = config.ApiScheme; ApiHost = config.ApiHost; + ApiUrl = config.ApiUrl; UserAgent = config.UserAgent; Credentials = config.Credentials; DefaultHeaders = config.DefaultHeaders; - StoreId = config.StoreId; RetryParams = new RetryParams { MaxRetry = config.MaxRetry, MinWaitInMs = config.MinWaitInMs }; } public ClientConfiguration() { } + /// + /// Gets or sets the Store ID. + /// + /// Store ID. + public string? StoreId { get; set; } + /// /// Gets or sets the Authorization Model ID. /// @@ -35,4 +43,26 @@ public ClientConfiguration() { } public string? AuthorizationModelId { get; set; } public RetryParams? RetryParams { get; set; } = new(); + + public new void IsValid() { + base.IsValid(); + + if (StoreId != null && !IsWellFormedUlidString(StoreId)) { + throw new FgaValidationError("StoreId is not in a valid ulid format"); + } + + if (AuthorizationModelId != null && AuthorizationModelId != "" && !IsWellFormedUlidString(AuthorizationModelId)) { + throw new FgaValidationError("AuthorizationModelId is not in a valid ulid format"); + } + } + + /// + /// Ensures that a string is in valid [ULID](https://github.com/ulid/spec) format + /// + /// + /// + public static bool IsWellFormedUlidString(string ulid) { + var regex = new Regex("^[0-7][0-9A-HJKMNP-TV-Z]{25}$"); + return regex.IsMatch(ulid); + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Client/Model/ClientBatchCheckOptions.cs b/src/OpenFga.Sdk/Client/Model/ClientBatchCheckOptions.cs index 59c8b9d..210cca0 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientBatchCheckOptions.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientBatchCheckOptions.cs @@ -21,6 +21,8 @@ public interface IClientBatchCheckOptions : IClientRequestOptionsWithAuthZModelI } public class ClientBatchCheckOptions : IClientBatchCheckOptions { + /// + public string? StoreId { get; set; } /// public string? AuthorizationModelId { get; set; } diff --git a/src/OpenFga.Sdk/Client/Model/ClientCheckOptions.cs b/src/OpenFga.Sdk/Client/Model/ClientCheckOptions.cs index c66a4b1..8723626 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientCheckOptions.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientCheckOptions.cs @@ -14,6 +14,8 @@ namespace OpenFga.Sdk.Client.Model; public class ClientCheckOptions : IClientRequestOptionsWithAuthZModelId { + /// + public string? StoreId { get; set; } /// public string? AuthorizationModelId { get; set; } diff --git a/src/OpenFga.Sdk/Client/Model/ClientCheckRequest.cs b/src/OpenFga.Sdk/Client/Model/ClientCheckRequest.cs index 9414741..6399899 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientCheckRequest.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientCheckRequest.cs @@ -18,11 +18,10 @@ namespace OpenFga.Sdk.Client.Model; -public interface IClientCheckRequest : IClientContextualTuplesWrapper { +public interface IClientCheckRequest : IClientQueryContextWrapper { public string User { get; set; } public string Relation { get; set; } public string Object { get; set; } - public List? ContextualTuples { get; set; } } /// @@ -50,12 +49,19 @@ public class ClientCheckRequest : IClientCheckRequest, IEquatable - /// Gets or Sets Object + /// Gets or Sets Contextual Tuples /// [DataMember(Name = "contextual_tuples", EmitDefaultValue = false)] [JsonPropertyName("contextual_tuples")] public List? ContextualTuples { get; set; } + /// + /// Gets or Sets Context + /// + [DataMember(Name = "context", EmitDefaultValue = false)] + [JsonPropertyName("context")] + public Object? Context { get; set; } + public bool Equals(ClientCheckRequest input) { if (input == null) { return false; @@ -63,9 +69,9 @@ public bool Equals(ClientCheckRequest input) { return ( - Object == input.Object || - (Object != null && - Object.Equals(input.Object)) + User == input.User || + (User != null && + User.Equals(input.User)) ) && ( Relation == input.Relation || @@ -73,14 +79,19 @@ public bool Equals(ClientCheckRequest input) { Relation.Equals(input.Relation)) ) && ( - User == input.User || - (User != null && - User.Equals(input.User)) + Object == input.Object || + (Object != null && + Object.Equals(input.Object)) ) && ( ContextualTuples == input.ContextualTuples || (ContextualTuples != null && ContextualTuples.Equals(input.ContextualTuples)) + ) && + ( + this.Context == input.Context || + (this.Context != null && + this.Context.Equals(input.Context)) ); } @@ -115,6 +126,10 @@ public override int GetHashCode() { hashCode = (hashCode * 9923) + ContextualTuples.GetHashCode(); } + if (Context != null) { + hashCode = (hashCode * 9923) + Context.GetHashCode(); + } + return hashCode; } } diff --git a/src/OpenFga.Sdk/Client/Model/ClientListObjectsRequest.cs b/src/OpenFga.Sdk/Client/Model/ClientListObjectsRequest.cs index 0e57a61..cc05087 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientListObjectsRequest.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientListObjectsRequest.cs @@ -18,7 +18,7 @@ namespace OpenFga.Sdk.Client.Model; -public interface IClientListObjectsRequest : IClientContextualTuplesWrapper { +public interface IClientListObjectsRequest : IClientQueryContextWrapper { public string User { get; set; } public string Relation { get; set; } public string Type { get; set; } @@ -57,6 +57,13 @@ public class ClientListObjectsRequest : IClientListObjectsRequest, IEquatable? ContextualTuples { get; set; } + /// + /// Gets or Sets Context + /// + [DataMember(Name = "context", EmitDefaultValue = false)] + [JsonPropertyName("context")] + public Object? Context { get; set; } + public bool Equals(ClientListObjectsRequest input) { if (input == null) { return false; @@ -64,9 +71,9 @@ public bool Equals(ClientListObjectsRequest input) { return ( - Type == input.Type || - (Type != null && - Type.Equals(input.Type)) + User == input.User || + (User != null && + User.Equals(input.User)) ) && ( Relation == input.Relation || @@ -74,14 +81,19 @@ public bool Equals(ClientListObjectsRequest input) { Relation.Equals(input.Relation)) ) && ( - User == input.User || - (User != null && - User.Equals(input.User)) + Type == input.Type || + (Type != null && + Type.Equals(input.Type)) ) && ( ContextualTuples == input.ContextualTuples || (ContextualTuples != null && ContextualTuples.Equals(input.ContextualTuples)) + ) && + ( + this.Context == input.Context || + (this.Context != null && + this.Context.Equals(input.Context)) ); } @@ -116,6 +128,10 @@ public override int GetHashCode() { hashCode = (hashCode * 9923) + ContextualTuples.GetHashCode(); } + if (Context != null) { + hashCode = (hashCode * 9923) + Context.GetHashCode(); + } + return hashCode; } } diff --git a/src/OpenFga.Sdk/Client/Model/ClientListRelationsOptions.cs b/src/OpenFga.Sdk/Client/Model/ClientListRelationsOptions.cs index b70ff58..d24c891 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientListRelationsOptions.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientListRelationsOptions.cs @@ -14,6 +14,8 @@ namespace OpenFga.Sdk.Client.Model; public class ClientListRelationsOptions : IClientBatchCheckOptions { + /// + public string? StoreId { get; set; } /// public string? AuthorizationModelId { get; set; } diff --git a/src/OpenFga.Sdk/Client/Model/ClientListRelationsRequest.cs b/src/OpenFga.Sdk/Client/Model/ClientListRelationsRequest.cs index 366a4ed..0c6f340 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientListRelationsRequest.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientListRelationsRequest.cs @@ -12,11 +12,13 @@ using System.ComponentModel.DataAnnotations; +using System.Runtime.Serialization; using System.Text.Json; +using System.Text.Json.Serialization; namespace OpenFga.Sdk.Client.Model; -public interface IClientListRelationsRequest : IClientContextualTuplesWrapper { +public interface IClientListRelationsRequest : IClientQueryContextWrapper { public string User { get; set; } public string Object { get; set; } @@ -36,6 +38,41 @@ public ClientListRelationsRequest() { Relations = new List(); } + /// + /// Gets or Sets User + /// + [DataMember(Name = "user", EmitDefaultValue = false)] + [JsonPropertyName("user")] + public string User { get; set; } + + /// + /// Gets or Sets Object + /// + [DataMember(Name = "object", EmitDefaultValue = false)] + [JsonPropertyName("object")] + public string Object { get; set; } + + /// + /// Gets or Sets Relation + /// + [DataMember(Name = "relations", EmitDefaultValue = false)] + [JsonPropertyName("relations")] + public List Relations { get; set; } + + /// + /// Gets or Sets Contextual Tuples + /// + [DataMember(Name = "contextual_tuples", EmitDefaultValue = false)] + [JsonPropertyName("contextual_tuples")] + public List? ContextualTuples { get; set; } + + /// + /// Gets or Sets Context + /// + [DataMember(Name = "context", EmitDefaultValue = false)] + [JsonPropertyName("context")] + public Object? Context { get; set; } + public bool Equals(ClientListRelationsRequest input) { if (input == null) { return false; @@ -43,34 +80,32 @@ public bool Equals(ClientListRelationsRequest input) { return ( - Object == input.Object || - (Object != null && - Object.Equals(input.Object)) + User == input.User || + (User != null && + User.Equals(input.User)) ) && ( Relations == input.Relations || (Relations != null && Relations.Equals(input.Relations)) ) && + ( + Object == input.Object || + (Object != null && + Object.Equals(input.Object)) + ) && ( ContextualTuples == input.ContextualTuples || (ContextualTuples != null && ContextualTuples.Equals(input.ContextualTuples)) ) && ( - User == input.User || - (User != null && - User.Equals(input.User)) + this.Context == input.Context || + (this.Context != null && + this.Context.Equals(input.Context)) ); } - public string User { get; set; } - - public string Object { get; set; } - - public List ContextualTuples { get; set; } - public List Relations { get; set; } - public IEnumerable Validate(ValidationContext validationContext) { yield break; } @@ -102,6 +137,10 @@ public override int GetHashCode() { hashCode = (hashCode * 9923) + ContextualTuples.GetHashCode(); } + if (Context != null) { + hashCode = (hashCode * 9923) + Context.GetHashCode(); + } + return hashCode; } } diff --git a/src/OpenFga.Sdk/Client/Model/ClientReadAssertionsOptions.cs b/src/OpenFga.Sdk/Client/Model/ClientReadAssertionsOptions.cs index abe5c2b..f7fc3f6 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientReadAssertionsOptions.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientReadAssertionsOptions.cs @@ -16,11 +16,13 @@ namespace OpenFga.Sdk.Client.Model; /// /// ClientReadAssertionsOptions - Client Options for ReadAssertions /// -public interface IClientReadAssertionsOptions : ClientRequestOptions, AuthorizationModelIdOptions { +public interface IClientReadAssertionsOptions : IClientRequestOptionsWithStoreId, AuthorizationModelIdOptions { } /// public class ClientReadAssertionsOptions : IClientReadAssertionsOptions { + /// + public string? StoreId { get; set; } /// public string? AuthorizationModelId { get; set; } diff --git a/src/OpenFga.Sdk/Client/Model/ClientReadAuthorizaionModelOptions.cs b/src/OpenFga.Sdk/Client/Model/ClientReadAuthorizaionModelOptions.cs index 7107c94..66f1f5e 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientReadAuthorizaionModelOptions.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientReadAuthorizaionModelOptions.cs @@ -16,11 +16,13 @@ namespace OpenFga.Sdk.Client.Model; /// /// ClientReadAuthorizationModelOptions - Client Options for ReadAuthorizationModel /// -public interface IClientReadAuthorizationModelOptions : ClientRequestOptions, AuthorizationModelIdOptions { +public interface IClientReadAuthorizationModelOptions : IClientRequestOptionsWithStoreId, AuthorizationModelIdOptions { } /// public class ClientReadAuthorizationModelOptions : IClientReadAuthorizationModelOptions { + /// + public string? StoreId { get; set; } /// public string? AuthorizationModelId { get; set; } diff --git a/src/OpenFga.Sdk/Client/Model/ClientReadAuthorizaionModelsOptions.cs b/src/OpenFga.Sdk/Client/Model/ClientReadAuthorizaionModelsOptions.cs index 257d847..7107986 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientReadAuthorizaionModelsOptions.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientReadAuthorizaionModelsOptions.cs @@ -16,11 +16,13 @@ namespace OpenFga.Sdk.Client.Model; /// /// ClientReadAuthorizationModelsOptions - Client Options for ReadAuthorizationModels /// -public interface IClientReadAuthorizationModelsOptions : ClientRequestOptions, ClientPaginationOptions { +public interface IClientReadAuthorizationModelsOptions : IClientRequestOptionsWithStoreId, ClientPaginationOptions { } /// public class ClientReadAuthorizationModelsOptions : IClientReadAuthorizationModelsOptions { + /// + public string? StoreId { get; set; } /// public int? PageSize { get; set; } diff --git a/src/OpenFga.Sdk/Client/Model/ClientReadChangesOptions.cs b/src/OpenFga.Sdk/Client/Model/ClientReadChangesOptions.cs index 47b4399..60ed887 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientReadChangesOptions.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientReadChangesOptions.cs @@ -16,11 +16,13 @@ namespace OpenFga.Sdk.Client.Model; /// /// ClientReadChangesOptions - Client Options for ReadChanges /// -public interface IClientReadChangesOptions : ClientRequestOptions, ClientPaginationOptions { +public interface IClientReadChangesOptions : IClientRequestOptionsWithStoreId, ClientPaginationOptions { } /// public class ClientReadChangesOptions : IClientReadChangesOptions { + /// + public string? StoreId { get; set; } /// public int? PageSize { get; set; } diff --git a/src/OpenFga.Sdk/Client/Model/ClientReadOptions.cs b/src/OpenFga.Sdk/Client/Model/ClientReadOptions.cs index bda3764..72f4068 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientReadOptions.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientReadOptions.cs @@ -16,11 +16,13 @@ namespace OpenFga.Sdk.Client.Model; /// /// ClientReadOptions - Client Options for Read /// -public interface IClientReadOptions : ClientRequestOptions, ClientPaginationOptions { +public interface IClientReadOptions : IClientRequestOptionsWithStoreId, ClientPaginationOptions { } /// public class ClientReadOptions : IClientReadOptions { + /// + public string? StoreId { get; set; } /// public int? PageSize { get; set; } diff --git a/src/OpenFga.Sdk/Client/Model/ClientReadRequest.cs b/src/OpenFga.Sdk/Client/Model/ClientReadRequest.cs index 1c9d45a..8d9a056 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientReadRequest.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientReadRequest.cs @@ -15,5 +15,5 @@ namespace OpenFga.Sdk.Client.Model; -public class ClientReadRequest : TupleKey { +public class ClientReadRequest : ReadRequestTupleKey { } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Client/Model/ClientRequestOptsWithAuthZModelId.cs b/src/OpenFga.Sdk/Client/Model/ClientRequestOptsWithAuthZModelId.cs index 7e53303..1976dd9 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientRequestOptsWithAuthZModelId.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientRequestOptsWithAuthZModelId.cs @@ -14,5 +14,5 @@ namespace OpenFga.Sdk.Client.Model; /// -public interface IClientRequestOptionsWithAuthZModelId : ClientRequestOptions, AuthorizationModelIdOptions { +public interface IClientRequestOptionsWithAuthZModelId : IClientRequestOptionsWithStoreId, AuthorizationModelIdOptions { } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Client/Model/ClientRequestOptsWithStoreId.cs b/src/OpenFga.Sdk/Client/Model/ClientRequestOptsWithStoreId.cs new file mode 100644 index 0000000..4b748ae --- /dev/null +++ b/src/OpenFga.Sdk/Client/Model/ClientRequestOptsWithStoreId.cs @@ -0,0 +1,18 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 0.1 +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://discord.gg/8naAwJfWN6 +// License: [Apache-2.0](https://github.com/openfga/dotnet-sdk/blob/main/LICENSE) +// +// NOTE: This file was auto generated. DO NOT EDIT. +// + + +namespace OpenFga.Sdk.Client.Model; + +/// +public interface IClientRequestOptionsWithStoreId : ClientRequestOptions, StoreIdOptions { +} \ No newline at end of file diff --git a/src/OpenFga.Sdk/Client/Model/ClientTupleKey.cs b/src/OpenFga.Sdk/Client/Model/ClientTupleKey.cs index 026a2d8..3fce6d3 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientTupleKey.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientTupleKey.cs @@ -19,23 +19,22 @@ namespace OpenFga.Sdk.Client.Model; -public interface IClientTupleKey { - public string User { get; set; } - public string Relation { get; set; } - public string Object { get; set; } +public interface IClientTupleKey : IClientTupleKeyWithoutCondition { + public RelationshipCondition? Condition { get; set; } } -public interface IClientContextualTuplesWrapper { +public interface IClientQueryContextWrapper { public List? ContextualTuples { get; set; } + public Object? Context { get; set; } } public class ClientTupleKey : IClientTupleKey { /// - /// Gets or Sets Object + /// Gets or Sets User /// - [DataMember(Name = "object", EmitDefaultValue = false)] - [JsonPropertyName("object")] - public new string Object { get; set; } + [DataMember(Name = "user", EmitDefaultValue = false)] + [JsonPropertyName("user")] + public new string User { get; set; } /// /// Gets or Sets Relation @@ -45,13 +44,23 @@ public class ClientTupleKey : IClientTupleKey { public new string Relation { get; set; } /// - /// Gets or Sets User + /// Gets or Sets Object /// - [DataMember(Name = "user", EmitDefaultValue = false)] - [JsonPropertyName("user")] - public new string User { get; set; } + [DataMember(Name = "object", EmitDefaultValue = false)] + [JsonPropertyName("object")] + public new string Object { get; set; } - public virtual TupleKey ToTupleKey() => new TupleKey { User = User, Relation = Relation, Object = Object }; + /// + /// Gets or Sets Condition + /// + [DataMember(Name = "condition", EmitDefaultValue = false)] + [JsonPropertyName("condition")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public RelationshipCondition? Condition { get; set; } + + public virtual TupleKey ToTupleKey() => new() { User = User, Relation = Relation, Object = Object, Condition = Condition }; + + public virtual TupleKeyWithoutCondition ToTupleKeyWithoutCondition() => new() { User = User, Relation = Relation, Object = Object }; public virtual string ToJson() => JsonSerializer.Serialize(this); @@ -67,9 +76,9 @@ public bool Equals(ClientTupleKey input) { return ( - Object == input.Object || - (Object != null && - Object.Equals(input.Object)) + User == input.User || + (User != null && + User.Equals(input.User)) ) && ( Relation == input.Relation || @@ -77,9 +86,14 @@ public bool Equals(ClientTupleKey input) { Relation.Equals(input.Relation)) ) && ( - User == input.User || - (User != null && - User.Equals(input.User)) + Object == input.Object || + (Object != null && + Object.Equals(input.Object)) + ) && + ( + Condition == input.Condition || + (Condition != null && + Condition.Equals(input.Condition)) ); } @@ -87,6 +101,11 @@ public override int GetHashCode() { unchecked // Overflow is fine, just wrap { var hashCode = 9661; + + if (User != null) { + hashCode = (hashCode * 9923) + User.GetHashCode(); + } + if (Object != null) { hashCode = (hashCode * 9923) + Object.GetHashCode(); } @@ -95,8 +114,8 @@ public override int GetHashCode() { hashCode = (hashCode * 9923) + Relation.GetHashCode(); } - if (User != null) { - hashCode = (hashCode * 9923) + User.GetHashCode(); + if (Condition != null) { + hashCode = (hashCode * 9923) + Condition.GetHashCode(); } return hashCode; diff --git a/src/OpenFga.Sdk/Client/Model/ClientTupleKeyWithoutCondition.cs b/src/OpenFga.Sdk/Client/Model/ClientTupleKeyWithoutCondition.cs new file mode 100644 index 0000000..9969e25 --- /dev/null +++ b/src/OpenFga.Sdk/Client/Model/ClientTupleKeyWithoutCondition.cs @@ -0,0 +1,108 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 0.1 +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://discord.gg/8naAwJfWN6 +// License: [Apache-2.0](https://github.com/openfga/dotnet-sdk/blob/main/LICENSE) +// +// NOTE: This file was auto generated. DO NOT EDIT. +// + + +using OpenFga.Sdk.Model; +using System.ComponentModel.DataAnnotations; +using System.Runtime.Serialization; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace OpenFga.Sdk.Client.Model; + +public interface IClientTupleKeyWithoutCondition { + public string User { get; set; } + public string Relation { get; set; } + public string Object { get; set; } +} + +public class ClientTupleKeyWithoutCondition : IClientTupleKeyWithoutCondition { + /// + /// Gets or Sets User + /// + [DataMember(Name = "user", EmitDefaultValue = false)] + [JsonPropertyName("user")] + public new string User { get; set; } + + /// + /// Gets or Sets Relation + /// + [DataMember(Name = "relation", EmitDefaultValue = false)] + [JsonPropertyName("relation")] + public new string Relation { get; set; } + + /// + /// Gets or Sets Object + /// + [DataMember(Name = "object", EmitDefaultValue = false)] + [JsonPropertyName("object")] + public new string Object { get; set; } + + public virtual TupleKey ToTupleKey() => new() { User = User, Relation = Relation, Object = Object }; + + public virtual TupleKeyWithoutCondition ToTupleKeyWithoutCondition() => new() { User = User, Relation = Relation, Object = Object }; + + public virtual string ToJson() => JsonSerializer.Serialize(this); + + public static ClientTupleKeyWithoutCondition FromJson(string jsonString) => + JsonSerializer.Deserialize(jsonString) ?? throw new InvalidOperationException(); + + public override bool Equals(object input) => Equals(input as ClientTupleKey); + + public bool Equals(ClientTupleKeyWithoutCondition input) { + if (input == null) { + return false; + } + + return + ( + User == input.User || + (User != null && + User.Equals(input.User)) + ) && + ( + Relation == input.Relation || + (Relation != null && + Relation.Equals(input.Relation)) + ) && + ( + Object == input.Object || + (Object != null && + Object.Equals(input.Object)) + ); + } + + public override int GetHashCode() { + unchecked // Overflow is fine, just wrap + { + var hashCode = 9661; + + if (User != null) { + hashCode = (hashCode * 9923) + User.GetHashCode(); + } + + if (Object != null) { + hashCode = (hashCode * 9923) + Object.GetHashCode(); + } + + if (Relation != null) { + hashCode = (hashCode * 9923) + Relation.GetHashCode(); + } + + return hashCode; + } + } + + public IEnumerable Validate(ValidationContext validationContext) { + yield break; + } +} \ No newline at end of file diff --git a/src/OpenFga.Sdk/Client/Model/ClientWriteAssertionsOptions.cs b/src/OpenFga.Sdk/Client/Model/ClientWriteAssertionsOptions.cs index 7f24335..f953c29 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientWriteAssertionsOptions.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientWriteAssertionsOptions.cs @@ -16,12 +16,15 @@ namespace OpenFga.Sdk.Client.Model; /// /// ClientReadAssertionsOptions - Client Options for ReadAssertions /// -public interface IClientWriteAssertionsOptions : ClientRequestOptions, AuthorizationModelIdOptions { +public interface IClientWriteAssertionsOptions : IClientRequestOptionsWithStoreId, AuthorizationModelIdOptions { } /// public class ClientWriteAssertionsOptions : IClientWriteAssertionsOptions { + /// + public string? StoreId { get; set; } + /// public string? AuthorizationModelId { get; set; } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Client/Model/ClientWriteOptions.cs b/src/OpenFga.Sdk/Client/Model/ClientWriteOptions.cs index 5eee642..c7f9e61 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientWriteOptions.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientWriteOptions.cs @@ -55,6 +55,9 @@ public interface IClientWriteOptions : IClientRequestOptionsWithAuthZModelId { } public class ClientWriteOptions : IClientWriteOptions { + /// + public string? StoreId { get; set; } + /// /// Override the Authorization Model ID for this request /// diff --git a/src/OpenFga.Sdk/Client/Model/ClientWriteRequest.cs b/src/OpenFga.Sdk/Client/Model/ClientWriteRequest.cs index fa11edc..0786293 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientWriteRequest.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientWriteRequest.cs @@ -21,7 +21,7 @@ namespace OpenFga.Sdk.Client.Model; internal interface IClientWriteRequest { public List? Writes { get; set; } - public List? Deletes { get; set; } + public List? Deletes { get; set; } } /// @@ -34,7 +34,7 @@ public class ClientWriteRequest : IClientWriteRequest, IEquatable /// writes. /// deletes. - public ClientWriteRequest(List? writes = default, List? deletes = default) { + public ClientWriteRequest(List? writes = default, List? deletes = default) { Writes = writes; Deletes = deletes; } @@ -51,7 +51,7 @@ public ClientWriteRequest(List? writes = default, List [DataMember(Name = "deletes", EmitDefaultValue = false)] [JsonPropertyName("deletes")] - public List? Deletes { get; set; } + public List? Deletes { get; set; } /// /// Returns true if WriteRequest instances are equal diff --git a/src/OpenFga.Sdk/Client/Model/StoreIdOptions.cs b/src/OpenFga.Sdk/Client/Model/StoreIdOptions.cs new file mode 100644 index 0000000..8037d49 --- /dev/null +++ b/src/OpenFga.Sdk/Client/Model/StoreIdOptions.cs @@ -0,0 +1,21 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 0.1 +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://discord.gg/8naAwJfWN6 +// License: [Apache-2.0](https://github.com/openfga/dotnet-sdk/blob/main/LICENSE) +// +// NOTE: This file was auto generated. DO NOT EDIT. +// + + +namespace OpenFga.Sdk.Client.Model; + +public interface StoreIdOptions { + /// + /// Overrides the StoreId in the ClientConfiguration + /// + string? StoreId { get; set; } +} \ No newline at end of file diff --git a/src/OpenFga.Sdk/Configuration/Configuration.cs b/src/OpenFga.Sdk/Configuration/Configuration.cs index 9a800fe..e01fc99 100644 --- a/src/OpenFga.Sdk/Configuration/Configuration.cs +++ b/src/OpenFga.Sdk/Configuration/Configuration.cs @@ -32,17 +32,13 @@ private static bool IsWellFormedUriString(string uri) { /// /// public void IsValid() { - if (string.IsNullOrWhiteSpace(ApiScheme)) { - throw new FgaRequiredParamError("Configuration", nameof(ApiScheme)); - } - - if (string.IsNullOrWhiteSpace(ApiHost)) { - throw new FgaRequiredParamError("Configuration", nameof(ApiHost)); + if (BasePath == null || BasePath == "") { + throw new FgaRequiredParamError("Configuration", "ApiUrl"); } if (!IsWellFormedUriString(BasePath)) { throw new FgaValidationError( - $"Configuration.ApiScheme ({ApiScheme}) and Configuration.ApiHost ({ApiHost}) do not form a valid URI ({BasePath})"); + $"Configuration.ApiUrl ({ApiUrl ?? BasePath}) does not form a valid URI ({BasePath})"); } if (MaxRetry > 15) { @@ -60,22 +56,14 @@ public void IsValid() { /// Version of the package. /// /// Version of the package. - public const string Version = "0.2.5"; + public const string Version = "0.3.0"; - private const string DefaultUserAgent = "openfga-sdk dotnet/0.2.5"; + private const string DefaultUserAgent = "openfga-sdk dotnet/0.3.0"; #endregion Constants #region Constructors - /// - /// Initializes a new instance of the class - /// - /// - public Configuration(string storeId) : this() { - StoreId = storeId; - } - /// /// Initializes a new instance of the class /// @@ -108,20 +96,41 @@ public Configuration() { /// Gets the Base Path. /// /// Base Path. - public string BasePath => $"{ApiScheme}://{ApiHost}"; + public string BasePath { + get { + if (ApiUrl != null && ApiUrl != "") { + return ApiUrl; + } + + if (ApiHost != null && ApiUrl != "") { + return $"{ApiScheme ?? "https"}://{ApiHost}"; + } + + return ""; + } + } + /// /// Gets or sets the API Scheme. /// /// ApiScheme. + [Obsolete("ApiScheme is deprecated, please use ApiUrl instead.")] public string ApiScheme { get; set; } = "https"; /// /// Gets or sets the API Host. /// /// ApiHost. + [Obsolete("ApiHost is deprecated, please use ApiUrl instead.")] public string ApiHost { get; set; } + /// + /// Gets or sets the API URL. + /// + /// ApiUrl. + public string ApiUrl { get; set; } + /// /// Gets or sets the Store ID. /// diff --git a/src/OpenFga.Sdk/Model/AbortedMessageResponse.cs b/src/OpenFga.Sdk/Model/AbortedMessageResponse.cs new file mode 100644 index 0000000..9ac2529 --- /dev/null +++ b/src/OpenFga.Sdk/Model/AbortedMessageResponse.cs @@ -0,0 +1,147 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 0.1 +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://discord.gg/8naAwJfWN6 +// License: [Apache-2.0](https://github.com/openfga/dotnet-sdk/blob/main/LICENSE) +// +// NOTE: This file was auto generated. DO NOT EDIT. +// + + +using System.ComponentModel.DataAnnotations; +using System.Runtime.Serialization; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace OpenFga.Sdk.Model { + /// + /// AbortedMessageResponse + /// + [DataContract(Name = "AbortedMessageResponse")] + public partial class AbortedMessageResponse : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public AbortedMessageResponse() { + this.AdditionalProperties = new Dictionary(); + } + + /// + /// Initializes a new instance of the class. + /// + /// code. + /// message. + public AbortedMessageResponse(string code = default(string), string message = default(string)) { + this.Code = code; + this.Message = message; + this.AdditionalProperties = new Dictionary(); + } + + /// + /// Gets or Sets Code + /// + [DataMember(Name = "code", EmitDefaultValue = false)] + [JsonPropertyName("code")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string? Code { get; set; } + + /// + /// Gets or Sets Message + /// + [DataMember(Name = "message", EmitDefaultValue = false)] + [JsonPropertyName("message")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string? Message { get; set; } + + /// + /// Gets or Sets additional properties + /// + [JsonExtensionData] + public IDictionary AdditionalProperties { get; set; } + + + /// + /// Returns the JSON string presentation of the object + /// + /// JSON string presentation of the object + public virtual string ToJson() { + return JsonSerializer.Serialize(this); + } + + /// + /// Builds a AbortedMessageResponse from the JSON string presentation of the object + /// + /// AbortedMessageResponse + public static AbortedMessageResponse FromJson(string jsonString) { + return JsonSerializer.Deserialize(jsonString) ?? throw new InvalidOperationException(); + } + + /// + /// Returns true if objects are equal + /// + /// Object to be compared + /// Boolean + public override bool Equals(object input) { + return this.Equals(input as AbortedMessageResponse); + } + + /// + /// Returns true if AbortedMessageResponse instances are equal + /// + /// Instance of AbortedMessageResponse to be compared + /// Boolean + public bool Equals(AbortedMessageResponse input) { + if (input == null) { + return false; + } + return + ( + this.Code == input.Code || + (this.Code != null && + this.Code.Equals(input.Code)) + ) && + ( + this.Message == input.Message || + (this.Message != null && + this.Message.Equals(input.Message)) + ) + && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + } + + /// + /// Gets the hash code + /// + /// Hash code + public override int GetHashCode() { + unchecked // Overflow is fine, just wrap + { + int hashCode = 9661; + if (this.Code != null) { + hashCode = (hashCode * 9923) + this.Code.GetHashCode(); + } + if (this.Message != null) { + hashCode = (hashCode * 9923) + this.Message.GetHashCode(); + } + if (this.AdditionalProperties != null) { + hashCode = (hashCode * 9923) + this.AdditionalProperties.GetHashCode(); + } + return hashCode; + } + } + + /// + /// To validate all properties of the instance + /// + /// Validation context + /// Validation Result + public IEnumerable Validate(ValidationContext validationContext) { + yield break; + } + + } + +} \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/Assertion.cs b/src/OpenFga.Sdk/Model/Assertion.cs index 7eeb084..6bbe723 100644 --- a/src/OpenFga.Sdk/Model/Assertion.cs +++ b/src/OpenFga.Sdk/Model/Assertion.cs @@ -35,7 +35,7 @@ public Assertion() { /// /// tupleKey (required). /// expectation (required). - public Assertion(TupleKey tupleKey = default(TupleKey), bool expectation = default(bool)) { + public Assertion(AssertionTupleKey tupleKey = default(AssertionTupleKey), bool expectation = default(bool)) { // to ensure "tupleKey" is required (not null) if (tupleKey == null) { throw new ArgumentNullException("tupleKey is a required property for Assertion and cannot be null"); @@ -51,7 +51,7 @@ public Assertion() { [DataMember(Name = "tuple_key", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("tuple_key")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public TupleKey TupleKey { get; set; } + public AssertionTupleKey TupleKey { get; set; } /// /// Gets or Sets Expectation diff --git a/src/OpenFga.Sdk/Model/AssertionTupleKey.cs b/src/OpenFga.Sdk/Model/AssertionTupleKey.cs new file mode 100644 index 0000000..303308f --- /dev/null +++ b/src/OpenFga.Sdk/Model/AssertionTupleKey.cs @@ -0,0 +1,192 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 0.1 +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://discord.gg/8naAwJfWN6 +// License: [Apache-2.0](https://github.com/openfga/dotnet-sdk/blob/main/LICENSE) +// +// NOTE: This file was auto generated. DO NOT EDIT. +// + + +using System.ComponentModel.DataAnnotations; +using System.Runtime.Serialization; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace OpenFga.Sdk.Model { + /// + /// AssertionTupleKey + /// + [DataContract(Name = "AssertionTupleKey")] + public partial class AssertionTupleKey : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public AssertionTupleKey() { + this.AdditionalProperties = new Dictionary(); + } + + /// + /// Initializes a new instance of the class. + /// + /// _object (required). + /// relation (required). + /// user (required). + public AssertionTupleKey(string _object = default(string), string relation = default(string), string user = default(string)) { + // to ensure "_object" is required (not null) + if (_object == null) { + throw new ArgumentNullException("_object is a required property for AssertionTupleKey and cannot be null"); + } + this.Object = _object; + // to ensure "relation" is required (not null) + if (relation == null) { + throw new ArgumentNullException("relation is a required property for AssertionTupleKey and cannot be null"); + } + this.Relation = relation; + // to ensure "user" is required (not null) + if (user == null) { + throw new ArgumentNullException("user is a required property for AssertionTupleKey and cannot be null"); + } + this.User = user; + this.AdditionalProperties = new Dictionary(); + } + + /// + /// Gets or Sets Object + /// + [DataMember(Name = "object", IsRequired = true, EmitDefaultValue = false)] + [JsonPropertyName("object")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string Object { get; set; } + + /// + /// Gets or Sets Relation + /// + [DataMember(Name = "relation", IsRequired = true, EmitDefaultValue = false)] + [JsonPropertyName("relation")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string Relation { get; set; } + + /// + /// Gets or Sets User + /// + [DataMember(Name = "user", IsRequired = true, EmitDefaultValue = false)] + [JsonPropertyName("user")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string User { get; set; } + + /// + /// Gets or Sets additional properties + /// + [JsonExtensionData] + public IDictionary AdditionalProperties { get; set; } + + + /// + /// Returns the JSON string presentation of the object + /// + /// JSON string presentation of the object + public virtual string ToJson() { + return JsonSerializer.Serialize(this); + } + + /// + /// Builds a AssertionTupleKey from the JSON string presentation of the object + /// + /// AssertionTupleKey + public static AssertionTupleKey FromJson(string jsonString) { + return JsonSerializer.Deserialize(jsonString) ?? throw new InvalidOperationException(); + } + + /// + /// Returns true if objects are equal + /// + /// Object to be compared + /// Boolean + public override bool Equals(object input) { + return this.Equals(input as AssertionTupleKey); + } + + /// + /// Returns true if AssertionTupleKey instances are equal + /// + /// Instance of AssertionTupleKey to be compared + /// Boolean + public bool Equals(AssertionTupleKey input) { + if (input == null) { + return false; + } + return + ( + this.Object == input.Object || + (this.Object != null && + this.Object.Equals(input.Object)) + ) && + ( + this.Relation == input.Relation || + (this.Relation != null && + this.Relation.Equals(input.Relation)) + ) && + ( + this.User == input.User || + (this.User != null && + this.User.Equals(input.User)) + ) + && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + } + + /// + /// Gets the hash code + /// + /// Hash code + public override int GetHashCode() { + unchecked // Overflow is fine, just wrap + { + int hashCode = 9661; + if (this.Object != null) { + hashCode = (hashCode * 9923) + this.Object.GetHashCode(); + } + if (this.Relation != null) { + hashCode = (hashCode * 9923) + this.Relation.GetHashCode(); + } + if (this.User != null) { + hashCode = (hashCode * 9923) + this.User.GetHashCode(); + } + if (this.AdditionalProperties != null) { + hashCode = (hashCode * 9923) + this.AdditionalProperties.GetHashCode(); + } + return hashCode; + } + } + + /// + /// To validate all properties of the instance + /// + /// Validation context + /// Validation Result + public IEnumerable Validate(ValidationContext validationContext) { + // Object (string) maxLength + if (this.Object != null && this.Object.Length > 256) { + yield return new ValidationResult("Invalid value for Object, length must be less than 256.", new[] { "Object" }); + } + + // Relation (string) maxLength + if (this.Relation != null && this.Relation.Length > 50) { + yield return new ValidationResult("Invalid value for Relation, length must be less than 50.", new[] { "Relation" }); + } + + // User (string) maxLength + if (this.User != null && this.User.Length > 512) { + yield return new ValidationResult("Invalid value for User, length must be less than 512.", new[] { "User" }); + } + + yield break; + } + + } + +} \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/AuthorizationModel.cs b/src/OpenFga.Sdk/Model/AuthorizationModel.cs index f22d7b6..16b7c9e 100644 --- a/src/OpenFga.Sdk/Model/AuthorizationModel.cs +++ b/src/OpenFga.Sdk/Model/AuthorizationModel.cs @@ -33,27 +33,37 @@ public AuthorizationModel() { /// /// Initializes a new instance of the class. /// - /// id. + /// id (required). /// schemaVersion (required). - /// typeDefinitions. - public AuthorizationModel(string id = default(string), string schemaVersion = default(string), List typeDefinitions = default(List)) { + /// typeDefinitions (required). + /// conditions. + public AuthorizationModel(string id = default(string), string schemaVersion = default(string), List typeDefinitions = default(List), Dictionary conditions = default(Dictionary)) { + // to ensure "id" is required (not null) + if (id == null) { + throw new ArgumentNullException("id is a required property for AuthorizationModel and cannot be null"); + } + this.Id = id; // to ensure "schemaVersion" is required (not null) if (schemaVersion == null) { throw new ArgumentNullException("schemaVersion is a required property for AuthorizationModel and cannot be null"); } this.SchemaVersion = schemaVersion; - this.Id = id; + // to ensure "typeDefinitions" is required (not null) + if (typeDefinitions == null) { + throw new ArgumentNullException("typeDefinitions is a required property for AuthorizationModel and cannot be null"); + } this.TypeDefinitions = typeDefinitions; + this.Conditions = conditions; this.AdditionalProperties = new Dictionary(); } /// /// Gets or Sets Id /// - [DataMember(Name = "id", EmitDefaultValue = false)] + [DataMember(Name = "id", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("id")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public string? Id { get; set; } + public string Id { get; set; } /// /// Gets or Sets SchemaVersion @@ -66,10 +76,18 @@ public AuthorizationModel() { /// /// Gets or Sets TypeDefinitions /// - [DataMember(Name = "type_definitions", EmitDefaultValue = false)] + [DataMember(Name = "type_definitions", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("type_definitions")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public List? TypeDefinitions { get; set; } + public List TypeDefinitions { get; set; } + + /// + /// Gets or Sets Conditions + /// + [DataMember(Name = "conditions", EmitDefaultValue = false)] + [JsonPropertyName("conditions")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public Dictionary? Conditions { get; set; } /// /// Gets or Sets additional properties @@ -128,6 +146,12 @@ public bool Equals(AuthorizationModel input) { this.TypeDefinitions != null && input.TypeDefinitions != null && this.TypeDefinitions.SequenceEqual(input.TypeDefinitions) + ) && + ( + this.Conditions == input.Conditions || + this.Conditions != null && + input.Conditions != null && + this.Conditions.SequenceEqual(input.Conditions) ) && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); } @@ -149,6 +173,9 @@ public override int GetHashCode() { if (this.TypeDefinitions != null) { hashCode = (hashCode * 9923) + this.TypeDefinitions.GetHashCode(); } + if (this.Conditions != null) { + hashCode = (hashCode * 9923) + this.Conditions.GetHashCode(); + } if (this.AdditionalProperties != null) { hashCode = (hashCode * 9923) + this.AdditionalProperties.GetHashCode(); } diff --git a/src/OpenFga.Sdk/Model/CheckRequest.cs b/src/OpenFga.Sdk/Model/CheckRequest.cs index 3e8c526..a1aabed 100644 --- a/src/OpenFga.Sdk/Model/CheckRequest.cs +++ b/src/OpenFga.Sdk/Model/CheckRequest.cs @@ -36,7 +36,8 @@ public CheckRequest() { /// tupleKey (required). /// contextualTuples. /// authorizationModelId. - public CheckRequest(TupleKey tupleKey = default(TupleKey), ContextualTupleKeys contextualTuples = default(ContextualTupleKeys), string authorizationModelId = default(string)) { + /// Additional request context that will be used to evaluate any ABAC conditions encountered in the query evaluation.. + public CheckRequest(CheckRequestTupleKey tupleKey = default(CheckRequestTupleKey), ContextualTupleKeys contextualTuples = default(ContextualTupleKeys), string authorizationModelId = default(string), Object context = default(Object)) { // to ensure "tupleKey" is required (not null) if (tupleKey == null) { throw new ArgumentNullException("tupleKey is a required property for CheckRequest and cannot be null"); @@ -44,6 +45,7 @@ public CheckRequest() { this.TupleKey = tupleKey; this.ContextualTuples = contextualTuples; this.AuthorizationModelId = authorizationModelId; + this.Context = context; this.AdditionalProperties = new Dictionary(); } @@ -53,7 +55,7 @@ public CheckRequest() { [DataMember(Name = "tuple_key", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("tuple_key")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public TupleKey TupleKey { get; set; } + public CheckRequestTupleKey TupleKey { get; set; } /// /// Gets or Sets ContextualTuples @@ -87,6 +89,15 @@ public CheckRequest() { public bool ShouldSerializeTrace() { return false; } + /// + /// Additional request context that will be used to evaluate any ABAC conditions encountered in the query evaluation. + /// + /// Additional request context that will be used to evaluate any ABAC conditions encountered in the query evaluation. + [DataMember(Name = "context", EmitDefaultValue = false)] + [JsonPropertyName("context")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public Object? Context { get; set; } + /// /// Gets or Sets additional properties /// @@ -147,6 +158,11 @@ public bool Equals(CheckRequest input) { ( this.Trace == input.Trace || this.Trace.Equals(input.Trace) + ) && + ( + this.Context == input.Context || + (this.Context != null && + this.Context.Equals(input.Context)) ) && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); } @@ -169,6 +185,9 @@ public override int GetHashCode() { hashCode = (hashCode * 9923) + this.AuthorizationModelId.GetHashCode(); } hashCode = (hashCode * 9923) + this.Trace.GetHashCode(); + if (this.Context != null) { + hashCode = (hashCode * 9923) + this.Context.GetHashCode(); + } if (this.AdditionalProperties != null) { hashCode = (hashCode * 9923) + this.AdditionalProperties.GetHashCode(); } diff --git a/src/OpenFga.Sdk/Model/CheckRequestTupleKey.cs b/src/OpenFga.Sdk/Model/CheckRequestTupleKey.cs new file mode 100644 index 0000000..00b2069 --- /dev/null +++ b/src/OpenFga.Sdk/Model/CheckRequestTupleKey.cs @@ -0,0 +1,192 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 0.1 +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://discord.gg/8naAwJfWN6 +// License: [Apache-2.0](https://github.com/openfga/dotnet-sdk/blob/main/LICENSE) +// +// NOTE: This file was auto generated. DO NOT EDIT. +// + + +using System.ComponentModel.DataAnnotations; +using System.Runtime.Serialization; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace OpenFga.Sdk.Model { + /// + /// CheckRequestTupleKey + /// + [DataContract(Name = "CheckRequestTupleKey")] + public partial class CheckRequestTupleKey : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public CheckRequestTupleKey() { + this.AdditionalProperties = new Dictionary(); + } + + /// + /// Initializes a new instance of the class. + /// + /// user (required). + /// relation (required). + /// _object (required). + public CheckRequestTupleKey(string user = default(string), string relation = default(string), string _object = default(string)) { + // to ensure "user" is required (not null) + if (user == null) { + throw new ArgumentNullException("user is a required property for CheckRequestTupleKey and cannot be null"); + } + this.User = user; + // to ensure "relation" is required (not null) + if (relation == null) { + throw new ArgumentNullException("relation is a required property for CheckRequestTupleKey and cannot be null"); + } + this.Relation = relation; + // to ensure "_object" is required (not null) + if (_object == null) { + throw new ArgumentNullException("_object is a required property for CheckRequestTupleKey and cannot be null"); + } + this.Object = _object; + this.AdditionalProperties = new Dictionary(); + } + + /// + /// Gets or Sets User + /// + [DataMember(Name = "user", IsRequired = true, EmitDefaultValue = false)] + [JsonPropertyName("user")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string User { get; set; } + + /// + /// Gets or Sets Relation + /// + [DataMember(Name = "relation", IsRequired = true, EmitDefaultValue = false)] + [JsonPropertyName("relation")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string Relation { get; set; } + + /// + /// Gets or Sets Object + /// + [DataMember(Name = "object", IsRequired = true, EmitDefaultValue = false)] + [JsonPropertyName("object")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string Object { get; set; } + + /// + /// Gets or Sets additional properties + /// + [JsonExtensionData] + public IDictionary AdditionalProperties { get; set; } + + + /// + /// Returns the JSON string presentation of the object + /// + /// JSON string presentation of the object + public virtual string ToJson() { + return JsonSerializer.Serialize(this); + } + + /// + /// Builds a CheckRequestTupleKey from the JSON string presentation of the object + /// + /// CheckRequestTupleKey + public static CheckRequestTupleKey FromJson(string jsonString) { + return JsonSerializer.Deserialize(jsonString) ?? throw new InvalidOperationException(); + } + + /// + /// Returns true if objects are equal + /// + /// Object to be compared + /// Boolean + public override bool Equals(object input) { + return this.Equals(input as CheckRequestTupleKey); + } + + /// + /// Returns true if CheckRequestTupleKey instances are equal + /// + /// Instance of CheckRequestTupleKey to be compared + /// Boolean + public bool Equals(CheckRequestTupleKey input) { + if (input == null) { + return false; + } + return + ( + this.User == input.User || + (this.User != null && + this.User.Equals(input.User)) + ) && + ( + this.Relation == input.Relation || + (this.Relation != null && + this.Relation.Equals(input.Relation)) + ) && + ( + this.Object == input.Object || + (this.Object != null && + this.Object.Equals(input.Object)) + ) + && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + } + + /// + /// Gets the hash code + /// + /// Hash code + public override int GetHashCode() { + unchecked // Overflow is fine, just wrap + { + int hashCode = 9661; + if (this.User != null) { + hashCode = (hashCode * 9923) + this.User.GetHashCode(); + } + if (this.Relation != null) { + hashCode = (hashCode * 9923) + this.Relation.GetHashCode(); + } + if (this.Object != null) { + hashCode = (hashCode * 9923) + this.Object.GetHashCode(); + } + if (this.AdditionalProperties != null) { + hashCode = (hashCode * 9923) + this.AdditionalProperties.GetHashCode(); + } + return hashCode; + } + } + + /// + /// To validate all properties of the instance + /// + /// Validation context + /// Validation Result + public IEnumerable Validate(ValidationContext validationContext) { + // User (string) maxLength + if (this.User != null && this.User.Length > 512) { + yield return new ValidationResult("Invalid value for User, length must be less than 512.", new[] { "User" }); + } + + // Relation (string) maxLength + if (this.Relation != null && this.Relation.Length > 50) { + yield return new ValidationResult("Invalid value for Relation, length must be less than 50.", new[] { "Relation" }); + } + + // Object (string) maxLength + if (this.Object != null && this.Object.Length > 256) { + yield return new ValidationResult("Invalid value for Object, length must be less than 256.", new[] { "Object" }); + } + + yield break; + } + + } + +} \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/Computed.cs b/src/OpenFga.Sdk/Model/Computed.cs index b9da040..22ba90c 100644 --- a/src/OpenFga.Sdk/Model/Computed.cs +++ b/src/OpenFga.Sdk/Model/Computed.cs @@ -33,8 +33,12 @@ public Computed() { /// /// Initializes a new instance of the class. /// - /// userset. + /// userset (required). public Computed(string userset = default(string)) { + // to ensure "userset" is required (not null) + if (userset == null) { + throw new ArgumentNullException("userset is a required property for Computed and cannot be null"); + } this.Userset = userset; this.AdditionalProperties = new Dictionary(); } @@ -42,10 +46,10 @@ public Computed() { /// /// Gets or Sets Userset /// - [DataMember(Name = "userset", EmitDefaultValue = false)] + [DataMember(Name = "userset", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("userset")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public string? Userset { get; set; } + public string Userset { get; set; } /// /// Gets or Sets additional properties diff --git a/src/OpenFga.Sdk/Model/Condition.cs b/src/OpenFga.Sdk/Model/Condition.cs new file mode 100644 index 0000000..d39766a --- /dev/null +++ b/src/OpenFga.Sdk/Model/Condition.cs @@ -0,0 +1,176 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 0.1 +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://discord.gg/8naAwJfWN6 +// License: [Apache-2.0](https://github.com/openfga/dotnet-sdk/blob/main/LICENSE) +// +// NOTE: This file was auto generated. DO NOT EDIT. +// + + +using System.ComponentModel.DataAnnotations; +using System.Runtime.Serialization; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace OpenFga.Sdk.Model { + /// + /// Condition + /// + [DataContract(Name = "Condition")] + public partial class Condition : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public Condition() { + this.AdditionalProperties = new Dictionary(); + } + + /// + /// Initializes a new instance of the class. + /// + /// name (required). + /// A Google CEL expression, expressed as a string. (required). + /// A map of parameter names to the parameter's defined type reference.. + public Condition(string name = default(string), string expression = default(string), Dictionary parameters = default(Dictionary)) { + // to ensure "name" is required (not null) + if (name == null) { + throw new ArgumentNullException("name is a required property for Condition and cannot be null"); + } + this.Name = name; + // to ensure "expression" is required (not null) + if (expression == null) { + throw new ArgumentNullException("expression is a required property for Condition and cannot be null"); + } + this.Expression = expression; + this.Parameters = parameters; + this.AdditionalProperties = new Dictionary(); + } + + /// + /// Gets or Sets Name + /// + [DataMember(Name = "name", IsRequired = true, EmitDefaultValue = false)] + [JsonPropertyName("name")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string Name { get; set; } + + /// + /// A Google CEL expression, expressed as a string. + /// + /// A Google CEL expression, expressed as a string. + [DataMember(Name = "expression", IsRequired = true, EmitDefaultValue = false)] + [JsonPropertyName("expression")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string Expression { get; set; } + + /// + /// A map of parameter names to the parameter's defined type reference. + /// + /// A map of parameter names to the parameter's defined type reference. + [DataMember(Name = "parameters", EmitDefaultValue = false)] + [JsonPropertyName("parameters")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public Dictionary? Parameters { get; set; } + + /// + /// Gets or Sets additional properties + /// + [JsonExtensionData] + public IDictionary AdditionalProperties { get; set; } + + + /// + /// Returns the JSON string presentation of the object + /// + /// JSON string presentation of the object + public virtual string ToJson() { + return JsonSerializer.Serialize(this); + } + + /// + /// Builds a Condition from the JSON string presentation of the object + /// + /// Condition + public static Condition FromJson(string jsonString) { + return JsonSerializer.Deserialize(jsonString) ?? throw new InvalidOperationException(); + } + + /// + /// Returns true if objects are equal + /// + /// Object to be compared + /// Boolean + public override bool Equals(object input) { + return this.Equals(input as Condition); + } + + /// + /// Returns true if Condition instances are equal + /// + /// Instance of Condition to be compared + /// Boolean + public bool Equals(Condition input) { + if (input == null) { + return false; + } + return + ( + this.Name == input.Name || + (this.Name != null && + this.Name.Equals(input.Name)) + ) && + ( + this.Expression == input.Expression || + (this.Expression != null && + this.Expression.Equals(input.Expression)) + ) && + ( + this.Parameters == input.Parameters || + this.Parameters != null && + input.Parameters != null && + this.Parameters.SequenceEqual(input.Parameters) + ) + && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + } + + /// + /// Gets the hash code + /// + /// Hash code + public override int GetHashCode() { + unchecked // Overflow is fine, just wrap + { + int hashCode = 9661; + if (this.Name != null) { + hashCode = (hashCode * 9923) + this.Name.GetHashCode(); + } + if (this.Expression != null) { + hashCode = (hashCode * 9923) + this.Expression.GetHashCode(); + } + if (this.Parameters != null) { + hashCode = (hashCode * 9923) + this.Parameters.GetHashCode(); + } + if (this.AdditionalProperties != null) { + hashCode = (hashCode * 9923) + this.AdditionalProperties.GetHashCode(); + } + return hashCode; + } + } + + /// + /// To validate all properties of the instance + /// + /// Validation context + /// Validation Result + public IEnumerable Validate(ValidationContext validationContext) { + yield break; + } + + } + +} \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/ConditionParamTypeRef.cs b/src/OpenFga.Sdk/Model/ConditionParamTypeRef.cs new file mode 100644 index 0000000..09b30ac --- /dev/null +++ b/src/OpenFga.Sdk/Model/ConditionParamTypeRef.cs @@ -0,0 +1,144 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 0.1 +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://discord.gg/8naAwJfWN6 +// License: [Apache-2.0](https://github.com/openfga/dotnet-sdk/blob/main/LICENSE) +// +// NOTE: This file was auto generated. DO NOT EDIT. +// + + +using System.ComponentModel.DataAnnotations; +using System.Runtime.Serialization; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace OpenFga.Sdk.Model { + /// + /// ConditionParamTypeRef + /// + [DataContract(Name = "ConditionParamTypeRef")] + public partial class ConditionParamTypeRef : IEquatable, IValidatableObject { + + /// + /// Gets or Sets TypeName + /// + [DataMember(Name = "type_name", IsRequired = true, EmitDefaultValue = false)] + [JsonPropertyName("type_name")] + public TypeName TypeName { get; set; } + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public ConditionParamTypeRef() { + this.AdditionalProperties = new Dictionary(); + } + + /// + /// Initializes a new instance of the class. + /// + /// typeName (required). + /// genericTypes. + public ConditionParamTypeRef(TypeName typeName = default(TypeName), List genericTypes = default(List)) { + this.TypeName = typeName; + this.GenericTypes = genericTypes; + this.AdditionalProperties = new Dictionary(); + } + + /// + /// Gets or Sets GenericTypes + /// + [DataMember(Name = "generic_types", EmitDefaultValue = false)] + [JsonPropertyName("generic_types")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public List? GenericTypes { get; set; } + + /// + /// Gets or Sets additional properties + /// + [JsonExtensionData] + public IDictionary AdditionalProperties { get; set; } + + + /// + /// Returns the JSON string presentation of the object + /// + /// JSON string presentation of the object + public virtual string ToJson() { + return JsonSerializer.Serialize(this); + } + + /// + /// Builds a ConditionParamTypeRef from the JSON string presentation of the object + /// + /// ConditionParamTypeRef + public static ConditionParamTypeRef FromJson(string jsonString) { + return JsonSerializer.Deserialize(jsonString) ?? throw new InvalidOperationException(); + } + + /// + /// Returns true if objects are equal + /// + /// Object to be compared + /// Boolean + public override bool Equals(object input) { + return this.Equals(input as ConditionParamTypeRef); + } + + /// + /// Returns true if ConditionParamTypeRef instances are equal + /// + /// Instance of ConditionParamTypeRef to be compared + /// Boolean + public bool Equals(ConditionParamTypeRef input) { + if (input == null) { + return false; + } + return + ( + this.TypeName == input.TypeName || + this.TypeName.Equals(input.TypeName) + ) && + ( + this.GenericTypes == input.GenericTypes || + this.GenericTypes != null && + input.GenericTypes != null && + this.GenericTypes.SequenceEqual(input.GenericTypes) + ) + && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + } + + /// + /// Gets the hash code + /// + /// Hash code + public override int GetHashCode() { + unchecked // Overflow is fine, just wrap + { + int hashCode = 9661; + hashCode = (hashCode * 9923) + this.TypeName.GetHashCode(); + if (this.GenericTypes != null) { + hashCode = (hashCode * 9923) + this.GenericTypes.GetHashCode(); + } + if (this.AdditionalProperties != null) { + hashCode = (hashCode * 9923) + this.AdditionalProperties.GetHashCode(); + } + return hashCode; + } + } + + /// + /// To validate all properties of the instance + /// + /// Validation context + /// Validation Result + public IEnumerable Validate(ValidationContext validationContext) { + yield break; + } + + } + +} \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/CreateStoreResponse.cs b/src/OpenFga.Sdk/Model/CreateStoreResponse.cs index 0aac8b2..d6204c6 100644 --- a/src/OpenFga.Sdk/Model/CreateStoreResponse.cs +++ b/src/OpenFga.Sdk/Model/CreateStoreResponse.cs @@ -33,12 +33,20 @@ public CreateStoreResponse() { /// /// Initializes a new instance of the class. /// - /// id. - /// name. - /// createdAt. - /// updatedAt. + /// id (required). + /// name (required). + /// createdAt (required). + /// updatedAt (required). public CreateStoreResponse(string id = default(string), string name = default(string), DateTime createdAt = default(DateTime), DateTime updatedAt = default(DateTime)) { + // to ensure "id" is required (not null) + if (id == null) { + throw new ArgumentNullException("id is a required property for CreateStoreResponse and cannot be null"); + } this.Id = id; + // to ensure "name" is required (not null) + if (name == null) { + throw new ArgumentNullException("name is a required property for CreateStoreResponse and cannot be null"); + } this.Name = name; this.CreatedAt = createdAt; this.UpdatedAt = updatedAt; @@ -48,34 +56,34 @@ public CreateStoreResponse() { /// /// Gets or Sets Id /// - [DataMember(Name = "id", EmitDefaultValue = false)] + [DataMember(Name = "id", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("id")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public string? Id { get; set; } + public string Id { get; set; } /// /// Gets or Sets Name /// - [DataMember(Name = "name", EmitDefaultValue = false)] + [DataMember(Name = "name", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("name")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public string? Name { get; set; } + public string Name { get; set; } /// /// Gets or Sets CreatedAt /// - [DataMember(Name = "created_at", EmitDefaultValue = false)] + [DataMember(Name = "created_at", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("created_at")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public DateTime? CreatedAt { get; set; } + public DateTime CreatedAt { get; set; } /// /// Gets or Sets UpdatedAt /// - [DataMember(Name = "updated_at", EmitDefaultValue = false)] + [DataMember(Name = "updated_at", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("updated_at")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public DateTime? UpdatedAt { get; set; } + public DateTime UpdatedAt { get; set; } /// /// Gets or Sets additional properties diff --git a/src/OpenFga.Sdk/Model/ExpandRequest.cs b/src/OpenFga.Sdk/Model/ExpandRequest.cs index 059ed1a..abf9ffd 100644 --- a/src/OpenFga.Sdk/Model/ExpandRequest.cs +++ b/src/OpenFga.Sdk/Model/ExpandRequest.cs @@ -35,7 +35,7 @@ public ExpandRequest() { /// /// tupleKey (required). /// authorizationModelId. - public ExpandRequest(TupleKey tupleKey = default(TupleKey), string authorizationModelId = default(string)) { + public ExpandRequest(ExpandRequestTupleKey tupleKey = default(ExpandRequestTupleKey), string authorizationModelId = default(string)) { // to ensure "tupleKey" is required (not null) if (tupleKey == null) { throw new ArgumentNullException("tupleKey is a required property for ExpandRequest and cannot be null"); @@ -51,7 +51,7 @@ public ExpandRequest() { [DataMember(Name = "tuple_key", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("tuple_key")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public TupleKey TupleKey { get; set; } + public ExpandRequestTupleKey TupleKey { get; set; } /// /// Gets or Sets AuthorizationModelId diff --git a/src/OpenFga.Sdk/Model/ExpandRequestTupleKey.cs b/src/OpenFga.Sdk/Model/ExpandRequestTupleKey.cs new file mode 100644 index 0000000..6a93f9f --- /dev/null +++ b/src/OpenFga.Sdk/Model/ExpandRequestTupleKey.cs @@ -0,0 +1,165 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 0.1 +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://discord.gg/8naAwJfWN6 +// License: [Apache-2.0](https://github.com/openfga/dotnet-sdk/blob/main/LICENSE) +// +// NOTE: This file was auto generated. DO NOT EDIT. +// + + +using System.ComponentModel.DataAnnotations; +using System.Runtime.Serialization; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace OpenFga.Sdk.Model { + /// + /// ExpandRequestTupleKey + /// + [DataContract(Name = "ExpandRequestTupleKey")] + public partial class ExpandRequestTupleKey : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public ExpandRequestTupleKey() { + this.AdditionalProperties = new Dictionary(); + } + + /// + /// Initializes a new instance of the class. + /// + /// relation (required). + /// _object (required). + public ExpandRequestTupleKey(string relation = default(string), string _object = default(string)) { + // to ensure "relation" is required (not null) + if (relation == null) { + throw new ArgumentNullException("relation is a required property for ExpandRequestTupleKey and cannot be null"); + } + this.Relation = relation; + // to ensure "_object" is required (not null) + if (_object == null) { + throw new ArgumentNullException("_object is a required property for ExpandRequestTupleKey and cannot be null"); + } + this.Object = _object; + this.AdditionalProperties = new Dictionary(); + } + + /// + /// Gets or Sets Relation + /// + [DataMember(Name = "relation", IsRequired = true, EmitDefaultValue = false)] + [JsonPropertyName("relation")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string Relation { get; set; } + + /// + /// Gets or Sets Object + /// + [DataMember(Name = "object", IsRequired = true, EmitDefaultValue = false)] + [JsonPropertyName("object")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string Object { get; set; } + + /// + /// Gets or Sets additional properties + /// + [JsonExtensionData] + public IDictionary AdditionalProperties { get; set; } + + + /// + /// Returns the JSON string presentation of the object + /// + /// JSON string presentation of the object + public virtual string ToJson() { + return JsonSerializer.Serialize(this); + } + + /// + /// Builds a ExpandRequestTupleKey from the JSON string presentation of the object + /// + /// ExpandRequestTupleKey + public static ExpandRequestTupleKey FromJson(string jsonString) { + return JsonSerializer.Deserialize(jsonString) ?? throw new InvalidOperationException(); + } + + /// + /// Returns true if objects are equal + /// + /// Object to be compared + /// Boolean + public override bool Equals(object input) { + return this.Equals(input as ExpandRequestTupleKey); + } + + /// + /// Returns true if ExpandRequestTupleKey instances are equal + /// + /// Instance of ExpandRequestTupleKey to be compared + /// Boolean + public bool Equals(ExpandRequestTupleKey input) { + if (input == null) { + return false; + } + return + ( + this.Relation == input.Relation || + (this.Relation != null && + this.Relation.Equals(input.Relation)) + ) && + ( + this.Object == input.Object || + (this.Object != null && + this.Object.Equals(input.Object)) + ) + && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + } + + /// + /// Gets the hash code + /// + /// Hash code + public override int GetHashCode() { + unchecked // Overflow is fine, just wrap + { + int hashCode = 9661; + if (this.Relation != null) { + hashCode = (hashCode * 9923) + this.Relation.GetHashCode(); + } + if (this.Object != null) { + hashCode = (hashCode * 9923) + this.Object.GetHashCode(); + } + if (this.AdditionalProperties != null) { + hashCode = (hashCode * 9923) + this.AdditionalProperties.GetHashCode(); + } + return hashCode; + } + } + + /// + /// To validate all properties of the instance + /// + /// Validation context + /// Validation Result + public IEnumerable Validate(ValidationContext validationContext) { + // Relation (string) maxLength + if (this.Relation != null && this.Relation.Length > 50) { + yield return new ValidationResult("Invalid value for Relation, length must be less than 50.", new[] { "Relation" }); + } + + // Object (string) maxLength + if (this.Object != null && this.Object.Length > 256) { + yield return new ValidationResult("Invalid value for Object, length must be less than 256.", new[] { "Object" }); + } + + yield break; + } + + } + +} \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/GetStoreResponse.cs b/src/OpenFga.Sdk/Model/GetStoreResponse.cs index 58684a4..0a56948 100644 --- a/src/OpenFga.Sdk/Model/GetStoreResponse.cs +++ b/src/OpenFga.Sdk/Model/GetStoreResponse.cs @@ -33,49 +33,67 @@ public GetStoreResponse() { /// /// Initializes a new instance of the class. /// - /// id. - /// name. - /// createdAt. - /// updatedAt. - public GetStoreResponse(string id = default(string), string name = default(string), DateTime createdAt = default(DateTime), DateTime updatedAt = default(DateTime)) { + /// id (required). + /// name (required). + /// createdAt (required). + /// updatedAt (required). + /// deletedAt. + public GetStoreResponse(string id = default(string), string name = default(string), DateTime createdAt = default(DateTime), DateTime updatedAt = default(DateTime), DateTime deletedAt = default(DateTime)) { + // to ensure "id" is required (not null) + if (id == null) { + throw new ArgumentNullException("id is a required property for GetStoreResponse and cannot be null"); + } this.Id = id; + // to ensure "name" is required (not null) + if (name == null) { + throw new ArgumentNullException("name is a required property for GetStoreResponse and cannot be null"); + } this.Name = name; this.CreatedAt = createdAt; this.UpdatedAt = updatedAt; + this.DeletedAt = deletedAt; this.AdditionalProperties = new Dictionary(); } /// /// Gets or Sets Id /// - [DataMember(Name = "id", EmitDefaultValue = false)] + [DataMember(Name = "id", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("id")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public string? Id { get; set; } + public string Id { get; set; } /// /// Gets or Sets Name /// - [DataMember(Name = "name", EmitDefaultValue = false)] + [DataMember(Name = "name", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("name")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public string? Name { get; set; } + public string Name { get; set; } /// /// Gets or Sets CreatedAt /// - [DataMember(Name = "created_at", EmitDefaultValue = false)] + [DataMember(Name = "created_at", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("created_at")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public DateTime? CreatedAt { get; set; } + public DateTime CreatedAt { get; set; } /// /// Gets or Sets UpdatedAt /// - [DataMember(Name = "updated_at", EmitDefaultValue = false)] + [DataMember(Name = "updated_at", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("updated_at")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public DateTime? UpdatedAt { get; set; } + public DateTime UpdatedAt { get; set; } + + /// + /// Gets or Sets DeletedAt + /// + [DataMember(Name = "deleted_at", EmitDefaultValue = false)] + [JsonPropertyName("deleted_at")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public DateTime? DeletedAt { get; set; } /// /// Gets or Sets additional properties @@ -138,6 +156,11 @@ public bool Equals(GetStoreResponse input) { this.UpdatedAt == input.UpdatedAt || (this.UpdatedAt != null && this.UpdatedAt.Equals(input.UpdatedAt)) + ) && + ( + this.DeletedAt == input.DeletedAt || + (this.DeletedAt != null && + this.DeletedAt.Equals(input.DeletedAt)) ) && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); } @@ -162,6 +185,9 @@ public override int GetHashCode() { if (this.UpdatedAt != null) { hashCode = (hashCode * 9923) + this.UpdatedAt.GetHashCode(); } + if (this.DeletedAt != null) { + hashCode = (hashCode * 9923) + this.DeletedAt.GetHashCode(); + } if (this.AdditionalProperties != null) { hashCode = (hashCode * 9923) + this.AdditionalProperties.GetHashCode(); } diff --git a/src/OpenFga.Sdk/Model/ListObjectsRequest.cs b/src/OpenFga.Sdk/Model/ListObjectsRequest.cs index a3c23bf..76a40d6 100644 --- a/src/OpenFga.Sdk/Model/ListObjectsRequest.cs +++ b/src/OpenFga.Sdk/Model/ListObjectsRequest.cs @@ -38,7 +38,8 @@ public ListObjectsRequest() { /// relation (required). /// user (required). /// contextualTuples. - public ListObjectsRequest(string authorizationModelId = default(string), string type = default(string), string relation = default(string), string user = default(string), ContextualTupleKeys contextualTuples = default(ContextualTupleKeys)) { + /// Additional request context that will be used to evaluate any ABAC conditions encountered in the query evaluation.. + public ListObjectsRequest(string authorizationModelId = default(string), string type = default(string), string relation = default(string), string user = default(string), ContextualTupleKeys contextualTuples = default(ContextualTupleKeys), Object context = default(Object)) { // to ensure "type" is required (not null) if (type == null) { throw new ArgumentNullException("type is a required property for ListObjectsRequest and cannot be null"); @@ -56,6 +57,7 @@ public ListObjectsRequest() { this.User = user; this.AuthorizationModelId = authorizationModelId; this.ContextualTuples = contextualTuples; + this.Context = context; this.AdditionalProperties = new Dictionary(); } @@ -99,6 +101,15 @@ public ListObjectsRequest() { [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public ContextualTupleKeys? ContextualTuples { get; set; } + /// + /// Additional request context that will be used to evaluate any ABAC conditions encountered in the query evaluation. + /// + /// Additional request context that will be used to evaluate any ABAC conditions encountered in the query evaluation. + [DataMember(Name = "context", EmitDefaultValue = false)] + [JsonPropertyName("context")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public Object? Context { get; set; } + /// /// Gets or Sets additional properties /// @@ -165,6 +176,11 @@ public bool Equals(ListObjectsRequest input) { this.ContextualTuples == input.ContextualTuples || (this.ContextualTuples != null && this.ContextualTuples.Equals(input.ContextualTuples)) + ) && + ( + this.Context == input.Context || + (this.Context != null && + this.Context.Equals(input.Context)) ) && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); } @@ -192,6 +208,9 @@ public override int GetHashCode() { if (this.ContextualTuples != null) { hashCode = (hashCode * 9923) + this.ContextualTuples.GetHashCode(); } + if (this.Context != null) { + hashCode = (hashCode * 9923) + this.Context.GetHashCode(); + } if (this.AdditionalProperties != null) { hashCode = (hashCode * 9923) + this.AdditionalProperties.GetHashCode(); } diff --git a/src/OpenFga.Sdk/Model/ListObjectsResponse.cs b/src/OpenFga.Sdk/Model/ListObjectsResponse.cs index 8df4263..7c9e8e9 100644 --- a/src/OpenFga.Sdk/Model/ListObjectsResponse.cs +++ b/src/OpenFga.Sdk/Model/ListObjectsResponse.cs @@ -33,8 +33,12 @@ public ListObjectsResponse() { /// /// Initializes a new instance of the class. /// - /// objects. + /// objects (required). public ListObjectsResponse(List objects = default(List)) { + // to ensure "objects" is required (not null) + if (objects == null) { + throw new ArgumentNullException("objects is a required property for ListObjectsResponse and cannot be null"); + } this.Objects = objects; this.AdditionalProperties = new Dictionary(); } @@ -42,10 +46,10 @@ public ListObjectsResponse() { /// /// Gets or Sets Objects /// - [DataMember(Name = "objects", EmitDefaultValue = false)] + [DataMember(Name = "objects", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("objects")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public List? Objects { get; set; } + public List Objects { get; set; } /// /// Gets or Sets additional properties diff --git a/src/OpenFga.Sdk/Model/ListStoresResponse.cs b/src/OpenFga.Sdk/Model/ListStoresResponse.cs index fe2cb49..6e2f7ac 100644 --- a/src/OpenFga.Sdk/Model/ListStoresResponse.cs +++ b/src/OpenFga.Sdk/Model/ListStoresResponse.cs @@ -33,10 +33,18 @@ public ListStoresResponse() { /// /// Initializes a new instance of the class. /// - /// stores. - /// The continuation token will be empty if there are no more stores.. + /// stores (required). + /// The continuation token will be empty if there are no more stores. (required). public ListStoresResponse(List stores = default(List), string continuationToken = default(string)) { + // to ensure "stores" is required (not null) + if (stores == null) { + throw new ArgumentNullException("stores is a required property for ListStoresResponse and cannot be null"); + } this.Stores = stores; + // to ensure "continuationToken" is required (not null) + if (continuationToken == null) { + throw new ArgumentNullException("continuationToken is a required property for ListStoresResponse and cannot be null"); + } this.ContinuationToken = continuationToken; this.AdditionalProperties = new Dictionary(); } @@ -44,19 +52,19 @@ public ListStoresResponse() { /// /// Gets or Sets Stores /// - [DataMember(Name = "stores", EmitDefaultValue = false)] + [DataMember(Name = "stores", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("stores")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public List? Stores { get; set; } + public List Stores { get; set; } /// /// The continuation token will be empty if there are no more stores. /// /// The continuation token will be empty if there are no more stores. - [DataMember(Name = "continuation_token", EmitDefaultValue = false)] + [DataMember(Name = "continuation_token", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("continuation_token")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public string? ContinuationToken { get; set; } + public string ContinuationToken { get; set; } /// /// Gets or Sets additional properties diff --git a/src/OpenFga.Sdk/Model/Node.cs b/src/OpenFga.Sdk/Model/Node.cs index d1301af..ba08153 100644 --- a/src/OpenFga.Sdk/Model/Node.cs +++ b/src/OpenFga.Sdk/Model/Node.cs @@ -33,12 +33,16 @@ public Node() { /// /// Initializes a new instance of the class. /// - /// name. + /// name (required). /// leaf. /// difference. /// union. /// intersection. public Node(string name = default(string), Leaf leaf = default(Leaf), UsersetTreeDifference difference = default(UsersetTreeDifference), Nodes union = default(Nodes), Nodes intersection = default(Nodes)) { + // to ensure "name" is required (not null) + if (name == null) { + throw new ArgumentNullException("name is a required property for Node and cannot be null"); + } this.Name = name; this.Leaf = leaf; this.Difference = difference; @@ -50,10 +54,10 @@ public Node() { /// /// Gets or Sets Name /// - [DataMember(Name = "name", EmitDefaultValue = false)] + [DataMember(Name = "name", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("name")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public string? Name { get; set; } + public string Name { get; set; } /// /// Gets or Sets Leaf diff --git a/src/OpenFga.Sdk/Model/Nodes.cs b/src/OpenFga.Sdk/Model/Nodes.cs index 9caaa01..c7f2267 100644 --- a/src/OpenFga.Sdk/Model/Nodes.cs +++ b/src/OpenFga.Sdk/Model/Nodes.cs @@ -33,8 +33,12 @@ public Nodes() { /// /// Initializes a new instance of the class. /// - /// nodes. + /// nodes (required). public Nodes(List nodes = default(List)) { + // to ensure "nodes" is required (not null) + if (nodes == null) { + throw new ArgumentNullException("nodes is a required property for Nodes and cannot be null"); + } this._Nodes = nodes; this.AdditionalProperties = new Dictionary(); } @@ -42,10 +46,10 @@ public Nodes() { /// /// Gets or Sets _Nodes /// - [DataMember(Name = "nodes", EmitDefaultValue = false)] + [DataMember(Name = "nodes", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("nodes")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public List? _Nodes { get; set; } + public List _Nodes { get; set; } /// /// Gets or Sets additional properties diff --git a/src/OpenFga.Sdk/Model/NullValue.cs b/src/OpenFga.Sdk/Model/NullValue.cs new file mode 100644 index 0000000..2ebd7de --- /dev/null +++ b/src/OpenFga.Sdk/Model/NullValue.cs @@ -0,0 +1,32 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 0.1 +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://discord.gg/8naAwJfWN6 +// License: [Apache-2.0](https://github.com/openfga/dotnet-sdk/blob/main/LICENSE) +// +// NOTE: This file was auto generated. DO NOT EDIT. +// + + +using System.Runtime.Serialization; +using System.Text.Json.Serialization; + +namespace OpenFga.Sdk.Model { + /// + /// `NullValue` is a singleton enumeration to represent the null value for the `Value` type union. The JSON representation for `NullValue` is JSON `null`. - NULL_VALUE: Null value. + /// + /// `NullValue` is a singleton enumeration to represent the null value for the `Value` type union. The JSON representation for `NullValue` is JSON `null`. - NULL_VALUE: Null value. + [JsonConverter(typeof(JsonStringEnumMemberConverter))] + public enum NullValue { + /// + /// Enum NULLVALUE for value: NULL_VALUE + /// + [EnumMember(Value = "NULL_VALUE")] + NULLVALUE = 1 + + } + +} \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/ReadAssertionsResponse.cs b/src/OpenFga.Sdk/Model/ReadAssertionsResponse.cs index 028e5a2..90da558 100644 --- a/src/OpenFga.Sdk/Model/ReadAssertionsResponse.cs +++ b/src/OpenFga.Sdk/Model/ReadAssertionsResponse.cs @@ -33,9 +33,13 @@ public ReadAssertionsResponse() { /// /// Initializes a new instance of the class. /// - /// authorizationModelId. + /// authorizationModelId (required). /// assertions. public ReadAssertionsResponse(string authorizationModelId = default(string), List assertions = default(List)) { + // to ensure "authorizationModelId" is required (not null) + if (authorizationModelId == null) { + throw new ArgumentNullException("authorizationModelId is a required property for ReadAssertionsResponse and cannot be null"); + } this.AuthorizationModelId = authorizationModelId; this.Assertions = assertions; this.AdditionalProperties = new Dictionary(); @@ -44,10 +48,10 @@ public ReadAssertionsResponse() { /// /// Gets or Sets AuthorizationModelId /// - [DataMember(Name = "authorization_model_id", EmitDefaultValue = false)] + [DataMember(Name = "authorization_model_id", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("authorization_model_id")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public string? AuthorizationModelId { get; set; } + public string AuthorizationModelId { get; set; } /// /// Gets or Sets Assertions diff --git a/src/OpenFga.Sdk/Model/ReadAuthorizationModelsResponse.cs b/src/OpenFga.Sdk/Model/ReadAuthorizationModelsResponse.cs index e258f83..d3d67ee 100644 --- a/src/OpenFga.Sdk/Model/ReadAuthorizationModelsResponse.cs +++ b/src/OpenFga.Sdk/Model/ReadAuthorizationModelsResponse.cs @@ -33,9 +33,13 @@ public ReadAuthorizationModelsResponse() { /// /// Initializes a new instance of the class. /// - /// authorizationModels. + /// authorizationModels (required). /// The continuation token will be empty if there are no more models.. public ReadAuthorizationModelsResponse(List authorizationModels = default(List), string continuationToken = default(string)) { + // to ensure "authorizationModels" is required (not null) + if (authorizationModels == null) { + throw new ArgumentNullException("authorizationModels is a required property for ReadAuthorizationModelsResponse and cannot be null"); + } this.AuthorizationModels = authorizationModels; this.ContinuationToken = continuationToken; this.AdditionalProperties = new Dictionary(); @@ -44,10 +48,10 @@ public ReadAuthorizationModelsResponse() { /// /// Gets or Sets AuthorizationModels /// - [DataMember(Name = "authorization_models", EmitDefaultValue = false)] + [DataMember(Name = "authorization_models", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("authorization_models")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public List? AuthorizationModels { get; set; } + public List AuthorizationModels { get; set; } /// /// The continuation token will be empty if there are no more models. diff --git a/src/OpenFga.Sdk/Model/ReadChangesResponse.cs b/src/OpenFga.Sdk/Model/ReadChangesResponse.cs index 0be405b..e28cc3e 100644 --- a/src/OpenFga.Sdk/Model/ReadChangesResponse.cs +++ b/src/OpenFga.Sdk/Model/ReadChangesResponse.cs @@ -33,9 +33,13 @@ public ReadChangesResponse() { /// /// Initializes a new instance of the class. /// - /// changes. + /// changes (required). /// The continuation token will be identical if there are no new changes.. public ReadChangesResponse(List changes = default(List), string continuationToken = default(string)) { + // to ensure "changes" is required (not null) + if (changes == null) { + throw new ArgumentNullException("changes is a required property for ReadChangesResponse and cannot be null"); + } this.Changes = changes; this.ContinuationToken = continuationToken; this.AdditionalProperties = new Dictionary(); @@ -44,10 +48,10 @@ public ReadChangesResponse() { /// /// Gets or Sets Changes /// - [DataMember(Name = "changes", EmitDefaultValue = false)] + [DataMember(Name = "changes", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("changes")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public List? Changes { get; set; } + public List Changes { get; set; } /// /// The continuation token will be identical if there are no new changes. diff --git a/src/OpenFga.Sdk/Model/ReadRequest.cs b/src/OpenFga.Sdk/Model/ReadRequest.cs index 9839daf..cf5b1a8 100644 --- a/src/OpenFga.Sdk/Model/ReadRequest.cs +++ b/src/OpenFga.Sdk/Model/ReadRequest.cs @@ -36,7 +36,7 @@ public ReadRequest() { /// tupleKey. /// pageSize. /// continuationToken. - public ReadRequest(TupleKey tupleKey = default(TupleKey), int pageSize = default(int), string continuationToken = default(string)) { + public ReadRequest(ReadRequestTupleKey tupleKey = default(ReadRequestTupleKey), int pageSize = default(int), string continuationToken = default(string)) { this.TupleKey = tupleKey; this.PageSize = pageSize; this.ContinuationToken = continuationToken; @@ -49,7 +49,7 @@ public ReadRequest() { [DataMember(Name = "tuple_key", EmitDefaultValue = false)] [JsonPropertyName("tuple_key")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public TupleKey? TupleKey { get; set; } + public ReadRequestTupleKey? TupleKey { get; set; } /// /// Gets or Sets PageSize diff --git a/src/OpenFga.Sdk/Model/ReadRequestTupleKey.cs b/src/OpenFga.Sdk/Model/ReadRequestTupleKey.cs new file mode 100644 index 0000000..aa584bb --- /dev/null +++ b/src/OpenFga.Sdk/Model/ReadRequestTupleKey.cs @@ -0,0 +1,180 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 0.1 +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://discord.gg/8naAwJfWN6 +// License: [Apache-2.0](https://github.com/openfga/dotnet-sdk/blob/main/LICENSE) +// +// NOTE: This file was auto generated. DO NOT EDIT. +// + + +using System.ComponentModel.DataAnnotations; +using System.Runtime.Serialization; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace OpenFga.Sdk.Model { + /// + /// ReadRequestTupleKey + /// + [DataContract(Name = "ReadRequestTupleKey")] + public partial class ReadRequestTupleKey : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public ReadRequestTupleKey() { + this.AdditionalProperties = new Dictionary(); + } + + /// + /// Initializes a new instance of the class. + /// + /// user. + /// relation. + /// _object. + public ReadRequestTupleKey(string user = default(string), string relation = default(string), string _object = default(string)) { + this.User = user; + this.Relation = relation; + this.Object = _object; + this.AdditionalProperties = new Dictionary(); + } + + /// + /// Gets or Sets User + /// + [DataMember(Name = "user", EmitDefaultValue = false)] + [JsonPropertyName("user")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string? User { get; set; } + + /// + /// Gets or Sets Relation + /// + [DataMember(Name = "relation", EmitDefaultValue = false)] + [JsonPropertyName("relation")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string? Relation { get; set; } + + /// + /// Gets or Sets Object + /// + [DataMember(Name = "object", EmitDefaultValue = false)] + [JsonPropertyName("object")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string? Object { get; set; } + + /// + /// Gets or Sets additional properties + /// + [JsonExtensionData] + public IDictionary AdditionalProperties { get; set; } + + + /// + /// Returns the JSON string presentation of the object + /// + /// JSON string presentation of the object + public virtual string ToJson() { + return JsonSerializer.Serialize(this); + } + + /// + /// Builds a ReadRequestTupleKey from the JSON string presentation of the object + /// + /// ReadRequestTupleKey + public static ReadRequestTupleKey FromJson(string jsonString) { + return JsonSerializer.Deserialize(jsonString) ?? throw new InvalidOperationException(); + } + + /// + /// Returns true if objects are equal + /// + /// Object to be compared + /// Boolean + public override bool Equals(object input) { + return this.Equals(input as ReadRequestTupleKey); + } + + /// + /// Returns true if ReadRequestTupleKey instances are equal + /// + /// Instance of ReadRequestTupleKey to be compared + /// Boolean + public bool Equals(ReadRequestTupleKey input) { + if (input == null) { + return false; + } + return + ( + this.User == input.User || + (this.User != null && + this.User.Equals(input.User)) + ) && + ( + this.Relation == input.Relation || + (this.Relation != null && + this.Relation.Equals(input.Relation)) + ) && + ( + this.Object == input.Object || + (this.Object != null && + this.Object.Equals(input.Object)) + ) + && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + } + + /// + /// Gets the hash code + /// + /// Hash code + public override int GetHashCode() { + unchecked // Overflow is fine, just wrap + { + int hashCode = 9661; + if (this.User != null) { + hashCode = (hashCode * 9923) + this.User.GetHashCode(); + } + if (this.Relation != null) { + hashCode = (hashCode * 9923) + this.Relation.GetHashCode(); + } + if (this.Object != null) { + hashCode = (hashCode * 9923) + this.Object.GetHashCode(); + } + if (this.AdditionalProperties != null) { + hashCode = (hashCode * 9923) + this.AdditionalProperties.GetHashCode(); + } + return hashCode; + } + } + + /// + /// To validate all properties of the instance + /// + /// Validation context + /// Validation Result + public IEnumerable Validate(ValidationContext validationContext) { + // User (string) maxLength + if (this.User != null && this.User.Length > 512) { + yield return new ValidationResult("Invalid value for User, length must be less than 512.", new[] { "User" }); + } + + // Relation (string) maxLength + if (this.Relation != null && this.Relation.Length > 50) { + yield return new ValidationResult("Invalid value for Relation, length must be less than 50.", new[] { "Relation" }); + } + + // Object (string) maxLength + if (this.Object != null && this.Object.Length > 256) { + yield return new ValidationResult("Invalid value for Object, length must be less than 256.", new[] { "Object" }); + } + + yield break; + } + + } + +} \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/ReadResponse.cs b/src/OpenFga.Sdk/Model/ReadResponse.cs index c4586f7..d5df3d2 100644 --- a/src/OpenFga.Sdk/Model/ReadResponse.cs +++ b/src/OpenFga.Sdk/Model/ReadResponse.cs @@ -33,10 +33,18 @@ public ReadResponse() { /// /// Initializes a new instance of the class. /// - /// tuples. - /// The continuation token will be empty if there are no more tuples.. + /// tuples (required). + /// The continuation token will be empty if there are no more tuples. (required). public ReadResponse(List tuples = default(List), string continuationToken = default(string)) { + // to ensure "tuples" is required (not null) + if (tuples == null) { + throw new ArgumentNullException("tuples is a required property for ReadResponse and cannot be null"); + } this.Tuples = tuples; + // to ensure "continuationToken" is required (not null) + if (continuationToken == null) { + throw new ArgumentNullException("continuationToken is a required property for ReadResponse and cannot be null"); + } this.ContinuationToken = continuationToken; this.AdditionalProperties = new Dictionary(); } @@ -44,19 +52,19 @@ public ReadResponse() { /// /// Gets or Sets Tuples /// - [DataMember(Name = "tuples", EmitDefaultValue = false)] + [DataMember(Name = "tuples", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("tuples")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public List? Tuples { get; set; } + public List Tuples { get; set; } /// /// The continuation token will be empty if there are no more tuples. /// /// The continuation token will be empty if there are no more tuples. - [DataMember(Name = "continuation_token", EmitDefaultValue = false)] + [DataMember(Name = "continuation_token", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("continuation_token")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public string? ContinuationToken { get; set; } + public string ContinuationToken { get; set; } /// /// Gets or Sets additional properties diff --git a/src/OpenFga.Sdk/Model/RelationReference.cs b/src/OpenFga.Sdk/Model/RelationReference.cs index 53670d0..7721be8 100644 --- a/src/OpenFga.Sdk/Model/RelationReference.cs +++ b/src/OpenFga.Sdk/Model/RelationReference.cs @@ -36,7 +36,8 @@ public RelationReference() { /// type (required). /// relation. /// wildcard. - public RelationReference(string type = default(string), string relation = default(string), Object wildcard = default(Object)) { + /// The name of a condition that is enforced over the allowed relation.. + public RelationReference(string type = default(string), string relation = default(string), Object wildcard = default(Object), string condition = default(string)) { // to ensure "type" is required (not null) if (type == null) { throw new ArgumentNullException("type is a required property for RelationReference and cannot be null"); @@ -44,6 +45,7 @@ public RelationReference() { this.Type = type; this.Relation = relation; this.Wildcard = wildcard; + this.Condition = condition; this.AdditionalProperties = new Dictionary(); } @@ -71,6 +73,15 @@ public RelationReference() { [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public Object? Wildcard { get; set; } + /// + /// The name of a condition that is enforced over the allowed relation. + /// + /// The name of a condition that is enforced over the allowed relation. + [DataMember(Name = "condition", EmitDefaultValue = false)] + [JsonPropertyName("condition")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string? Condition { get; set; } + /// /// Gets or Sets additional properties /// @@ -127,6 +138,11 @@ public bool Equals(RelationReference input) { this.Wildcard == input.Wildcard || (this.Wildcard != null && this.Wildcard.Equals(input.Wildcard)) + ) && + ( + this.Condition == input.Condition || + (this.Condition != null && + this.Condition.Equals(input.Condition)) ) && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); } @@ -148,6 +164,9 @@ public override int GetHashCode() { if (this.Wildcard != null) { hashCode = (hashCode * 9923) + this.Wildcard.GetHashCode(); } + if (this.Condition != null) { + hashCode = (hashCode * 9923) + this.Condition.GetHashCode(); + } if (this.AdditionalProperties != null) { hashCode = (hashCode * 9923) + this.AdditionalProperties.GetHashCode(); } diff --git a/src/OpenFga.Sdk/Model/RelationshipCondition.cs b/src/OpenFga.Sdk/Model/RelationshipCondition.cs new file mode 100644 index 0000000..1aa943e --- /dev/null +++ b/src/OpenFga.Sdk/Model/RelationshipCondition.cs @@ -0,0 +1,158 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 0.1 +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://discord.gg/8naAwJfWN6 +// License: [Apache-2.0](https://github.com/openfga/dotnet-sdk/blob/main/LICENSE) +// +// NOTE: This file was auto generated. DO NOT EDIT. +// + + +using System.ComponentModel.DataAnnotations; +using System.Runtime.Serialization; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace OpenFga.Sdk.Model { + /// + /// RelationshipCondition + /// + [DataContract(Name = "RelationshipCondition")] + public partial class RelationshipCondition : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public RelationshipCondition() { + this.AdditionalProperties = new Dictionary(); + } + + /// + /// Initializes a new instance of the class. + /// + /// A reference (by name) of the relationship condition defined in the authorization model. (required). + /// Additional context/data to persist along with the condition. The keys must match the parameters defined by the condition, and the value types must match the parameter type definitions.. + public RelationshipCondition(string name = default(string), Object context = default(Object)) { + // to ensure "name" is required (not null) + if (name == null) { + throw new ArgumentNullException("name is a required property for RelationshipCondition and cannot be null"); + } + this.Name = name; + this.Context = context; + this.AdditionalProperties = new Dictionary(); + } + + /// + /// A reference (by name) of the relationship condition defined in the authorization model. + /// + /// A reference (by name) of the relationship condition defined in the authorization model. + [DataMember(Name = "name", IsRequired = true, EmitDefaultValue = false)] + [JsonPropertyName("name")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string Name { get; set; } + + /// + /// Additional context/data to persist along with the condition. The keys must match the parameters defined by the condition, and the value types must match the parameter type definitions. + /// + /// Additional context/data to persist along with the condition. The keys must match the parameters defined by the condition, and the value types must match the parameter type definitions. + [DataMember(Name = "context", EmitDefaultValue = false)] + [JsonPropertyName("context")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public Object? Context { get; set; } + + /// + /// Gets or Sets additional properties + /// + [JsonExtensionData] + public IDictionary AdditionalProperties { get; set; } + + + /// + /// Returns the JSON string presentation of the object + /// + /// JSON string presentation of the object + public virtual string ToJson() { + return JsonSerializer.Serialize(this); + } + + /// + /// Builds a RelationshipCondition from the JSON string presentation of the object + /// + /// RelationshipCondition + public static RelationshipCondition FromJson(string jsonString) { + return JsonSerializer.Deserialize(jsonString) ?? throw new InvalidOperationException(); + } + + /// + /// Returns true if objects are equal + /// + /// Object to be compared + /// Boolean + public override bool Equals(object input) { + return this.Equals(input as RelationshipCondition); + } + + /// + /// Returns true if RelationshipCondition instances are equal + /// + /// Instance of RelationshipCondition to be compared + /// Boolean + public bool Equals(RelationshipCondition input) { + if (input == null) { + return false; + } + return + ( + this.Name == input.Name || + (this.Name != null && + this.Name.Equals(input.Name)) + ) && + ( + this.Context == input.Context || + (this.Context != null && + this.Context.Equals(input.Context)) + ) + && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + } + + /// + /// Gets the hash code + /// + /// Hash code + public override int GetHashCode() { + unchecked // Overflow is fine, just wrap + { + int hashCode = 9661; + if (this.Name != null) { + hashCode = (hashCode * 9923) + this.Name.GetHashCode(); + } + if (this.Context != null) { + hashCode = (hashCode * 9923) + this.Context.GetHashCode(); + } + if (this.AdditionalProperties != null) { + hashCode = (hashCode * 9923) + this.AdditionalProperties.GetHashCode(); + } + return hashCode; + } + } + + /// + /// To validate all properties of the instance + /// + /// Validation context + /// Validation Result + public IEnumerable Validate(ValidationContext validationContext) { + // Name (string) maxLength + if (this.Name != null && this.Name.Length > 256) { + yield return new ValidationResult("Invalid value for Name, length must be less than 256.", new[] { "Name" }); + } + + yield break; + } + + } + +} \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/Store.cs b/src/OpenFga.Sdk/Model/Store.cs index c8a161a..50550c4 100644 --- a/src/OpenFga.Sdk/Model/Store.cs +++ b/src/OpenFga.Sdk/Model/Store.cs @@ -33,13 +33,21 @@ public Store() { /// /// Initializes a new instance of the class. /// - /// id. - /// name. - /// createdAt. - /// updatedAt. + /// id (required). + /// name (required). + /// createdAt (required). + /// updatedAt (required). /// deletedAt. public Store(string id = default(string), string name = default(string), DateTime createdAt = default(DateTime), DateTime updatedAt = default(DateTime), DateTime deletedAt = default(DateTime)) { + // to ensure "id" is required (not null) + if (id == null) { + throw new ArgumentNullException("id is a required property for Store and cannot be null"); + } this.Id = id; + // to ensure "name" is required (not null) + if (name == null) { + throw new ArgumentNullException("name is a required property for Store and cannot be null"); + } this.Name = name; this.CreatedAt = createdAt; this.UpdatedAt = updatedAt; @@ -50,34 +58,34 @@ public Store() { /// /// Gets or Sets Id /// - [DataMember(Name = "id", EmitDefaultValue = false)] + [DataMember(Name = "id", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("id")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public string? Id { get; set; } + public string Id { get; set; } /// /// Gets or Sets Name /// - [DataMember(Name = "name", EmitDefaultValue = false)] + [DataMember(Name = "name", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("name")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public string? Name { get; set; } + public string Name { get; set; } /// /// Gets or Sets CreatedAt /// - [DataMember(Name = "created_at", EmitDefaultValue = false)] + [DataMember(Name = "created_at", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("created_at")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public DateTime? CreatedAt { get; set; } + public DateTime CreatedAt { get; set; } /// /// Gets or Sets UpdatedAt /// - [DataMember(Name = "updated_at", EmitDefaultValue = false)] + [DataMember(Name = "updated_at", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("updated_at")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public DateTime? UpdatedAt { get; set; } + public DateTime UpdatedAt { get; set; } /// /// Gets or Sets DeletedAt diff --git a/src/OpenFga.Sdk/Model/Tuple.cs b/src/OpenFga.Sdk/Model/Tuple.cs index 7038563..fbc32ec 100644 --- a/src/OpenFga.Sdk/Model/Tuple.cs +++ b/src/OpenFga.Sdk/Model/Tuple.cs @@ -33,9 +33,13 @@ public Tuple() { /// /// Initializes a new instance of the class. /// - /// key. - /// timestamp. + /// key (required). + /// timestamp (required). public Tuple(TupleKey key = default(TupleKey), DateTime timestamp = default(DateTime)) { + // to ensure "key" is required (not null) + if (key == null) { + throw new ArgumentNullException("key is a required property for Tuple and cannot be null"); + } this.Key = key; this.Timestamp = timestamp; this.AdditionalProperties = new Dictionary(); @@ -44,18 +48,18 @@ public Tuple() { /// /// Gets or Sets Key /// - [DataMember(Name = "key", EmitDefaultValue = false)] + [DataMember(Name = "key", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("key")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public TupleKey? Key { get; set; } + public TupleKey Key { get; set; } /// /// Gets or Sets Timestamp /// - [DataMember(Name = "timestamp", EmitDefaultValue = false)] + [DataMember(Name = "timestamp", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("timestamp")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public DateTime? Timestamp { get; set; } + public DateTime Timestamp { get; set; } /// /// Gets or Sets additional properties diff --git a/src/OpenFga.Sdk/Model/TupleChange.cs b/src/OpenFga.Sdk/Model/TupleChange.cs index a7c5633..44702f4 100644 --- a/src/OpenFga.Sdk/Model/TupleChange.cs +++ b/src/OpenFga.Sdk/Model/TupleChange.cs @@ -26,9 +26,9 @@ public partial class TupleChange : IEquatable, IValidatableObject { /// /// Gets or Sets Operation /// - [DataMember(Name = "operation", EmitDefaultValue = false)] + [DataMember(Name = "operation", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("operation")] - public TupleOperation? Operation { get; set; } + public TupleOperation Operation { get; set; } /// /// Initializes a new instance of the class. /// @@ -40,10 +40,14 @@ public TupleChange() { /// /// Initializes a new instance of the class. /// - /// tupleKey. - /// operation. - /// timestamp. - public TupleChange(TupleKey tupleKey = default(TupleKey), TupleOperation? operation = default(TupleOperation?), DateTime timestamp = default(DateTime)) { + /// tupleKey (required). + /// operation (required). + /// timestamp (required). + public TupleChange(TupleKey tupleKey = default(TupleKey), TupleOperation operation = default(TupleOperation), DateTime timestamp = default(DateTime)) { + // to ensure "tupleKey" is required (not null) + if (tupleKey == null) { + throw new ArgumentNullException("tupleKey is a required property for TupleChange and cannot be null"); + } this.TupleKey = tupleKey; this.Operation = operation; this.Timestamp = timestamp; @@ -53,18 +57,18 @@ public TupleChange() { /// /// Gets or Sets TupleKey /// - [DataMember(Name = "tuple_key", EmitDefaultValue = false)] + [DataMember(Name = "tuple_key", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("tuple_key")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public TupleKey? TupleKey { get; set; } + public TupleKey TupleKey { get; set; } /// /// Gets or Sets Timestamp /// - [DataMember(Name = "timestamp", EmitDefaultValue = false)] + [DataMember(Name = "timestamp", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("timestamp")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public DateTime? Timestamp { get; set; } + public DateTime Timestamp { get; set; } /// /// Gets or Sets additional properties diff --git a/src/OpenFga.Sdk/Model/TupleKey.cs b/src/OpenFga.Sdk/Model/TupleKey.cs index 74100a7..3714785 100644 --- a/src/OpenFga.Sdk/Model/TupleKey.cs +++ b/src/OpenFga.Sdk/Model/TupleKey.cs @@ -33,39 +33,61 @@ public TupleKey() { /// /// Initializes a new instance of the class. /// - /// _object. - /// relation. - /// user. - public TupleKey(string _object = default(string), string relation = default(string), string user = default(string)) { - this.Object = _object; - this.Relation = relation; + /// user (required). + /// relation (required). + /// _object (required). + /// condition. + public TupleKey(string user = default(string), string relation = default(string), string _object = default(string), RelationshipCondition condition = default(RelationshipCondition)) { + // to ensure "user" is required (not null) + if (user == null) { + throw new ArgumentNullException("user is a required property for TupleKey and cannot be null"); + } this.User = user; + // to ensure "relation" is required (not null) + if (relation == null) { + throw new ArgumentNullException("relation is a required property for TupleKey and cannot be null"); + } + this.Relation = relation; + // to ensure "_object" is required (not null) + if (_object == null) { + throw new ArgumentNullException("_object is a required property for TupleKey and cannot be null"); + } + this.Object = _object; + this.Condition = condition; this.AdditionalProperties = new Dictionary(); } /// - /// Gets or Sets Object + /// Gets or Sets User /// - [DataMember(Name = "object", EmitDefaultValue = false)] - [JsonPropertyName("object")] + [DataMember(Name = "user", IsRequired = true, EmitDefaultValue = false)] + [JsonPropertyName("user")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public string? Object { get; set; } + public string User { get; set; } /// /// Gets or Sets Relation /// - [DataMember(Name = "relation", EmitDefaultValue = false)] + [DataMember(Name = "relation", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("relation")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public string? Relation { get; set; } + public string Relation { get; set; } /// - /// Gets or Sets User + /// Gets or Sets Object /// - [DataMember(Name = "user", EmitDefaultValue = false)] - [JsonPropertyName("user")] + [DataMember(Name = "object", IsRequired = true, EmitDefaultValue = false)] + [JsonPropertyName("object")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public string? User { get; set; } + public string Object { get; set; } + + /// + /// Gets or Sets Condition + /// + [DataMember(Name = "condition", EmitDefaultValue = false)] + [JsonPropertyName("condition")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public RelationshipCondition? Condition { get; set; } /// /// Gets or Sets additional properties @@ -110,9 +132,9 @@ public bool Equals(TupleKey input) { } return ( - this.Object == input.Object || - (this.Object != null && - this.Object.Equals(input.Object)) + this.User == input.User || + (this.User != null && + this.User.Equals(input.User)) ) && ( this.Relation == input.Relation || @@ -120,9 +142,14 @@ public bool Equals(TupleKey input) { this.Relation.Equals(input.Relation)) ) && ( - this.User == input.User || - (this.User != null && - this.User.Equals(input.User)) + this.Object == input.Object || + (this.Object != null && + this.Object.Equals(input.Object)) + ) && + ( + this.Condition == input.Condition || + (this.Condition != null && + this.Condition.Equals(input.Condition)) ) && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); } @@ -135,14 +162,17 @@ public override int GetHashCode() { unchecked // Overflow is fine, just wrap { int hashCode = 9661; - if (this.Object != null) { - hashCode = (hashCode * 9923) + this.Object.GetHashCode(); + if (this.User != null) { + hashCode = (hashCode * 9923) + this.User.GetHashCode(); } if (this.Relation != null) { hashCode = (hashCode * 9923) + this.Relation.GetHashCode(); } - if (this.User != null) { - hashCode = (hashCode * 9923) + this.User.GetHashCode(); + if (this.Object != null) { + hashCode = (hashCode * 9923) + this.Object.GetHashCode(); + } + if (this.Condition != null) { + hashCode = (hashCode * 9923) + this.Condition.GetHashCode(); } if (this.AdditionalProperties != null) { hashCode = (hashCode * 9923) + this.AdditionalProperties.GetHashCode(); @@ -157,9 +187,9 @@ public override int GetHashCode() { /// Validation context /// Validation Result public IEnumerable Validate(ValidationContext validationContext) { - // Object (string) maxLength - if (this.Object != null && this.Object.Length > 256) { - yield return new ValidationResult("Invalid value for Object, length must be less than 256.", new[] { "Object" }); + // User (string) maxLength + if (this.User != null && this.User.Length > 512) { + yield return new ValidationResult("Invalid value for User, length must be less than 512.", new[] { "User" }); } // Relation (string) maxLength @@ -167,9 +197,9 @@ public IEnumerable Validate(ValidationContext validationContex yield return new ValidationResult("Invalid value for Relation, length must be less than 50.", new[] { "Relation" }); } - // User (string) maxLength - if (this.User != null && this.User.Length > 512) { - yield return new ValidationResult("Invalid value for User, length must be less than 512.", new[] { "User" }); + // Object (string) maxLength + if (this.Object != null && this.Object.Length > 256) { + yield return new ValidationResult("Invalid value for Object, length must be less than 256.", new[] { "Object" }); } yield break; diff --git a/src/OpenFga.Sdk/Model/TupleKeyWithoutCondition.cs b/src/OpenFga.Sdk/Model/TupleKeyWithoutCondition.cs new file mode 100644 index 0000000..9eac882 --- /dev/null +++ b/src/OpenFga.Sdk/Model/TupleKeyWithoutCondition.cs @@ -0,0 +1,192 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 0.1 +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://discord.gg/8naAwJfWN6 +// License: [Apache-2.0](https://github.com/openfga/dotnet-sdk/blob/main/LICENSE) +// +// NOTE: This file was auto generated. DO NOT EDIT. +// + + +using System.ComponentModel.DataAnnotations; +using System.Runtime.Serialization; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace OpenFga.Sdk.Model { + /// + /// TupleKeyWithoutCondition + /// + [DataContract(Name = "TupleKeyWithoutCondition")] + public partial class TupleKeyWithoutCondition : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public TupleKeyWithoutCondition() { + this.AdditionalProperties = new Dictionary(); + } + + /// + /// Initializes a new instance of the class. + /// + /// user (required). + /// relation (required). + /// _object (required). + public TupleKeyWithoutCondition(string user = default(string), string relation = default(string), string _object = default(string)) { + // to ensure "user" is required (not null) + if (user == null) { + throw new ArgumentNullException("user is a required property for TupleKeyWithoutCondition and cannot be null"); + } + this.User = user; + // to ensure "relation" is required (not null) + if (relation == null) { + throw new ArgumentNullException("relation is a required property for TupleKeyWithoutCondition and cannot be null"); + } + this.Relation = relation; + // to ensure "_object" is required (not null) + if (_object == null) { + throw new ArgumentNullException("_object is a required property for TupleKeyWithoutCondition and cannot be null"); + } + this.Object = _object; + this.AdditionalProperties = new Dictionary(); + } + + /// + /// Gets or Sets User + /// + [DataMember(Name = "user", IsRequired = true, EmitDefaultValue = false)] + [JsonPropertyName("user")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string User { get; set; } + + /// + /// Gets or Sets Relation + /// + [DataMember(Name = "relation", IsRequired = true, EmitDefaultValue = false)] + [JsonPropertyName("relation")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string Relation { get; set; } + + /// + /// Gets or Sets Object + /// + [DataMember(Name = "object", IsRequired = true, EmitDefaultValue = false)] + [JsonPropertyName("object")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string Object { get; set; } + + /// + /// Gets or Sets additional properties + /// + [JsonExtensionData] + public IDictionary AdditionalProperties { get; set; } + + + /// + /// Returns the JSON string presentation of the object + /// + /// JSON string presentation of the object + public virtual string ToJson() { + return JsonSerializer.Serialize(this); + } + + /// + /// Builds a TupleKeyWithoutCondition from the JSON string presentation of the object + /// + /// TupleKeyWithoutCondition + public static TupleKeyWithoutCondition FromJson(string jsonString) { + return JsonSerializer.Deserialize(jsonString) ?? throw new InvalidOperationException(); + } + + /// + /// Returns true if objects are equal + /// + /// Object to be compared + /// Boolean + public override bool Equals(object input) { + return this.Equals(input as TupleKeyWithoutCondition); + } + + /// + /// Returns true if TupleKeyWithoutCondition instances are equal + /// + /// Instance of TupleKeyWithoutCondition to be compared + /// Boolean + public bool Equals(TupleKeyWithoutCondition input) { + if (input == null) { + return false; + } + return + ( + this.User == input.User || + (this.User != null && + this.User.Equals(input.User)) + ) && + ( + this.Relation == input.Relation || + (this.Relation != null && + this.Relation.Equals(input.Relation)) + ) && + ( + this.Object == input.Object || + (this.Object != null && + this.Object.Equals(input.Object)) + ) + && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + } + + /// + /// Gets the hash code + /// + /// Hash code + public override int GetHashCode() { + unchecked // Overflow is fine, just wrap + { + int hashCode = 9661; + if (this.User != null) { + hashCode = (hashCode * 9923) + this.User.GetHashCode(); + } + if (this.Relation != null) { + hashCode = (hashCode * 9923) + this.Relation.GetHashCode(); + } + if (this.Object != null) { + hashCode = (hashCode * 9923) + this.Object.GetHashCode(); + } + if (this.AdditionalProperties != null) { + hashCode = (hashCode * 9923) + this.AdditionalProperties.GetHashCode(); + } + return hashCode; + } + } + + /// + /// To validate all properties of the instance + /// + /// Validation context + /// Validation Result + public IEnumerable Validate(ValidationContext validationContext) { + // User (string) maxLength + if (this.User != null && this.User.Length > 512) { + yield return new ValidationResult("Invalid value for User, length must be less than 512.", new[] { "User" }); + } + + // Relation (string) maxLength + if (this.Relation != null && this.Relation.Length > 50) { + yield return new ValidationResult("Invalid value for Relation, length must be less than 50.", new[] { "Relation" }); + } + + // Object (string) maxLength + if (this.Object != null && this.Object.Length > 256) { + yield return new ValidationResult("Invalid value for Object, length must be less than 256.", new[] { "Object" }); + } + + yield break; + } + + } + +} \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/TupleToUserset.cs b/src/OpenFga.Sdk/Model/TupleToUserset.cs index 5c8b6c5..605a1d8 100644 --- a/src/OpenFga.Sdk/Model/TupleToUserset.cs +++ b/src/OpenFga.Sdk/Model/TupleToUserset.cs @@ -33,10 +33,18 @@ public TupleToUserset() { /// /// Initializes a new instance of the class. /// - /// tupleset. - /// computedUserset. + /// tupleset (required). + /// computedUserset (required). public TupleToUserset(ObjectRelation tupleset = default(ObjectRelation), ObjectRelation computedUserset = default(ObjectRelation)) { + // to ensure "tupleset" is required (not null) + if (tupleset == null) { + throw new ArgumentNullException("tupleset is a required property for TupleToUserset and cannot be null"); + } this.Tupleset = tupleset; + // to ensure "computedUserset" is required (not null) + if (computedUserset == null) { + throw new ArgumentNullException("computedUserset is a required property for TupleToUserset and cannot be null"); + } this.ComputedUserset = computedUserset; this.AdditionalProperties = new Dictionary(); } @@ -44,18 +52,18 @@ public TupleToUserset() { /// /// Gets or Sets Tupleset /// - [DataMember(Name = "tupleset", EmitDefaultValue = false)] + [DataMember(Name = "tupleset", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("tupleset")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public ObjectRelation? Tupleset { get; set; } + public ObjectRelation Tupleset { get; set; } /// /// Gets or Sets ComputedUserset /// - [DataMember(Name = "computedUserset", EmitDefaultValue = false)] + [DataMember(Name = "computedUserset", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("computedUserset")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public ObjectRelation? ComputedUserset { get; set; } + public ObjectRelation ComputedUserset { get; set; } /// /// Gets or Sets additional properties diff --git a/src/OpenFga.Sdk/Model/TypeName.cs b/src/OpenFga.Sdk/Model/TypeName.cs new file mode 100644 index 0000000..d66a4bc --- /dev/null +++ b/src/OpenFga.Sdk/Model/TypeName.cs @@ -0,0 +1,97 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 0.1 +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://discord.gg/8naAwJfWN6 +// License: [Apache-2.0](https://github.com/openfga/dotnet-sdk/blob/main/LICENSE) +// +// NOTE: This file was auto generated. DO NOT EDIT. +// + + +using System.Runtime.Serialization; +using System.Text.Json.Serialization; + +namespace OpenFga.Sdk.Model { + /// + /// Defines TypeName + /// + [JsonConverter(typeof(JsonStringEnumMemberConverter))] + public enum TypeName { + /// + /// Enum UNSPECIFIED for value: TYPE_NAME_UNSPECIFIED + /// + [EnumMember(Value = "TYPE_NAME_UNSPECIFIED")] + UNSPECIFIED = 1, + + /// + /// Enum ANY for value: TYPE_NAME_ANY + /// + [EnumMember(Value = "TYPE_NAME_ANY")] + ANY = 2, + + /// + /// Enum BOOL for value: TYPE_NAME_BOOL + /// + [EnumMember(Value = "TYPE_NAME_BOOL")] + BOOL = 3, + + /// + /// Enum STRING for value: TYPE_NAME_STRING + /// + [EnumMember(Value = "TYPE_NAME_STRING")] + STRING = 4, + + /// + /// Enum INT for value: TYPE_NAME_INT + /// + [EnumMember(Value = "TYPE_NAME_INT")] + INT = 5, + + /// + /// Enum UINT for value: TYPE_NAME_UINT + /// + [EnumMember(Value = "TYPE_NAME_UINT")] + UINT = 6, + + /// + /// Enum DOUBLE for value: TYPE_NAME_DOUBLE + /// + [EnumMember(Value = "TYPE_NAME_DOUBLE")] + DOUBLE = 7, + + /// + /// Enum DURATION for value: TYPE_NAME_DURATION + /// + [EnumMember(Value = "TYPE_NAME_DURATION")] + DURATION = 8, + + /// + /// Enum TIMESTAMP for value: TYPE_NAME_TIMESTAMP + /// + [EnumMember(Value = "TYPE_NAME_TIMESTAMP")] + TIMESTAMP = 9, + + /// + /// Enum MAP for value: TYPE_NAME_MAP + /// + [EnumMember(Value = "TYPE_NAME_MAP")] + MAP = 10, + + /// + /// Enum LIST for value: TYPE_NAME_LIST + /// + [EnumMember(Value = "TYPE_NAME_LIST")] + LIST = 11, + + /// + /// Enum IPADDRESS for value: TYPE_NAME_IPADDRESS + /// + [EnumMember(Value = "TYPE_NAME_IPADDRESS")] + IPADDRESS = 12 + + } + +} \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/Users.cs b/src/OpenFga.Sdk/Model/Users.cs index 344a212..64370cf 100644 --- a/src/OpenFga.Sdk/Model/Users.cs +++ b/src/OpenFga.Sdk/Model/Users.cs @@ -33,8 +33,12 @@ public Users() { /// /// Initializes a new instance of the class. /// - /// users. + /// users (required). public Users(List users = default(List)) { + // to ensure "users" is required (not null) + if (users == null) { + throw new ArgumentNullException("users is a required property for Users and cannot be null"); + } this._Users = users; this.AdditionalProperties = new Dictionary(); } @@ -42,10 +46,10 @@ public Users() { /// /// Gets or Sets _Users /// - [DataMember(Name = "users", EmitDefaultValue = false)] + [DataMember(Name = "users", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("users")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public List? _Users { get; set; } + public List _Users { get; set; } /// /// Gets or Sets additional properties diff --git a/src/OpenFga.Sdk/Model/UsersetTreeDifference.cs b/src/OpenFga.Sdk/Model/UsersetTreeDifference.cs index ee94730..faa420c 100644 --- a/src/OpenFga.Sdk/Model/UsersetTreeDifference.cs +++ b/src/OpenFga.Sdk/Model/UsersetTreeDifference.cs @@ -33,10 +33,18 @@ public UsersetTreeDifference() { /// /// Initializes a new instance of the class. /// - /// _base. - /// subtract. + /// _base (required). + /// subtract (required). public UsersetTreeDifference(Node _base = default(Node), Node subtract = default(Node)) { + // to ensure "_base" is required (not null) + if (_base == null) { + throw new ArgumentNullException("_base is a required property for UsersetTreeDifference and cannot be null"); + } this.Base = _base; + // to ensure "subtract" is required (not null) + if (subtract == null) { + throw new ArgumentNullException("subtract is a required property for UsersetTreeDifference and cannot be null"); + } this.Subtract = subtract; this.AdditionalProperties = new Dictionary(); } @@ -44,18 +52,18 @@ public UsersetTreeDifference() { /// /// Gets or Sets Base /// - [DataMember(Name = "base", EmitDefaultValue = false)] + [DataMember(Name = "base", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("base")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public Node? Base { get; set; } + public Node Base { get; set; } /// /// Gets or Sets Subtract /// - [DataMember(Name = "subtract", EmitDefaultValue = false)] + [DataMember(Name = "subtract", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("subtract")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public Node? Subtract { get; set; } + public Node Subtract { get; set; } /// /// Gets or Sets additional properties diff --git a/src/OpenFga.Sdk/Model/UsersetTreeTupleToUserset.cs b/src/OpenFga.Sdk/Model/UsersetTreeTupleToUserset.cs index b40d159..f01a2c1 100644 --- a/src/OpenFga.Sdk/Model/UsersetTreeTupleToUserset.cs +++ b/src/OpenFga.Sdk/Model/UsersetTreeTupleToUserset.cs @@ -33,10 +33,18 @@ public UsersetTreeTupleToUserset() { /// /// Initializes a new instance of the class. /// - /// tupleset. - /// computed. + /// tupleset (required). + /// computed (required). public UsersetTreeTupleToUserset(string tupleset = default(string), List computed = default(List)) { + // to ensure "tupleset" is required (not null) + if (tupleset == null) { + throw new ArgumentNullException("tupleset is a required property for UsersetTreeTupleToUserset and cannot be null"); + } this.Tupleset = tupleset; + // to ensure "computed" is required (not null) + if (computed == null) { + throw new ArgumentNullException("computed is a required property for UsersetTreeTupleToUserset and cannot be null"); + } this.Computed = computed; this.AdditionalProperties = new Dictionary(); } @@ -44,18 +52,18 @@ public UsersetTreeTupleToUserset() { /// /// Gets or Sets Tupleset /// - [DataMember(Name = "tupleset", EmitDefaultValue = false)] + [DataMember(Name = "tupleset", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("tupleset")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public string? Tupleset { get; set; } + public string Tupleset { get; set; } /// /// Gets or Sets Computed /// - [DataMember(Name = "computed", EmitDefaultValue = false)] + [DataMember(Name = "computed", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("computed")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public List? Computed { get; set; } + public List Computed { get; set; } /// /// Gets or Sets additional properties diff --git a/src/OpenFga.Sdk/Model/Usersets.cs b/src/OpenFga.Sdk/Model/Usersets.cs index 72040df..c70ac14 100644 --- a/src/OpenFga.Sdk/Model/Usersets.cs +++ b/src/OpenFga.Sdk/Model/Usersets.cs @@ -33,8 +33,12 @@ public Usersets() { /// /// Initializes a new instance of the class. /// - /// child. + /// child (required). public Usersets(List child = default(List)) { + // to ensure "child" is required (not null) + if (child == null) { + throw new ArgumentNullException("child is a required property for Usersets and cannot be null"); + } this.Child = child; this.AdditionalProperties = new Dictionary(); } @@ -42,10 +46,10 @@ public Usersets() { /// /// Gets or Sets Child /// - [DataMember(Name = "child", EmitDefaultValue = false)] + [DataMember(Name = "child", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("child")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public List? Child { get; set; } + public List Child { get; set; } /// /// Gets or Sets additional properties diff --git a/src/OpenFga.Sdk/Model/WriteAuthorizationModelRequest.cs b/src/OpenFga.Sdk/Model/WriteAuthorizationModelRequest.cs index b51cbc2..0c5b3ec 100644 --- a/src/OpenFga.Sdk/Model/WriteAuthorizationModelRequest.cs +++ b/src/OpenFga.Sdk/Model/WriteAuthorizationModelRequest.cs @@ -34,14 +34,20 @@ public WriteAuthorizationModelRequest() { /// Initializes a new instance of the class. /// /// typeDefinitions (required). - /// schemaVersion. - public WriteAuthorizationModelRequest(List typeDefinitions = default(List), string schemaVersion = default(string)) { + /// schemaVersion (required). + /// conditions. + public WriteAuthorizationModelRequest(List typeDefinitions = default(List), string schemaVersion = default(string), Dictionary conditions = default(Dictionary)) { // to ensure "typeDefinitions" is required (not null) if (typeDefinitions == null) { throw new ArgumentNullException("typeDefinitions is a required property for WriteAuthorizationModelRequest and cannot be null"); } this.TypeDefinitions = typeDefinitions; + // to ensure "schemaVersion" is required (not null) + if (schemaVersion == null) { + throw new ArgumentNullException("schemaVersion is a required property for WriteAuthorizationModelRequest and cannot be null"); + } this.SchemaVersion = schemaVersion; + this.Conditions = conditions; this.AdditionalProperties = new Dictionary(); } @@ -56,10 +62,18 @@ public WriteAuthorizationModelRequest() { /// /// Gets or Sets SchemaVersion /// - [DataMember(Name = "schema_version", EmitDefaultValue = false)] + [DataMember(Name = "schema_version", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("schema_version")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public string? SchemaVersion { get; set; } + public string SchemaVersion { get; set; } + + /// + /// Gets or Sets Conditions + /// + [DataMember(Name = "conditions", EmitDefaultValue = false)] + [JsonPropertyName("conditions")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public Dictionary? Conditions { get; set; } /// /// Gets or Sets additional properties @@ -113,6 +127,12 @@ public bool Equals(WriteAuthorizationModelRequest input) { this.SchemaVersion == input.SchemaVersion || (this.SchemaVersion != null && this.SchemaVersion.Equals(input.SchemaVersion)) + ) && + ( + this.Conditions == input.Conditions || + this.Conditions != null && + input.Conditions != null && + this.Conditions.SequenceEqual(input.Conditions) ) && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); } @@ -131,6 +151,9 @@ public override int GetHashCode() { if (this.SchemaVersion != null) { hashCode = (hashCode * 9923) + this.SchemaVersion.GetHashCode(); } + if (this.Conditions != null) { + hashCode = (hashCode * 9923) + this.Conditions.GetHashCode(); + } if (this.AdditionalProperties != null) { hashCode = (hashCode * 9923) + this.AdditionalProperties.GetHashCode(); } diff --git a/src/OpenFga.Sdk/Model/WriteAuthorizationModelResponse.cs b/src/OpenFga.Sdk/Model/WriteAuthorizationModelResponse.cs index bce62fe..d40888a 100644 --- a/src/OpenFga.Sdk/Model/WriteAuthorizationModelResponse.cs +++ b/src/OpenFga.Sdk/Model/WriteAuthorizationModelResponse.cs @@ -33,8 +33,12 @@ public WriteAuthorizationModelResponse() { /// /// Initializes a new instance of the class. /// - /// authorizationModelId. + /// authorizationModelId (required). public WriteAuthorizationModelResponse(string authorizationModelId = default(string)) { + // to ensure "authorizationModelId" is required (not null) + if (authorizationModelId == null) { + throw new ArgumentNullException("authorizationModelId is a required property for WriteAuthorizationModelResponse and cannot be null"); + } this.AuthorizationModelId = authorizationModelId; this.AdditionalProperties = new Dictionary(); } @@ -42,10 +46,10 @@ public WriteAuthorizationModelResponse() { /// /// Gets or Sets AuthorizationModelId /// - [DataMember(Name = "authorization_model_id", EmitDefaultValue = false)] + [DataMember(Name = "authorization_model_id", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("authorization_model_id")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public string? AuthorizationModelId { get; set; } + public string AuthorizationModelId { get; set; } /// /// Gets or Sets additional properties diff --git a/src/OpenFga.Sdk/Model/WriteRequest.cs b/src/OpenFga.Sdk/Model/WriteRequest.cs index c9c0d5f..4a87b66 100644 --- a/src/OpenFga.Sdk/Model/WriteRequest.cs +++ b/src/OpenFga.Sdk/Model/WriteRequest.cs @@ -36,7 +36,7 @@ public WriteRequest() { /// writes. /// deletes. /// authorizationModelId. - public WriteRequest(TupleKeys writes = default(TupleKeys), TupleKeys deletes = default(TupleKeys), string authorizationModelId = default(string)) { + public WriteRequest(WriteRequestWrites writes = default(WriteRequestWrites), WriteRequestDeletes deletes = default(WriteRequestDeletes), string authorizationModelId = default(string)) { this.Writes = writes; this.Deletes = deletes; this.AuthorizationModelId = authorizationModelId; @@ -49,7 +49,7 @@ public WriteRequest() { [DataMember(Name = "writes", EmitDefaultValue = false)] [JsonPropertyName("writes")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public TupleKeys? Writes { get; set; } + public WriteRequestWrites? Writes { get; set; } /// /// Gets or Sets Deletes @@ -57,7 +57,7 @@ public WriteRequest() { [DataMember(Name = "deletes", EmitDefaultValue = false)] [JsonPropertyName("deletes")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public TupleKeys? Deletes { get; set; } + public WriteRequestDeletes? Deletes { get; set; } /// /// Gets or Sets AuthorizationModelId diff --git a/src/OpenFga.Sdk/Model/WriteRequestDeletes.cs b/src/OpenFga.Sdk/Model/WriteRequestDeletes.cs new file mode 100644 index 0000000..3f598c3 --- /dev/null +++ b/src/OpenFga.Sdk/Model/WriteRequestDeletes.cs @@ -0,0 +1,134 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 0.1 +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://discord.gg/8naAwJfWN6 +// License: [Apache-2.0](https://github.com/openfga/dotnet-sdk/blob/main/LICENSE) +// +// NOTE: This file was auto generated. DO NOT EDIT. +// + + +using System.ComponentModel.DataAnnotations; +using System.Runtime.Serialization; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace OpenFga.Sdk.Model { + /// + /// WriteRequestDeletes + /// + [DataContract(Name = "WriteRequestDeletes")] + public partial class WriteRequestDeletes : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public WriteRequestDeletes() { + this.AdditionalProperties = new Dictionary(); + } + + /// + /// Initializes a new instance of the class. + /// + /// tupleKeys (required). + public WriteRequestDeletes(List tupleKeys = default(List)) { + // to ensure "tupleKeys" is required (not null) + if (tupleKeys == null) { + throw new ArgumentNullException("tupleKeys is a required property for WriteRequestDeletes and cannot be null"); + } + this.TupleKeys = tupleKeys; + this.AdditionalProperties = new Dictionary(); + } + + /// + /// Gets or Sets TupleKeys + /// + [DataMember(Name = "tuple_keys", IsRequired = true, EmitDefaultValue = false)] + [JsonPropertyName("tuple_keys")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public List TupleKeys { get; set; } + + /// + /// Gets or Sets additional properties + /// + [JsonExtensionData] + public IDictionary AdditionalProperties { get; set; } + + + /// + /// Returns the JSON string presentation of the object + /// + /// JSON string presentation of the object + public virtual string ToJson() { + return JsonSerializer.Serialize(this); + } + + /// + /// Builds a WriteRequestDeletes from the JSON string presentation of the object + /// + /// WriteRequestDeletes + public static WriteRequestDeletes FromJson(string jsonString) { + return JsonSerializer.Deserialize(jsonString) ?? throw new InvalidOperationException(); + } + + /// + /// Returns true if objects are equal + /// + /// Object to be compared + /// Boolean + public override bool Equals(object input) { + return this.Equals(input as WriteRequestDeletes); + } + + /// + /// Returns true if WriteRequestDeletes instances are equal + /// + /// Instance of WriteRequestDeletes to be compared + /// Boolean + public bool Equals(WriteRequestDeletes input) { + if (input == null) { + return false; + } + return + ( + this.TupleKeys == input.TupleKeys || + this.TupleKeys != null && + input.TupleKeys != null && + this.TupleKeys.SequenceEqual(input.TupleKeys) + ) + && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + } + + /// + /// Gets the hash code + /// + /// Hash code + public override int GetHashCode() { + unchecked // Overflow is fine, just wrap + { + int hashCode = 9661; + if (this.TupleKeys != null) { + hashCode = (hashCode * 9923) + this.TupleKeys.GetHashCode(); + } + if (this.AdditionalProperties != null) { + hashCode = (hashCode * 9923) + this.AdditionalProperties.GetHashCode(); + } + return hashCode; + } + } + + /// + /// To validate all properties of the instance + /// + /// Validation context + /// Validation Result + public IEnumerable Validate(ValidationContext validationContext) { + yield break; + } + + } + +} \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/TupleKeys.cs b/src/OpenFga.Sdk/Model/WriteRequestWrites.cs similarity index 67% rename from src/OpenFga.Sdk/Model/TupleKeys.cs rename to src/OpenFga.Sdk/Model/WriteRequestWrites.cs index 877f395..24c4387 100644 --- a/src/OpenFga.Sdk/Model/TupleKeys.cs +++ b/src/OpenFga.Sdk/Model/WriteRequestWrites.cs @@ -18,38 +18,38 @@ namespace OpenFga.Sdk.Model { /// - /// TupleKeys + /// WriteRequestWrites /// - [DataContract(Name = "TupleKeys")] - public partial class TupleKeys : IEquatable, IValidatableObject { + [DataContract(Name = "WriteRequestWrites")] + public partial class WriteRequestWrites : IEquatable, IValidatableObject { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// [JsonConstructor] - public TupleKeys() { + public WriteRequestWrites() { this.AdditionalProperties = new Dictionary(); } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// tupleKeys (required). - public TupleKeys(List tupleKeys = default(List)) { + public WriteRequestWrites(List tupleKeys = default(List)) { // to ensure "tupleKeys" is required (not null) if (tupleKeys == null) { - throw new ArgumentNullException("tupleKeys is a required property for TupleKeys and cannot be null"); + throw new ArgumentNullException("tupleKeys is a required property for WriteRequestWrites and cannot be null"); } - this._TupleKeys = tupleKeys; + this.TupleKeys = tupleKeys; this.AdditionalProperties = new Dictionary(); } /// - /// Gets or Sets _TupleKeys + /// Gets or Sets TupleKeys /// [DataMember(Name = "tuple_keys", IsRequired = true, EmitDefaultValue = false)] [JsonPropertyName("tuple_keys")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public List _TupleKeys { get; set; } + public List TupleKeys { get; set; } /// /// Gets or Sets additional properties @@ -67,11 +67,11 @@ public virtual string ToJson() { } /// - /// Builds a TupleKeys from the JSON string presentation of the object + /// Builds a WriteRequestWrites from the JSON string presentation of the object /// - /// TupleKeys - public static TupleKeys FromJson(string jsonString) { - return JsonSerializer.Deserialize(jsonString) ?? throw new InvalidOperationException(); + /// WriteRequestWrites + public static WriteRequestWrites FromJson(string jsonString) { + return JsonSerializer.Deserialize(jsonString) ?? throw new InvalidOperationException(); } /// @@ -80,24 +80,24 @@ public static TupleKeys FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as TupleKeys); + return this.Equals(input as WriteRequestWrites); } /// - /// Returns true if TupleKeys instances are equal + /// Returns true if WriteRequestWrites instances are equal /// - /// Instance of TupleKeys to be compared + /// Instance of WriteRequestWrites to be compared /// Boolean - public bool Equals(TupleKeys input) { + public bool Equals(WriteRequestWrites input) { if (input == null) { return false; } return ( - this._TupleKeys == input._TupleKeys || - this._TupleKeys != null && - input._TupleKeys != null && - this._TupleKeys.SequenceEqual(input._TupleKeys) + this.TupleKeys == input.TupleKeys || + this.TupleKeys != null && + input.TupleKeys != null && + this.TupleKeys.SequenceEqual(input.TupleKeys) ) && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); } @@ -110,8 +110,8 @@ public override int GetHashCode() { unchecked // Overflow is fine, just wrap { int hashCode = 9661; - if (this._TupleKeys != null) { - hashCode = (hashCode * 9923) + this._TupleKeys.GetHashCode(); + if (this.TupleKeys != null) { + hashCode = (hashCode * 9923) + this.TupleKeys.GetHashCode(); } if (this.AdditionalProperties != null) { hashCode = (hashCode * 9923) + this.AdditionalProperties.GetHashCode(); diff --git a/src/OpenFga.Sdk/OpenFga.Sdk.csproj b/src/OpenFga.Sdk/OpenFga.Sdk.csproj index b7053af..cdd282e 100644 --- a/src/OpenFga.Sdk/OpenFga.Sdk.csproj +++ b/src/OpenFga.Sdk/OpenFga.Sdk.csproj @@ -12,7 +12,7 @@ .NET SDK for OpenFGA OpenFGA OpenFga.Sdk - 0.2.5 + 0.3.0 bin\$(Configuration)\$(TargetFramework)\OpenFga.Sdk.xml Apache-2.0 README.md