From 15c644f2d56dacf8eb8839d8456ffeaea9925865 Mon Sep 17 00:00:00 2001 From: Ryan Quinn Date: Thu, 1 May 2025 11:04:02 -0500 Subject: [PATCH 1/4] feat: support dotnet standard 2.0 --- CHANGELOG.md | 6 +- Makefile | 41 ++ OpenFga.Sdk.sln | 6 +- README.md | 77 ++-- docs/Assertion.md | 2 + docs/AuthErrorCode.md | 9 + docs/BatchCheckItem.md | 13 + docs/BatchCheckRequest.md | 12 + docs/BatchCheckResponse.md | 10 + docs/BatchCheckSingleResult.md | 11 + docs/CheckError.md | 12 + docs/ConsistencyPreference.md | 2 +- docs/ExpandRequest.md | 1 + docs/ForbiddenResponse.md | 11 + docs/OpenFgaApi.md | 116 ++++- example/Example1/Example1.cs | 148 ++----- example/Example1/Example1.csproj | 9 +- .../FrameworkCompatibilityTests.cs | 91 ++++ .../OpenFga.Sdk.Test.Framework.csproj | 25 ++ .../NetCore31CompatibilityTests.cs | 89 ++++ .../OpenFga.Sdk.Test.NetCore31.csproj | 25 ++ src/OpenFga.Sdk.Test/Api/OpenFgaApiTests.cs | 65 +-- .../Client/OpenFgaClientTests.cs | 91 ++-- .../FrameworkCompatibility/FrameworkTests.cs | 66 +++ .../Helpers/FrameworkCompat.cs | 93 ++++ src/OpenFga.Sdk.Test/Models/ModelTests.cs | 6 +- src/OpenFga.Sdk.Test/OpenFga.Sdk.Test.csproj | 10 +- src/OpenFga.Sdk/Api/OpenFgaApi.cs | 50 ++- src/OpenFga.Sdk/ApiClient/ApiClient.cs | 4 +- src/OpenFga.Sdk/ApiClient/BaseClient.cs | 10 +- src/OpenFga.Sdk/ApiClient/OAuth2Client.cs | 1 - src/OpenFga.Sdk/ApiClient/RequestBuilder.cs | 3 - src/OpenFga.Sdk/ApiClient/Utils.cs | 5 - src/OpenFga.Sdk/Client/Client.cs | 123 +++--- src/OpenFga.Sdk/Client/ClientConfiguration.cs | 1 - src/OpenFga.Sdk/Client/ClientExtensions.cs | 59 +++ .../Client/DictionaryExtensions.cs | 35 ++ .../Client/Model/ClientBatchCheckResponse.cs | 19 +- .../Client/Model/ClientCheckRequest.cs | 6 - .../Client/Model/ClientExpandRequest.cs | 6 - .../Client/Model/ClientListObjectsRequest.cs | 6 - .../Model/ClientListRelationsRequest.cs | 6 - .../Model/ClientListRelationsResponse.cs | 4 - .../Client/Model/ClientListUsersRequest.cs | 4 - .../Client/Model/ClientReadChangesRequest.cs | 6 +- .../Client/Model/ClientTupleKey.cs | 4 - .../Model/ClientTupleKeyWithoutCondition.cs | 4 - .../Model/ClientWriteAssertionsRequest.cs | 6 - .../Client/Model/ClientWriteRequest.cs | 4 - .../Client/Model/ClientWriteResponse.cs | 4 - .../Client/Model/ClientWriteStatus.cs | 4 - .../Configuration/Configuration.cs | 2 +- src/OpenFga.Sdk/Configuration/Credentials.cs | 1 - .../Configuration/TelemetryConfig.cs | 40 +- .../Exceptions/ApiAuthenticationError.cs | 1 - src/OpenFga.Sdk/Exceptions/ApiError.cs | 5 +- src/OpenFga.Sdk/Exceptions/ApiException.cs | 48 ++- .../Exceptions/Parsers/ApiErrorParser.cs | 4 - .../Exceptions/Parsers/RateLimitParser.cs | 4 - src/OpenFga.Sdk/GlobalUsings.cs | 28 ++ .../Model/AbortedMessageResponse.cs | 6 - src/OpenFga.Sdk/Model/Any.cs | 6 - src/OpenFga.Sdk/Model/Assertion.cs | 46 +- src/OpenFga.Sdk/Model/AssertionTupleKey.cs | 6 - src/OpenFga.Sdk/Model/AuthErrorCode.cs | 75 ++++ src/OpenFga.Sdk/Model/AuthorizationModel.cs | 6 - src/OpenFga.Sdk/Model/BatchCheckItem.cs | 186 ++++++++ src/OpenFga.Sdk/Model/BatchCheckRequest.cs | 160 +++++++ src/OpenFga.Sdk/Model/BatchCheckResponse.cs | 125 ++++++ .../Model/BatchCheckSingleResult.cs | 138 ++++++ src/OpenFga.Sdk/Model/CheckError.cs | 151 +++++++ src/OpenFga.Sdk/Model/CheckRequest.cs | 6 - src/OpenFga.Sdk/Model/CheckRequestTupleKey.cs | 6 - src/OpenFga.Sdk/Model/CheckResponse.cs | 6 - src/OpenFga.Sdk/Model/Computed.cs | 6 - src/OpenFga.Sdk/Model/Condition.cs | 6 - src/OpenFga.Sdk/Model/ConditionMetadata.cs | 6 - .../Model/ConditionParamTypeRef.cs | 6 - .../Model/ConsistencyPreference.cs | 8 +- src/OpenFga.Sdk/Model/ContextualTupleKeys.cs | 6 - src/OpenFga.Sdk/Model/CreateStoreRequest.cs | 6 - src/OpenFga.Sdk/Model/CreateStoreResponse.cs | 6 - src/OpenFga.Sdk/Model/Difference.cs | 6 - src/OpenFga.Sdk/Model/ErrorCode.cs | 18 +- src/OpenFga.Sdk/Model/ExpandRequest.cs | 26 +- .../Model/ExpandRequestTupleKey.cs | 6 - src/OpenFga.Sdk/Model/ExpandResponse.cs | 6 - src/OpenFga.Sdk/Model/FgaObject.cs | 6 - src/OpenFga.Sdk/Model/ForbiddenResponse.cs | 137 ++++++ src/OpenFga.Sdk/Model/GetStoreResponse.cs | 6 - src/OpenFga.Sdk/Model/InternalErrorCode.cs | 26 +- .../Model/InternalErrorMessageResponse.cs | 6 - .../Model/JsonStringEnumMemberConverter.cs | 5 +- src/OpenFga.Sdk/Model/Leaf.cs | 6 - src/OpenFga.Sdk/Model/ListObjectsRequest.cs | 6 - src/OpenFga.Sdk/Model/ListObjectsResponse.cs | 6 - src/OpenFga.Sdk/Model/ListStoresResponse.cs | 6 - src/OpenFga.Sdk/Model/ListUsersRequest.cs | 6 - src/OpenFga.Sdk/Model/ListUsersResponse.cs | 6 - src/OpenFga.Sdk/Model/Metadata.cs | 6 - src/OpenFga.Sdk/Model/Node.cs | 6 - src/OpenFga.Sdk/Model/Nodes.cs | 6 - src/OpenFga.Sdk/Model/NotFoundErrorCode.cs | 4 - src/OpenFga.Sdk/Model/NullValue.cs | 4 - src/OpenFga.Sdk/Model/ObjectRelation.cs | 6 - .../Model/PathUnknownErrorMessageResponse.cs | 6 - .../Model/ReadAssertionsResponse.cs | 6 - .../Model/ReadAuthorizationModelResponse.cs | 6 - .../Model/ReadAuthorizationModelsResponse.cs | 6 - src/OpenFga.Sdk/Model/ReadChangesResponse.cs | 6 - src/OpenFga.Sdk/Model/ReadRequest.cs | 16 +- src/OpenFga.Sdk/Model/ReadRequestTupleKey.cs | 6 - src/OpenFga.Sdk/Model/ReadResponse.cs | 6 - src/OpenFga.Sdk/Model/RelationMetadata.cs | 6 - src/OpenFga.Sdk/Model/RelationReference.cs | 6 - .../Model/RelationshipCondition.cs | 6 - src/OpenFga.Sdk/Model/SourceInfo.cs | 6 - src/OpenFga.Sdk/Model/Status.cs | 6 - src/OpenFga.Sdk/Model/Store.cs | 6 - src/OpenFga.Sdk/Model/Tuple.cs | 6 - src/OpenFga.Sdk/Model/TupleChange.cs | 6 - src/OpenFga.Sdk/Model/TupleKey.cs | 6 - .../Model/TupleKeyWithoutCondition.cs | 6 - src/OpenFga.Sdk/Model/TupleOperation.cs | 4 - src/OpenFga.Sdk/Model/TupleToUserset.cs | 6 - src/OpenFga.Sdk/Model/TypeDefinition.cs | 6 - src/OpenFga.Sdk/Model/TypeName.cs | 130 +++--- src/OpenFga.Sdk/Model/TypedWildcard.cs | 6 - .../Model/UnauthenticatedResponse.cs | 6 - .../Model/UnprocessableContentErrorCode.cs | 4 - .../UnprocessableContentMessageResponse.cs | 6 - src/OpenFga.Sdk/Model/User.cs | 6 - src/OpenFga.Sdk/Model/UserTypeFilter.cs | 6 - src/OpenFga.Sdk/Model/Users.cs | 6 - src/OpenFga.Sdk/Model/Userset.cs | 6 - src/OpenFga.Sdk/Model/UsersetTree.cs | 6 - .../Model/UsersetTreeDifference.cs | 6 - .../Model/UsersetTreeTupleToUserset.cs | 6 - src/OpenFga.Sdk/Model/UsersetUser.cs | 6 - src/OpenFga.Sdk/Model/Usersets.cs | 6 - .../Model/ValidationErrorMessageResponse.cs | 6 - .../Model/WriteAssertionsRequest.cs | 6 - .../Model/WriteAuthorizationModelRequest.cs | 6 - .../Model/WriteAuthorizationModelResponse.cs | 6 - src/OpenFga.Sdk/Model/WriteRequest.cs | 6 - src/OpenFga.Sdk/Model/WriteRequestDeletes.cs | 6 - src/OpenFga.Sdk/Model/WriteRequestWrites.cs | 6 - .../Net/HttpStatusCodeExtensions.cs | 29 ++ src/OpenFga.Sdk/OpenFga.Sdk.csproj | 14 +- src/OpenFga.Sdk/Telemetry/Attributes.cs | 402 ++++++++++-------- src/OpenFga.Sdk/Telemetry/Counters.cs | 4 - src/OpenFga.Sdk/Telemetry/Histograms.cs | 1 - src/OpenFga.Sdk/Telemetry/Meters.cs | 13 +- src/OpenFga.Sdk/Telemetry/Metrics.cs | 1 - .../Telemetry/Standard20TelemetryTypes.cs | 99 +++++ 155 files changed, 2577 insertions(+), 1211 deletions(-) create mode 100644 Makefile create mode 100644 docs/AuthErrorCode.md create mode 100644 docs/BatchCheckItem.md create mode 100644 docs/BatchCheckRequest.md create mode 100644 docs/BatchCheckResponse.md create mode 100644 docs/BatchCheckSingleResult.md create mode 100644 docs/CheckError.md create mode 100644 docs/ForbiddenResponse.md create mode 100644 src/OpenFga.Sdk.Test.Framework/FrameworkCompatibilityTests.cs create mode 100644 src/OpenFga.Sdk.Test.Framework/OpenFga.Sdk.Test.Framework.csproj create mode 100644 src/OpenFga.Sdk.Test.NetCore31/NetCore31CompatibilityTests.cs create mode 100644 src/OpenFga.Sdk.Test.NetCore31/OpenFga.Sdk.Test.NetCore31.csproj create mode 100644 src/OpenFga.Sdk.Test/FrameworkCompatibility/FrameworkTests.cs create mode 100644 src/OpenFga.Sdk.Test/Helpers/FrameworkCompat.cs create mode 100644 src/OpenFga.Sdk/Client/ClientExtensions.cs create mode 100644 src/OpenFga.Sdk/Client/DictionaryExtensions.cs create mode 100644 src/OpenFga.Sdk/GlobalUsings.cs create mode 100644 src/OpenFga.Sdk/Model/AuthErrorCode.cs create mode 100644 src/OpenFga.Sdk/Model/BatchCheckItem.cs create mode 100644 src/OpenFga.Sdk/Model/BatchCheckRequest.cs create mode 100644 src/OpenFga.Sdk/Model/BatchCheckResponse.cs create mode 100644 src/OpenFga.Sdk/Model/BatchCheckSingleResult.cs create mode 100644 src/OpenFga.Sdk/Model/CheckError.cs create mode 100644 src/OpenFga.Sdk/Model/ForbiddenResponse.cs create mode 100644 src/OpenFga.Sdk/Net/HttpStatusCodeExtensions.cs create mode 100644 src/OpenFga.Sdk/Telemetry/Standard20TelemetryTypes.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index f1528c3..7e01224 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## [Unreleased](https://github.com/openfga/dotnet-sdk/compare/v0.5.1...HEAD) + +- feat: add support for `start_time` parameter in `ReadChanges` endpoint + ## v0.5.1 ### [0.5.1](https://github.com/openfga/dotnet-sdk/compare/v0.5.0...v0.5.1) (2024-09-09) @@ -136,7 +140,7 @@ Updated to include support for [OpenFGA 0.3.0](https://github.com/openfga/openfg Changes: - [BREAKING] feat(list-objects)!: response has been changed to include the object type - e.g. response that was `{"object_ids":["roadmap"]}`, will now be `{"objects":["document:roadmap"]}` + e.g. response that was `{"object_ids":["roadmap"]}`, will now be `{"objects":["document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a"]}` Fixes: - fix(models): update interfaces that had incorrectly optional fields to make them required diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..62e5991 --- /dev/null +++ b/Makefile @@ -0,0 +1,41 @@ +ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) + +# Main test target - runs .NET 6.0 tests for CI/CD +.PHONY: test +test: + dotnet test $(ROOT_DIR)/src/OpenFga.Sdk.Test/OpenFga.Sdk.Test.csproj + +# NOTE: These framework-specific tests require the appropriate .NET environment: +# - test-framework: Requires Windows or Mono with full xUnit support +# - test-netcore31: Requires .NET Core 3.1 SDK + +# Test .NET Framework 4.8 compatibility using Mono +.PHONY: test-framework +test-framework: + @if command -v mono >/dev/null 2>&1; then \ + cd $(ROOT_DIR)/src/OpenFga.Sdk.Test.Framework && \ + dotnet build -c Debug && \ + mono /xunit/xunit.runner.console.2.1.0/tools/xunit.console.exe \ + $(ROOT_DIR)/src/OpenFga.Sdk.Test.Framework/bin/Debug/net48/OpenFga.Sdk.Test.Framework.dll; \ + else \ + echo "Mono is not installed. Skipping .NET Framework tests."; \ + exit 0; \ + fi + +# Test .NET Core 3.1 compatibility +.PHONY: test-netcore31 +test-netcore31: + dotnet test $(ROOT_DIR)/src/OpenFga.Sdk.Test.NetCore31/OpenFga.Sdk.Test.NetCore31.csproj + +# Run all tests - Note: Will only fully succeed on a Windows environment with all .NET versions installed +.PHONY: test-all +test-all: test + @echo "To run framework-specific tests, use 'make test-framework' and 'make test-netcore31' on appropriate environments" + +.PHONY: build +build: + dotnet build $(ROOT_DIR)/src/OpenFga.Sdk/OpenFga.Sdk.csproj + +.PHONY: pack +pack: + dotnet pack $(ROOT_DIR)/src/OpenFga.Sdk/OpenFga.Sdk.csproj -c Release \ No newline at end of file diff --git a/OpenFga.Sdk.sln b/OpenFga.Sdk.sln index 8b59a38..ec5b6b7 100644 --- a/OpenFga.Sdk.sln +++ b/OpenFga.Sdk.sln @@ -1,7 +1,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 -VisualStudioVersion = 12.0.0.0 -MinimumVisualStudioVersion = 10.0.0.1 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 Project("{59de7a42-91d3-40f9-b967-84ff8236d62a}") = "OpenFga.Sdk", "src\OpenFga.Sdk\OpenFga.Sdk.csproj", "{b8d9e3e9-0156-4948-9de7-5e0d3f9c4d9e}" EndProject Project("{59de7a42-91d3-40f9-b967-84ff8236d62a}") = "OpenFga.Sdk.Test", "src\OpenFga.Sdk.Test\OpenFga.Sdk.Test.csproj", "{d119dfae-509a-4eba-a973-645b739356fc}" diff --git a/README.md b/README.md index a376d7a..059acca 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ Search for and install `OpenFga.Sdk` in each of their respective package manager We strongly recommend you initialize the `OpenFgaClient` only once and then re-use it throughout your app, otherwise you will incur the cost of having to re-initialize multiple times or at every request, the cost of reduced connection pooling and re-use, and would be particularly costly in the client credentials flow, as that flow will be preformed on every request. -> The `OpenFga.SdkClient` will by default retry API requests up to 15 times on 429 and 5xx errors. +> The `OpenFga.SdkClient` will by default retry API requests up to 3 times on 429 and 5xx errors. #### No Credentials @@ -379,7 +379,8 @@ Reads the list of historical relationship tuple writes and deletes. [API Documentation](https://openfga.dev/api/service#/Relationship%20Tuples/ReadChanges) ```csharp -var body = new ClientReadChangesRequest { Type = "document" }; +var startTime = DateTime.Parse("2022-01-01T00:00:00Z"); +var body = new ClientReadChangesRequest { Type = "document", StartTime = startTime }; var options = new ClientReadChangesOptions { PageSize = 10, ContinuationToken = "...", @@ -405,13 +406,13 @@ Reads the relationship tuples stored in the database. It does not evaluate nor e var body = new ClientReadRequest() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", }; // Find all relationship tuples where a certain user has a relationship as any relation to a certain document var body = new ClientReadRequest() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", }; // Find all relationship tuples where a certain user is a viewer of any document @@ -424,7 +425,7 @@ var body = new ClientReadRequest() { // Find all relationship tuples where any user has a relationship as any relation with a particular document var body = new ClientReadRequest() { - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", }; // Read all stored relationship tuples @@ -457,19 +458,19 @@ var body = new ClientWriteRequest() { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", }, new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:budget", + Object = "document:0192ab2d-d36e-7cb3-a4a8-5d1d67a300c5", } }, Deletes = new List { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "writer", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", } }, }; @@ -492,19 +493,19 @@ var body = new ClientWriteRequest() { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", }, new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:budget", + Object = "document:0192ab2d-d36e-7cb3-a4a8-5d1d67a300c5", } }, Deletes = new List { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "writer", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", } }, }; @@ -536,7 +537,7 @@ var options = new ClientCheckOptions { var body = new ClientCheckRequest { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "writer", - Object = "document:roadmap" + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }; var response = await fgaClient.Check(body, options); // response.Allowed = true @@ -545,7 +546,7 @@ var response = await fgaClient.Check(body, options); ##### Batch Check Run a set of [checks](#check). Batch Check will return `allowed: false` if it encounters an error, and will return the error in the body. -If 429s or 5xxs are encountered, the underlying check will retry up to 15 times before giving up. +If 429s or 5xxs are encountered, the underlying check will retry up to 3 times before giving up. ```csharp var options = new ClientBatchCheckOptions { @@ -557,36 +558,36 @@ var body = new List(){ new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", ContextualTuples = new List() { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "editor", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", } }, }, new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "admin", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", ContextualTuples = new List() { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "editor", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", } }, }, new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "creator", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", }, new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "deleter", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", } }; @@ -598,11 +599,11 @@ response.Responses = [{ Request: { User: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation: "viewer", - Object: "document:roadmap", + Object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", ContextualTuples: [{ User: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation: "editor", - Object: "document:roadmap" + Object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }] } }, { @@ -610,11 +611,11 @@ response.Responses = [{ Request: { User: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation: "admin", - Object: "document:roadmap", + Object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", ContextualTuples: [{ User: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation: "editor", - Object: "document:roadmap" + Object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }] } }, { @@ -622,7 +623,7 @@ response.Responses = [{ Request: { User: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation: "creator", - Object: "document:roadmap", + Object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", }, Error: }, { @@ -630,7 +631,7 @@ response.Responses = [{ Request: { User: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation: "deleter", - Object: "document:roadmap", + Object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", }}, ] */ @@ -649,11 +650,11 @@ var options = new ClientCheckOptions { }; var body = new ClientExpandRequest { Relation = "viewer", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", }; var response = await fgaClient.Expand(body, options); -// response.Tree.Root = {"name":"document:roadmap#viewer","leaf":{"users":{"users":["user:81684243-9356-4421-8fbf-a4f8d36aa31b","user:f52a4f7a-054d-47ff-bb6e-3ac81269988f"]}}} +// response.Tree.Root = {"name":"document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#viewer","leaf":{"users":{"users":["user:81684243-9356-4421-8fbf-a4f8d36aa31b","user:f52a4f7a-054d-47ff-bb6e-3ac81269988f"]}}} ``` ##### List Objects @@ -675,13 +676,13 @@ var body = new ClientListObjectsRequest { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "writer", - Object = "document:budget", + Object = "document:0192ab2d-d36e-7cb3-a4a8-5d1d67a300c5", }, }, }; var response = await fgaClient.ListObjects(body, options); -// response.Objects = ["document:roadmap"] +// response.Objects = ["document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a"] ``` ##### List Relations @@ -692,13 +693,13 @@ List the relations a user has on an object. ListRelationsRequest body = new ListRelationsRequest() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", Relations = new List {"can_view", "can_edit", "can_delete", "can_rename"}, ContextualTuples = new List() { new ClientTupleKey { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "editor", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", } } }; @@ -742,7 +743,7 @@ const response = await fgaClient.listUsers({ }, { user: "folder:product", relation: "parent", - object: "document:roadmap" + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }] }, options); @@ -779,7 +780,7 @@ var options = new ClientWriteAssertionsOptions { var body = new List() {new ClientAssertion() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", Expectation = true, }}; await fgaClient.WriteAssertions(body, options); @@ -788,7 +789,7 @@ await fgaClient.WriteAssertions(body, options); ### Retries -If a network request fails with a 429 or 5xx error from the server, the SDK will automatically retry the request up to 15 times with a minimum wait time of 100 milliseconds between each attempt. +If a network request fails with a 429 or 5xx error from the server, the SDK will automatically retry the request up to 3 times with a minimum wait time of 100 milliseconds between each attempt. To customize this behavior, create a `RetryParams` instance and assign values to the `MaxRetry` and `MinWaitInMs` constructor parameters. `MaxRetry` determines the maximum number of retries (up to 15), while `MinWaitInMs` sets the minimum wait time between retries in milliseconds. @@ -826,6 +827,7 @@ namespace Example { | Method | HTTP request | Description | | ------------- | ------------- | ------------- | +| [**BatchCheck**](docs/OpenFgaApi.md#batchcheck) | **POST** /stores/{store_id}/batch-check | Send a list of `check` operations in a single request | | [**Check**](docs/OpenFgaApi.md#check) | **POST** /stores/{store_id}/check | Check whether a user is authorized to access an object | | [**CreateStore**](docs/OpenFgaApi.md#createstore) | **POST** /stores | Create a store | | [**DeleteStore**](docs/OpenFgaApi.md#deletestore) | **DELETE** /stores/{store_id} | Delete a store | @@ -851,7 +853,13 @@ namespace Example { - [Model.Any](docs/Any.md) - [Model.Assertion](docs/Assertion.md) - [Model.AssertionTupleKey](docs/AssertionTupleKey.md) + - [Model.AuthErrorCode](docs/AuthErrorCode.md) - [Model.AuthorizationModel](docs/AuthorizationModel.md) + - [Model.BatchCheckItem](docs/BatchCheckItem.md) + - [Model.BatchCheckRequest](docs/BatchCheckRequest.md) + - [Model.BatchCheckResponse](docs/BatchCheckResponse.md) + - [Model.BatchCheckSingleResult](docs/BatchCheckSingleResult.md) + - [Model.CheckError](docs/CheckError.md) - [Model.CheckRequest](docs/CheckRequest.md) - [Model.CheckRequestTupleKey](docs/CheckRequestTupleKey.md) - [Model.CheckResponse](docs/CheckResponse.md) @@ -869,6 +877,7 @@ namespace Example { - [Model.ExpandRequestTupleKey](docs/ExpandRequestTupleKey.md) - [Model.ExpandResponse](docs/ExpandResponse.md) - [Model.FgaObject](docs/FgaObject.md) + - [Model.ForbiddenResponse](docs/ForbiddenResponse.md) - [Model.GetStoreResponse](docs/GetStoreResponse.md) - [Model.InternalErrorCode](docs/InternalErrorCode.md) - [Model.InternalErrorMessageResponse](docs/InternalErrorMessageResponse.md) diff --git a/docs/Assertion.md b/docs/Assertion.md index 2a6031b..a2b5459 100644 --- a/docs/Assertion.md +++ b/docs/Assertion.md @@ -6,6 +6,8 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **TupleKey** | [**AssertionTupleKey**](AssertionTupleKey.md) | | **Expectation** | **bool** | | +**ContextualTuples** | [**List<TupleKey>**](TupleKey.md) | | [optional] +**Context** | **Object** | Additional request context that will be used to evaluate any ABAC conditions encountered in the query evaluation. | [optional] [[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) diff --git a/docs/AuthErrorCode.md b/docs/AuthErrorCode.md new file mode 100644 index 0000000..13d0f01 --- /dev/null +++ b/docs/AuthErrorCode.md @@ -0,0 +1,9 @@ +# OpenFga.Sdk.Model.AuthErrorCode + +## 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/BatchCheckItem.md b/docs/BatchCheckItem.md new file mode 100644 index 0000000..5601197 --- /dev/null +++ b/docs/BatchCheckItem.md @@ -0,0 +1,13 @@ +# OpenFga.Sdk.Model.BatchCheckItem + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**TupleKey** | [**CheckRequestTupleKey**](CheckRequestTupleKey.md) | | +**ContextualTuples** | [**ContextualTupleKeys**](ContextualTupleKeys.md) | | [optional] +**Context** | **Object** | | [optional] +**CorrelationId** | **string** | correlation_id must be a string containing only letters, numbers, or hyphens, with length ≤ 36 characters. | + +[[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md) + diff --git a/docs/BatchCheckRequest.md b/docs/BatchCheckRequest.md new file mode 100644 index 0000000..84b7445 --- /dev/null +++ b/docs/BatchCheckRequest.md @@ -0,0 +1,12 @@ +# OpenFga.Sdk.Model.BatchCheckRequest + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Checks** | [**List<BatchCheckItem>**](BatchCheckItem.md) | | +**AuthorizationModelId** | **string** | | [optional] +**Consistency** | **ConsistencyPreference** | | [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/BatchCheckResponse.md b/docs/BatchCheckResponse.md new file mode 100644 index 0000000..cee0442 --- /dev/null +++ b/docs/BatchCheckResponse.md @@ -0,0 +1,10 @@ +# OpenFga.Sdk.Model.BatchCheckResponse + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Result** | [**Dictionary<string, BatchCheckSingleResult>**](BatchCheckSingleResult.md) | map keys are the correlation_id values from the BatchCheckItems in the request | [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/BatchCheckSingleResult.md b/docs/BatchCheckSingleResult.md new file mode 100644 index 0000000..f39bbb4 --- /dev/null +++ b/docs/BatchCheckSingleResult.md @@ -0,0 +1,11 @@ +# OpenFga.Sdk.Model.BatchCheckSingleResult + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Allowed** | **bool** | | [optional] +**Error** | [**CheckError**](CheckError.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/CheckError.md b/docs/CheckError.md new file mode 100644 index 0000000..f150536 --- /dev/null +++ b/docs/CheckError.md @@ -0,0 +1,12 @@ +# OpenFga.Sdk.Model.CheckError + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**InputError** | **ErrorCode** | | [optional] +**InternalError** | **InternalErrorCode** | | [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/ConsistencyPreference.md b/docs/ConsistencyPreference.md index 4c95048..c6049be 100644 --- a/docs/ConsistencyPreference.md +++ b/docs/ConsistencyPreference.md @@ -1,5 +1,5 @@ # OpenFga.Sdk.Model.ConsistencyPreference -- UNSPECIFIED: Default if not set. Behavior will be the same as MINIMIZE_LATENCY - MINIMIZE_LATENCY: Minimize latency at the potential expense of lower consistency. - HIGHER_CONSISTENCY: Prefer higher consistency, at the potential expense of increased latency. +Controls the consistency preferences when calling the query APIs. - UNSPECIFIED: Default if not set. Behavior will be the same as MINIMIZE_LATENCY. - MINIMIZE_LATENCY: Minimize latency at the potential expense of lower consistency. - HIGHER_CONSISTENCY: Prefer higher consistency, at the potential expense of increased latency. ## Properties diff --git a/docs/ExpandRequest.md b/docs/ExpandRequest.md index f09f08e..0ac8ea4 100644 --- a/docs/ExpandRequest.md +++ b/docs/ExpandRequest.md @@ -7,6 +7,7 @@ Name | Type | Description | Notes **TupleKey** | [**ExpandRequestTupleKey**](ExpandRequestTupleKey.md) | | **AuthorizationModelId** | **string** | | [optional] **Consistency** | **ConsistencyPreference** | | [optional] +**ContextualTuples** | [**ContextualTupleKeys**](ContextualTupleKeys.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/ForbiddenResponse.md b/docs/ForbiddenResponse.md new file mode 100644 index 0000000..1d51214 --- /dev/null +++ b/docs/ForbiddenResponse.md @@ -0,0 +1,11 @@ +# OpenFga.Sdk.Model.ForbiddenResponse + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Code** | **AuthErrorCode** | | [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/OpenFgaApi.md b/docs/OpenFgaApi.md index 0e34e98..60361b3 100644 --- a/docs/OpenFgaApi.md +++ b/docs/OpenFgaApi.md @@ -4,6 +4,7 @@ All URIs are relative to *http://localhost* Method | HTTP request | Description ------------- | ------------- | ------------- +[**BatchCheck**](OpenFgaApi.md#batchcheck) | **POST** /stores/{store_id}/batch-check | Send a list of `check` operations in a single request [**Check**](OpenFgaApi.md#check) | **POST** /stores/{store_id}/check | Check whether a user is authorized to access an object [**CreateStore**](OpenFgaApi.md#createstore) | **POST** /stores | Create a store [**DeleteStore**](OpenFgaApi.md#deletestore) | **DELETE** /stores/{store_id} | Delete a store @@ -22,13 +23,94 @@ Method | HTTP request | Description [**WriteAuthorizationModel**](OpenFgaApi.md#writeauthorizationmodel) | **POST** /stores/{store_id}/authorization-models | Create a new authorization model + +# **BatchCheck** +> BatchCheckResponse BatchCheck (BatchCheckRequest body) + +Send a list of `check` operations in a single request + +The `BatchCheck` API functions nearly identically to `Check`, but instead of checking a single user-object relationship BatchCheck accepts a list of relationships to check and returns a map containing `BatchCheckItem` response for each check it received. An associated `correlation_id` is required for each check in the batch. This ID is used to correlate a check to the appropriate response. It is a string consisting of only alphanumeric characters or hyphens with a maximum length of 36 characters. This `correlation_id` is used to map the result of each check to the item which was checked, so it must be unique for each item in the batch. We recommend using a UUID or ULID as the `correlation_id`, but you can use whatever unique identifier you need as long as it matches this regex pattern: `^[\\w\\d-]{1,36}$` For more details on how `Check` functions, see the docs for `/check`. ### Examples #### A BatchCheckRequest ```json { \"checks\": [ { \"tuple_key\": { \"object\": \"document:2021-budget\" \"relation\": \"reader\", \"user\": \"user:anne\", }, \"contextual_tuples\": {...} \"context\": {} \"correlation_id\": \"01JA8PM3QM7VBPGB8KMPK8SBD5\" }, { \"tuple_key\": { \"object\": \"document:2021-budget\" \"relation\": \"reader\", \"user\": \"user:bob\", }, \"contextual_tuples\": {...} \"context\": {} \"correlation_id\": \"01JA8PMM6A90NV5ET0F28CYSZQ\" } ] } ``` Below is a possible response to the above request. Note that the result map's keys are the `correlation_id` values from the checked items in the request: ```json { \"result\": { \"01JA8PMM6A90NV5ET0F28CYSZQ\": { \"allowed\": false, \"error\": {\"message\": \"\"} }, \"01JA8PM3QM7VBPGB8KMPK8SBD5\": { \"allowed\": true, \"error\": {\"message\": \"\"} } } ``` + +### Example +```csharp +using System.Collections.Generic; +using System.Diagnostics; +using System.Net.Http; +using OpenFga.Sdk.Api; +using OpenFga.Sdk.Client; +using OpenFga.Sdk.Configuration; +using OpenFga.Sdk.Model; + +namespace Example +{ + public class BatchCheckExample + { + public static void Main() + { + var configuration = new Configuration() { + 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` + }; + HttpClient httpClient = new HttpClient(); + var openFgaApi = new OpenFgaApi(config, httpClient); + var body = new BatchCheckRequest(); // BatchCheckRequest | + + try + { + // Send a list of `check` operations in a single request + BatchCheckResponse response = await openFgaApi.BatchCheck(body); + Debug.WriteLine(response); + } + catch (ApiException e) + { + Debug.Print("Exception when calling OpenFgaApi.BatchCheck: " + e.Message ); + Debug.Print("Status Code: "+ e.ErrorCode); + Debug.Print(e.StackTrace); + } + } + } +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + + **body** | [**BatchCheckRequest**](BatchCheckRequest.md)| | + +### Return type + +[**BatchCheckResponse**](BatchCheckResponse.md) + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json + + +### HTTP response details +| Status code | Description | Response headers | +|-------------|-------------|------------------| +| **200** | A successful response. | - | +| **400** | Request failed due to invalid input. | - | +| **401** | Not authenticated. | - | +| **403** | Forbidden. | - | +| **404** | Request failed due to incorrect path. | - | +| **409** | Request was aborted due a transaction conflict. | - | +| **422** | Request timed out due to excessive request throttling. | - | +| **500** | Request failed due to internal server error. | - | + +[[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) + # **Check** > CheckResponse Check (CheckRequest body) Check whether a user is authorized to access an object -The Check API returns whether a given user has a relationship with a given object in a given store. The `user` field of the request can be a specific target, such as `user:anne`, or a userset (set of users) such as `group:marketing#member` or a type-bound public access `user:*`. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). A `contextual_tuples` object may also be included in the body of the request. This object contains one field `tuple_keys`, which is an array of tuple keys. Each of these tuples may have an associated `condition`. You may also provide an `authorization_model_id` in the body. This will be used to assert that the input `tuple_key` is valid for the model specified. If not specified, the assertion will be made against the latest authorization model ID. It is strongly recommended to specify authorization model id for better performance. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will return whether the relationship exists in the field `allowed`. Some exceptions apply, but in general, if a Check API responds with `{allowed: true}`, then you can expect the equivalent ListObjects query to return the object, and viceversa. For example, if `Check(user:anne, reader, document:2021-budget)` responds with `{allowed: true}`, then `ListObjects(user:anne, reader, document)` may include `document:2021-budget` in the response. ## Examples ### Querying with contextual tuples In order to check if user `user:anne` of type `user` has a `reader` relationship with object `document:2021-budget` given the following contextual tuple ```json { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ``` the Check API can be used with the following request body: ```json { \"tuple_key\": { \"user\": \"user:anne\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ] }, \"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\" } ``` ### Querying usersets Some Checks will always return `true`, even without any tuples. For example, for the following authorization model ```python model schema 1.1 type user type document relations define reader: [user] ``` the following query ```json { \"tuple_key\": { \"user\": \"document:2021-budget#reader\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" } } ``` will always return `{ \"allowed\": true }`. This is because usersets are self-defining: the userset `document:2021-budget#reader` will always have the `reader` relation with `document:2021-budget`. ### Querying usersets with difference in the model A Check for a userset can yield results that must be treated carefully if the model involves difference. For example, for the following authorization model ```python model schema 1.1 type user type group relations define member: [user] type document relations define blocked: [user] define reader: [group#member] but not blocked ``` the following query ```json { \"tuple_key\": { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"group:finance\" }, { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, { \"user\": \"user:anne\", \"relation\": \"blocked\", \"object\": \"document:2021-budget\" } ] }, } ``` will return `{ \"allowed\": true }`, even though a specific user of the userset `group:finance#member` does not have the `reader` relationship with the given object. +The Check API returns whether a given user has a relationship with a given object in a given store. The `user` field of the request can be a specific target, such as `user:anne`, or a userset (set of users) such as `group:marketing#member` or a type-bound public access `user:*`. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). A `contextual_tuples` object may also be included in the body of the request. This object contains one field `tuple_keys`, which is an array of tuple keys. Each of these tuples may have an associated `condition`. You may also provide an `authorization_model_id` in the body. This will be used to assert that the input `tuple_key` is valid for the model specified. If not specified, the assertion will be made against the latest authorization model ID. It is strongly recommended to specify authorization model id for better performance. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. By default, the Check API caches results for a short time to optimize performance. You may specify a value of `HIGHER_CONSISTENCY` for the optional `consistency` parameter in the body to inform the server that higher conisistency is preferred at the expense of increased latency. Consideration should be given to the increased latency if requesting higher consistency. The response will return whether the relationship exists in the field `allowed`. Some exceptions apply, but in general, if a Check API responds with `{allowed: true}`, then you can expect the equivalent ListObjects query to return the object, and viceversa. For example, if `Check(user:anne, reader, document:2021-budget)` responds with `{allowed: true}`, then `ListObjects(user:anne, reader, document)` may include `document:2021-budget` in the response. ## Examples ### Querying with contextual tuples In order to check if user `user:anne` of type `user` has a `reader` relationship with object `document:2021-budget` given the following contextual tuple ```json { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ``` the Check API can be used with the following request body: ```json { \"tuple_key\": { \"user\": \"user:anne\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ] }, \"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\" } ``` ### Querying usersets Some Checks will always return `true`, even without any tuples. For example, for the following authorization model ```python model schema 1.1 type user type document relations define reader: [user] ``` the following query ```json { \"tuple_key\": { \"user\": \"document:2021-budget#reader\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" } } ``` will always return `{ \"allowed\": true }`. This is because usersets are self-defining: the userset `document:2021-budget#reader` will always have the `reader` relation with `document:2021-budget`. ### Querying usersets with difference in the model A Check for a userset can yield results that must be treated carefully if the model involves difference. For example, for the following authorization model ```python model schema 1.1 type user type group relations define member: [user] type document relations define blocked: [user] define reader: [group#member] but not blocked ``` the following query ```json { \"tuple_key\": { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"group:finance\" }, { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, { \"user\": \"user:anne\", \"relation\": \"blocked\", \"object\": \"document:2021-budget\" } ] }, } ``` will return `{ \"allowed\": true }`, even though a specific user of the userset `group:finance#member` does not have the `reader` relationship with the given object. ### Requesting higher consistency By default, the Check API caches results for a short time to optimize performance. You may request higher consistency to inform the server that higher consistency should be preferred at the expense of increased latency. Care should be taken when requesting higher consistency due to the increased latency. ```json { \"tuple_key\": { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"consistency\": \"HIGHER_CONSISTENCY\" } ``` ### Example ```csharp @@ -95,6 +177,7 @@ Name | Type | Description | Notes | **200** | A successful response. | - | | **400** | Request failed due to invalid input. | - | | **401** | Not authenticated. | - | +| **403** | Forbidden. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | | **422** | Request timed out due to excessive request throttling. | - | @@ -173,6 +256,7 @@ Name | Type | Description | Notes | **201** | A successful response. | - | | **400** | Request failed due to invalid input. | - | | **401** | Not authenticated. | - | +| **403** | Forbidden. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | | **422** | Request timed out due to excessive request throttling. | - | @@ -250,6 +334,7 @@ void (empty response body) | **204** | A successful response. | - | | **400** | Request failed due to invalid input. | - | | **401** | Not authenticated. | - | +| **403** | Forbidden. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | | **422** | Request timed out due to excessive request throttling. | - | @@ -263,7 +348,7 @@ void (empty response body) 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`. +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. 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`. 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`. ### Expand Request with Contextual Tuples Given the model ```python model schema 1.1 type user type folder relations define owner: [user] type document relations define parent: [folder] define viewer: [user] or writer define writer: [user] or owner from parent ``` and the initial tuples ```json [{ \"user\": \"user:bob\", \"relation\": \"owner\", \"object\": \"folder:1\" }] ``` To expand all `writers` of `document:1` when `document:1` is put in `folder:1`, the first call could be ```json { \"tuple_key\": { \"object\": \"document:1\", \"relation\": \"writer\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"folder:1\", \"relation\": \"parent\", \"object\": \"document:1\" } ] } } ``` this returns: ```json { \"tree\": { \"root\": { \"name\": \"document:1#writer\", \"union\": { \"nodes\": [ { \"name\": \"document:1#writer\", \"leaf\": { \"users\": { \"users\": [] } } }, { \"name\": \"document:1#writer\", \"leaf\": { \"tupleToUserset\": { \"tupleset\": \"document:1#parent\", \"computed\": [ { \"userset\": \"folder:1#owner\" } ] } } } ] } } } } ``` This tells us that the `owner` of `folder:1` may also be a writer. So our next call could be to find the `owners` of `folder:1` ```json { \"tuple_key\": { \"object\": \"folder:1\", \"relation\": \"owner\" } } ``` which gives ```json { \"tree\": { \"root\": { \"name\": \"folder:1#owner\", \"leaf\": { \"users\": { \"users\": [ \"user:bob\" ] } } } } } ``` ### Example ```csharp @@ -330,6 +415,7 @@ Name | Type | Description | Notes | **200** | A successful response. | - | | **400** | Request failed due to invalid input. | - | | **401** | Not authenticated. | - | +| **403** | Forbidden. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | | **422** | Request timed out due to excessive request throttling. | - | @@ -408,6 +494,7 @@ Name | Type | Description | Notes | **200** | A successful response. | - | | **400** | Request failed due to invalid input. | - | | **401** | Not authenticated. | - | +| **403** | Forbidden. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | | **422** | Request timed out due to excessive request throttling. | - | @@ -421,7 +508,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 arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related objects in an array in the \"objects\" field of the response and they will be strings in the object format `:` (e.g. \"document:roadmap\"). The number of objects in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_OBJECTS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_OBJECTS_MAX_RESULTS, whichever is hit first. The objects given will not be sorted, and therefore two identical calls can give a given different set of objects. +The ListObjects API returns a list of all the objects of the given type that the user has a relation with. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. By default, the Check API caches results for a short time to optimize performance. You may specify a value of `HIGHER_CONSISTENCY` for the optional `consistency` parameter in the body to inform the server that higher conisistency is preferred at the expense of increased latency. Consideration should be given to the increased latency if requesting higher consistency. 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 @@ -488,6 +575,7 @@ Name | Type | Description | Notes | **200** | A successful response. | - | | **400** | Request failed due to invalid input. | - | | **401** | Not authenticated. | - | +| **403** | Forbidden. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | | **422** | Request timed out due to excessive request throttling. | - | @@ -568,6 +656,7 @@ Name | Type | Description | Notes | **200** | A successful response. | - | | **400** | Request failed due to invalid input. | - | | **401** | Not authenticated. | - | +| **403** | Forbidden. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | | **422** | Request timed out due to excessive request throttling. | - | @@ -581,7 +670,7 @@ Name | Type | Description | Notes List the users matching the provided filter who have a certain relation to a particular type. -The ListUsers API returns a list of all the users of a specific type that have a relation to a given object. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related users in an array in the \"users\" field of the response. These results may include specific objects, usersets or type-bound public access. Each of these types of results is encoded in its own type and not represented as a string.In cases where a type-bound public acces result is returned (e.g. `user:*`), it cannot be inferred that all subjects of that type have a relation to the object; it is possible that negations exist and checks should still be queried on individual subjects to ensure access to that document.The number of users in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_USERS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_USERS_MAX_RESULTS, whichever is hit first. The returned users will not be sorted, and therefore two identical calls may yield different sets of users. +The ListUsers API returns a list of all the users of a specific type that have a relation to a given object. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related users in an array in the \"users\" field of the response. These results may include specific objects, usersets or type-bound public access. Each of these types of results is encoded in its own type and not represented as a string.In cases where a type-bound public access result is returned (e.g. `user:*`), it cannot be inferred that all subjects of that type have a relation to the object; it is possible that negations exist and checks should still be queried on individual subjects to ensure access to that document.The number of users in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_USERS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_USERS_MAX_RESULTS, whichever is hit first. The returned users will not be sorted, and therefore two identical calls may yield different sets of users. ### Example ```csharp @@ -648,6 +737,7 @@ Name | Type | Description | Notes | **200** | A successful response. | - | | **400** | Request failed due to invalid input. | - | | **401** | Not authenticated. | - | +| **403** | Forbidden. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | | **422** | Request timed out due to excessive request throttling. | - | @@ -728,6 +818,7 @@ Name | Type | Description | Notes | **200** | A successful response. | - | | **400** | Request failed due to invalid input. | - | | **401** | Not authenticated. | - | +| **403** | Forbidden. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | | **422** | Request timed out due to excessive request throttling. | - | @@ -741,7 +832,7 @@ Name | Type | Description | Notes 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. +The ReadAssertions API will return, for a given authorization model id, all the assertions stored for it. ### Example ```csharp @@ -808,6 +899,7 @@ Name | Type | Description | Notes | **200** | A successful response. | - | | **400** | Request failed due to invalid input. | - | | **401** | Not authenticated. | - | +| **403** | Forbidden. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | | **422** | Request timed out due to excessive request throttling. | - | @@ -888,6 +980,7 @@ Name | Type | Description | Notes | **200** | A successful response. | - | | **400** | Request failed due to invalid input. | - | | **401** | Not authenticated. | - | +| **403** | Forbidden. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | | **422** | Request timed out due to excessive request throttling. | - | @@ -970,6 +1063,7 @@ Name | Type | Description | Notes | **200** | A successful response. | - | | **400** | Request failed due to invalid input. | - | | **401** | Not authenticated. | - | +| **403** | Forbidden. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | | **422** | Request timed out due to excessive request throttling. | - | @@ -979,7 +1073,7 @@ Name | Type | Description | Notes # **ReadChanges** -> ReadChangesResponse ReadChanges (string? type = null, int? pageSize = null, string? continuationToken = null) +> ReadChangesResponse ReadChanges (string? type = null, int? pageSize = null, string? continuationToken = null, DateTime? startTime = null) Return a list of all the tuple changes @@ -1011,11 +1105,12 @@ namespace Example var type = "type_example"; // string? | (optional) var pageSize = 56; // int? | (optional) var continuationToken = "continuationToken_example"; // string? | (optional) + var startTime = DateTime.Parse("2013-10-20T19:20:30+01:00"); // DateTime? | Start date and time of changes to read. Format: ISO 8601 timestamp (e.g., 2022-01-01T00:00:00Z) If a continuation_token is provided along side start_time, the continuation_token will take precedence over start_time. (optional) try { // Return a list of all the tuple changes - ReadChangesResponse response = await openFgaApi.ReadChanges(type, pageSize, continuationToken); + ReadChangesResponse response = await openFgaApi.ReadChanges(type, pageSize, continuationToken, startTime); Debug.WriteLine(response); } catch (ApiException e) @@ -1037,6 +1132,7 @@ Name | Type | Description | Notes **type** | **string?**| | [optional] **pageSize** | **int?**| | [optional] **continuationToken** | **string?**| | [optional] + **startTime** | **DateTime?**| Start date and time of changes to read. Format: ISO 8601 timestamp (e.g., 2022-01-01T00:00:00Z) If a continuation_token is provided along side start_time, the continuation_token will take precedence over start_time. | [optional] ### Return type @@ -1054,6 +1150,7 @@ Name | Type | Description | Notes | **200** | A successful response. | - | | **400** | Request failed due to invalid input. | - | | **401** | Not authenticated. | - | +| **403** | Forbidden. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | | **422** | Request timed out due to excessive request throttling. | - | @@ -1134,6 +1231,7 @@ Name | Type | Description | Notes | **200** | A successful response. | - | | **400** | Request failed due to invalid input. | - | | **401** | Not authenticated. | - | +| **403** | Forbidden. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | | **422** | Request timed out due to excessive request throttling. | - | @@ -1147,7 +1245,7 @@ Name | Type | Description | Notes 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. +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, the expectation of whether a call to the Check API of that tuple key will return true or false, and optionally a list of contextual tuples. ### Example ```csharp @@ -1215,6 +1313,7 @@ void (empty response body) | **204** | A successful response. | - | | **400** | Request failed due to invalid input. | - | | **401** | Not authenticated. | - | +| **403** | Forbidden. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | | **422** | Request timed out due to excessive request throttling. | - | @@ -1295,6 +1394,7 @@ Name | Type | Description | Notes | **201** | A successful response. | - | | **400** | Request failed due to invalid input. | - | | **401** | Not authenticated. | - | +| **403** | Forbidden. | - | | **404** | Request failed due to incorrect path. | - | | **409** | Request was aborted due a transaction conflict. | - | | **422** | Request timed out due to excessive request throttling. | - | diff --git a/example/Example1/Example1.cs b/example/Example1/Example1.cs index 657e90b..3324677 100644 --- a/example/Example1/Example1.cs +++ b/example/Example1/Example1.cs @@ -9,9 +9,6 @@ namespace Example1; public class Example1 { public static async Task Main() { - var shouldSkipListingStores = false; - var shouldSkipStoreMethods = false; - try { var credentials = new Credentials(); if (Environment.GetEnvironmentVariable("FGA_CLIENT_ID") != null) { @@ -32,44 +29,28 @@ public static async Task Main() { }; var fgaClient = new OpenFgaClient(configuration); - GetStoreResponse? currentStore = null; - if (shouldSkipStoreMethods) { - Console.WriteLine("Skipping initial store creation"); - } - else { - if (shouldSkipListingStores) { - Console.WriteLine("Skipping Listing Stores"); - } - else { - // ListStores - Console.WriteLine("Listing Stores"); - var stores1 = await fgaClient.ListStores(); - Console.WriteLine("Stores Count: " + stores1.Stores?.Count()); - } + // 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("Created Test Store ID: " + store.Id); + // 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; + // Set the store id + fgaClient.StoreId = store.Id; - if (shouldSkipListingStores) { - Console.WriteLine("Skipping Listing Stores"); - } - else { - // ListStores after Create - Console.WriteLine("Listing Stores"); - var stores = await fgaClient.ListStores(); - Console.WriteLine("Stores Count: " + stores.Stores?.Count()); - } + // 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"); - currentStore = await fgaClient.GetStore(); - Console.WriteLine("Current Store Name: " + currentStore.Name); - } + // GetStore + Console.WriteLine("Getting Current Store"); + var currentStore = await fgaClient.GetStore(); + Console.WriteLine("Current Store Name: " + currentStore.Name); // ReadAuthorizationModels Console.WriteLine("Reading Authorization Models"); @@ -161,23 +142,16 @@ public static async Task Main() { Console.WriteLine("Authorization Model ID " + authorizationModel.AuthorizationModelId); // ReadAuthorizationModels - after Write - Thread.Sleep(10_000); Console.WriteLine("Reading Authorization Models"); models = await fgaClient.ReadAuthorizationModels(); Console.WriteLine("Models Count: " + models.AuthorizationModels?.Count()); // ReadLatestAuthorizationModel - after Write latestAauthorizationModel = await fgaClient.ReadLatestAuthorizationModel(); - if (latestAauthorizationModel == null) { - throw new Exception("Cannot find module that was written"); - } - else { - var latestModelId = latestAauthorizationModel.AuthorizationModel?.Id; - Console.WriteLine("Latest Authorization Model ID " + latestModelId); + Console.WriteLine("Latest Authorization Model ID " + latestAauthorizationModel.AuthorizationModel.Id); - // Set the model ID - fgaClient.AuthorizationModelId = latestModelId; - } + // Set the model ID + fgaClient.AuthorizationModelId = latestAauthorizationModel.AuthorizationModel.Id; // Write Console.WriteLine("Writing Tuples"); @@ -186,7 +160,7 @@ await fgaClient.Write(new ClientWriteRequest { new() { User = "user:anne", Relation = "writer", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", Condition = new RelationshipCondition() { Name = "ViewCountLessThan200", Context = new { Name = "Roadmap", Type = "document" } @@ -214,7 +188,7 @@ await fgaClient.Write(new ClientWriteRequest { var failingCheckResponse = await fgaClient.Check(new ClientCheckRequest { User = "user:anne", Relation = "viewer", - Object = "document:roadmap" + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }); Console.WriteLine("Allowed: " + failingCheckResponse.Allowed); } @@ -227,70 +201,11 @@ await fgaClient.Write(new ClientWriteRequest { var checkResponse = await fgaClient.Check(new ClientCheckRequest { User = "user:anne", Relation = "viewer", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", Context = new { ViewCount = 100 } }); Console.WriteLine("Allowed: " + checkResponse.Allowed); - // Batch checking for access with context - Console.WriteLine("Batch checking for access with context"); - var batchCheckResponse = await fgaClient.BatchCheck(new List() { - new () { - User = "user:anne", - Relation = "viewer", - Object = "document:roadmap", - Context = new { ViewCount = 100 } - } - }); - Console.WriteLine("Responses[0].Allowed: " + batchCheckResponse.Responses[0].Allowed); - - // Listing relations with context - Console.WriteLine("Listing relations with context"); - var listRelationsResponse = await fgaClient.ListRelations(new ClientListRelationsRequest() { - User = "user:anne", - Relations = new List() {"viewer", "writer"}, - Object = "document:roadmap", - Context = new { ViewCount = 100 } - }); - // var allowedRelations = new List(); - // listRelationsResponse.Relations?.ForEach(r => { - // allowedRelations.Add(r); - // }); - Console.WriteLine("Relations: " + string.Join(" | ", listRelationsResponse.Relations!)); - - // Listing objects with context - Console.WriteLine("Listing objects with context"); - var listObjectsResponse = await fgaClient.ListObjects(new ClientListObjectsRequest() { - User = "user:anne", - Relation = "viewer", - Type = "document", - Context = new { ViewCount = 100 } - }); - // var allowedObjects = new List(); - // listObjectsResponse.Objects?.ForEach(o => { - // allowedObjects.Add(o); - // }); - Console.WriteLine("Objects: " + string.Join(" | ", listObjectsResponse.Objects!)); - - // Listing users with context - Console.WriteLine("Listing users with context"); - var listUsersResponse = await fgaClient.ListUsers(new ClientListUsersRequest() { - UserFilters = new List() { - new () { Type = "user" }, - }, - Relation = "viewer", - Object = new FgaObject() { - Type = "document", - Id = "roadmap" - }, - Context = new { ViewCount = 100 } - }); - var allowedUsers = new List(); - listUsersResponse.Users?.ForEach(u => { - allowedUsers.Add(u.ToJson()); - }); - Console.WriteLine("Users: " + string.Join(" | ", allowedUsers)); - // WriteAssertions await fgaClient.WriteAssertions(new List() { new ClientAssertion() { @@ -302,7 +217,7 @@ await fgaClient.WriteAssertions(new List() { new ClientAssertion() { User = "user:anne", Relation = "viewer", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", Expectation = false, } }); @@ -313,15 +228,10 @@ await fgaClient.WriteAssertions(new List() { var assertions = await fgaClient.ReadAssertions(); Console.WriteLine("Assertions " + assertions.ToJson()); - if (shouldSkipStoreMethods || currentStore == null) { - Console.WriteLine("Skipping store deletion"); - } - else { - // DeleteStore - Console.WriteLine("Deleting Test Store"); - await fgaClient.DeleteStore(); - Console.WriteLine("Deleted Store: " + currentStore.Name); - } + // DeleteStore + Console.WriteLine("Deleting Current Store"); + await fgaClient.DeleteStore(); + Console.WriteLine("Deleted Store: " + currentStore.Name); } catch (ApiException e) { Console.WriteLine("Error: " + e); diff --git a/example/Example1/Example1.csproj b/example/Example1/Example1.csproj index 3428ee9..3bbed4d 100644 --- a/example/Example1/Example1.csproj +++ b/example/Example1/Example1.csproj @@ -10,7 +10,7 @@ - all + all @@ -20,4 +20,11 @@ + + + + + + + diff --git a/src/OpenFga.Sdk.Test.Framework/FrameworkCompatibilityTests.cs b/src/OpenFga.Sdk.Test.Framework/FrameworkCompatibilityTests.cs new file mode 100644 index 0000000..3b120b7 --- /dev/null +++ b/src/OpenFga.Sdk.Test.Framework/FrameworkCompatibilityTests.cs @@ -0,0 +1,91 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 1.x +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://openfga.dev/community +// License: [Apache-2.0](https://github.com/openfga/dotnet-sdk/blob/main/LICENSE) +// +// NOTE: This file was auto generated. DO NOT EDIT. +// + + +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Threading.Tasks; +using Xunit; +using OpenFga.Sdk.Client; +using OpenFga.Sdk.Configuration; + +namespace OpenFga.Sdk.Framework.Tests +{ + public class FrameworkCompatibilityTests + { + [Fact] + public void CanCreateClientConfiguration() + { + // This test verifies that the SDK can be properly referenced and used in .NET Framework 4.8 + var config = new ClientConfiguration + { + ApiUrl = "https://api.openfga.example", + StoreId = "01GXSA8YR785C4FYS3C0RTG7B1" + }; + + Assert.NotNull(config); + Assert.Equal("https://api.openfga.example", config.ApiUrl); + Assert.Equal("01GXSA8YR785C4FYS3C0RTG7B1", config.StoreId); + } + + [Fact] + public void CanCreateOpenFgaClient() + { + var config = new ClientConfiguration + { + ApiUrl = "https://api.openfga.example", + StoreId = "01GXSA8YR785C4FYS3C0RTG7B1" + }; + + var client = new OpenFgaClient(config); + Assert.NotNull(client); + Assert.Equal("01GXSA8YR785C4FYS3C0RTG7B1", client.StoreId); + } + + [Fact] + public void CanSerializeObjects() + { + // Test using System.Text.Json which is one of the packages added for .NET Standard 2.0 compatibility + var tuple = new Client.Model.ClientTupleKey + { + User = "user:123", + Relation = "viewer", + Object = "document:456" + }; + + var json = System.Text.Json.JsonSerializer.Serialize(tuple); + Assert.Contains("user:123", json); + Assert.Contains("viewer", json); + Assert.Contains("document:456", json); + } + + [Fact] + public void CanUseNetStandard20Collections() + { + // Create a dictionary and use extension methods + var dict = new Dictionary + { + { "key1", "value1" }, + { "key2", "value2" } + }; + + // Access using extensions + var hasKey = dict.ContainsKey("key1"); + Assert.True(hasKey); + + // Create list and use its methods + var list = new List { "item1", "item2" }; + Assert.Equal(2, list.Count); + } + } +} \ No newline at end of file diff --git a/src/OpenFga.Sdk.Test.Framework/OpenFga.Sdk.Test.Framework.csproj b/src/OpenFga.Sdk.Test.Framework/OpenFga.Sdk.Test.Framework.csproj new file mode 100644 index 0000000..e790400 --- /dev/null +++ b/src/OpenFga.Sdk.Test.Framework/OpenFga.Sdk.Test.Framework.csproj @@ -0,0 +1,25 @@ + + + + false + OpenFga.Sdk.Test.Framework + OpenFga.Sdk.Test.Framework + net48 + false + 8.0 + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + \ No newline at end of file diff --git a/src/OpenFga.Sdk.Test.NetCore31/NetCore31CompatibilityTests.cs b/src/OpenFga.Sdk.Test.NetCore31/NetCore31CompatibilityTests.cs new file mode 100644 index 0000000..843d438 --- /dev/null +++ b/src/OpenFga.Sdk.Test.NetCore31/NetCore31CompatibilityTests.cs @@ -0,0 +1,89 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 1.x +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://openfga.dev/community +// License: [Apache-2.0](https://github.com/openfga/dotnet-sdk/blob/main/LICENSE) +// +// NOTE: This file was auto generated. DO NOT EDIT. +// + + +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Threading.Tasks; +using Xunit; +using OpenFga.Sdk.Client; +using OpenFga.Sdk.Configuration; + +namespace OpenFga.Sdk.NetCore31.Tests +{ + public class NetCore31CompatibilityTests + { + [Fact] + public void CanCreateClientConfiguration() + { + // This test verifies that the SDK can be properly referenced and used in .NET Core 3.1 + var config = new ClientConfiguration + { + ApiUrl = "https://api.openfga.example", + StoreId = "01GXSA8YR785C4FYS3C0RTG7B1" + }; + + Assert.NotNull(config); + Assert.Equal("https://api.openfga.example", config.ApiUrl); + Assert.Equal("01GXSA8YR785C4FYS3C0RTG7B1", config.StoreId); + } + + [Fact] + public void CanCreateOpenFgaClient() + { + var config = new ClientConfiguration + { + ApiUrl = "https://api.openfga.example", + StoreId = "01GXSA8YR785C4FYS3C0RTG7B1" + }; + + var client = new OpenFgaClient(config); + Assert.NotNull(client); + Assert.Equal("01GXSA8YR785C4FYS3C0RTG7B1", client.StoreId); + } + + [Fact] + public void CanSerializeObjects() + { + // Test using System.Text.Json which is one of the packages added for .NET Standard 2.0 compatibility + var tuple = new Client.Model.ClientTupleKey + { + User = "user:123", + Relation = "viewer", + Object = "document:456" + }; + + var json = System.Text.Json.JsonSerializer.Serialize(tuple); + Assert.Contains("user:123", json); + Assert.Contains("viewer", json); + Assert.Contains("document:456", json); + } + + [Fact] + public void CanUseHttpClientFeatures() + { + // Test that we can use HttpClient features in .NET Core 3.1 + var handler = new HttpClientHandler(); + var client = new HttpClient(handler); + + // Create a request message (will be used for API calls) + var request = new HttpRequestMessage(HttpMethod.Get, "https://api.openfga.example"); + request.Headers.Add("X-Test-Header", "test-value"); + + Assert.NotNull(client); + Assert.NotNull(request); + Assert.Equal(HttpMethod.Get, request.Method); + Assert.True(request.Headers.Contains("X-Test-Header")); + } + } +} \ No newline at end of file diff --git a/src/OpenFga.Sdk.Test.NetCore31/OpenFga.Sdk.Test.NetCore31.csproj b/src/OpenFga.Sdk.Test.NetCore31/OpenFga.Sdk.Test.NetCore31.csproj new file mode 100644 index 0000000..27ab9e4 --- /dev/null +++ b/src/OpenFga.Sdk.Test.NetCore31/OpenFga.Sdk.Test.NetCore31.csproj @@ -0,0 +1,25 @@ + + + + false + OpenFga.Sdk.Test.NetCore31 + OpenFga.Sdk.Test.NetCore31 + netcoreapp3.1 + false + 8.0 + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + \ 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 85892f6..5e8876c 100644 --- a/src/OpenFga.Sdk.Test/Api/OpenFgaApiTests.cs +++ b/src/OpenFga.Sdk.Test/Api/OpenFgaApiTests.cs @@ -604,7 +604,7 @@ public async Task FgaApiValidationErrorTest() { TupleKey = new CheckRequestTupleKey() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap" + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }, AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1" }; @@ -658,7 +658,7 @@ public async Task FgaApiInternalErrorTest() { TupleKey = new CheckRequestTupleKey() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap" + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }, AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1" }; @@ -711,7 +711,7 @@ public async Task FgaApiInternalErrorRetrySuccessTest() { TupleKey = new CheckRequestTupleKey() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap" + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" } }; @@ -756,7 +756,7 @@ public async Task FgaNotFoundErrorTest() { TupleKey = new CheckRequestTupleKey() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap" + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" } }; @@ -803,7 +803,7 @@ public async Task FgaApiErrorTest() { TupleKey = new CheckRequestTupleKey() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap" + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" } }; @@ -857,7 +857,7 @@ public async Task FgaApiRateLimitExceededErrorTest() { TupleKey = new CheckRequestTupleKey() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap" + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" } }; @@ -906,7 +906,7 @@ public async Task FgaApiRateLimitExceededErrorRetrySuccessTest() { TupleKey = new CheckRequestTupleKey() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap" + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" } }; @@ -955,7 +955,7 @@ public async Task RetryOnRateLimitTest() { TupleKey = new CheckRequestTupleKey() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap" + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" } }; @@ -1181,7 +1181,7 @@ public async Task CheckTest() { TupleKey = new CheckRequestTupleKey() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap" + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }, AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1" }; @@ -1227,7 +1227,7 @@ public async Task WriteWriteTest() { Writes = new WriteRequestWrites(new List { new () { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap" + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" } }), AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1" }; @@ -1269,7 +1269,7 @@ public async Task WriteDeleteTest() { Deletes = new WriteRequestDeletes(new List { new () { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap" + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" } }), AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1" }; @@ -1311,11 +1311,11 @@ public async Task WriteMixedWithAuthorizationModelIdTest() { Writes = new WriteRequestWrites(new List { new () { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "writer", - Object = "document:roadmap" + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }, new () { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap" + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" } }), AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1" }; @@ -1339,7 +1339,7 @@ public async Task ExpandTest() { var mockHandler = new Mock(MockBehavior.Strict); var jsonResponse = - "{\"tree\":{\"root\":{\"name\":\"document:roadmap#owner\", \"union\":{\"nodes\":[{\"name\":\"document:roadmap#owner\", \"leaf\":{\"users\":{\"users\":[\"team:product#member\"]}}}, {\"name\":\"document:roadmap#owner\", \"leaf\":{\"tupleToUserset\":{\"tupleset\":\"document:roadmap#owner\", \"computed\":[{\"userset\":\"org:contoso#admin\"}]}}}]}}}}"; + "{\"tree\":{\"root\":{\"name\":\"document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#owner\", \"union\":{\"nodes\":[{\"name\":\"document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#owner\", \"leaf\":{\"users\":{\"users\":[\"team:product#member\"]}}}, {\"name\":\"document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#owner\", \"leaf\":{\"tupleToUserset\":{\"tupleset\":\"document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#owner\", \"computed\":[{\"userset\":\"org:contoso#admin\"}]}}}]}}}}"; mockHandler.Protected() .Setup>( "SendAsync", @@ -1356,7 +1356,7 @@ public async Task ExpandTest() { var httpClient = new HttpClient(mockHandler.Object); var openFgaApi = new OpenFgaApi(_config, httpClient); - var body = new ExpandRequest { TupleKey = new ExpandRequestTupleKey(_object: "document:roadmap", relation: "viewer"), AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1" }; + var body = new ExpandRequest { TupleKey = new ExpandRequestTupleKey(_object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", relation: "viewer"), AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1" }; var response = await openFgaApi.Expand(_storeId, body); mockHandler.Protected().Verify( @@ -1381,22 +1381,22 @@ public async Task ExpandComplexResponseTest() { var mockHandler = new Mock(MockBehavior.Strict); var mockResponse = new ExpandResponse( tree: new UsersetTree( - root: new Node(name: "document:roadmap1#owner", + root: new Node(name: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a1#owner", union: new Nodes( nodes: new List() { - new Node(name: "document:roadmap2#owner", leaf: new Leaf(users: new Users(users: new List(){"team:product#member"}))), - new Node(name: "document:roadmap3#owner", leaf: new Leaf(tupleToUserset: new UsersetTreeTupleToUserset(tupleset: "document:roadmap#owner", computed: new List(){ + new Node(name: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a2#owner", leaf: new Leaf(users: new Users(users: new List(){"team:product#member"}))), + new Node(name: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a3#owner", leaf: new Leaf(tupleToUserset: new UsersetTreeTupleToUserset(tupleset: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#owner", computed: new List(){ new Computed(userset: "org:contoso#admin") }))), }), difference: new UsersetTreeDifference( - _base: new Node(name: "document:roadmap3#owner", leaf: new Leaf(users: new Users(users: new List() { "team:product#member" }))), - subtract: new Node(name: "document:roadmap4#owner", leaf: new Leaf(users: new Users(users: new List() { "team:product#member" }))) + _base: new Node(name: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a3#owner", leaf: new Leaf(users: new Users(users: new List() { "team:product#member" }))), + subtract: new Node(name: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a4#owner", leaf: new Leaf(users: new Users(users: new List() { "team:product#member" }))) ), intersection: new Nodes( nodes: new List() { - new Node(name: "document:roadmap5#owner", leaf: new Leaf(users: new Users(users: new List(){"team:product#commentor"}))), - new Node(name: "document:roadmap6#owner", leaf: new Leaf(tupleToUserset: new UsersetTreeTupleToUserset(tupleset: "document:roadmap#viewer", computed: new List(){ + new Node(name: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a5#owner", leaf: new Leaf(users: new Users(users: new List(){"team:product#commentor"}))), + new Node(name: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a6#owner", leaf: new Leaf(tupleToUserset: new UsersetTreeTupleToUserset(tupleset: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#viewer", computed: new List(){ new Computed(userset: "org:contoso#owner") }))), })) @@ -1418,7 +1418,7 @@ public async Task ExpandComplexResponseTest() { var httpClient = new HttpClient(mockHandler.Object); var openFgaApi = new OpenFgaApi(_config, httpClient); - var body = new ExpandRequest(new ExpandRequestTupleKey(_object: "document:roadmap", relation: "viewer")); + var body = new ExpandRequest(new ExpandRequestTupleKey(_object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", relation: "viewer")); var response = await openFgaApi.Expand(_storeId, body); mockHandler.Protected().Verify( @@ -1440,7 +1440,7 @@ public async Task ExpandComplexResponseTest() { [Fact] public async Task ListObjectsTest() { var mockHandler = new Mock(MockBehavior.Strict); - var expectedResponse = new ListObjectsResponse { Objects = new List { "document:roadmap" } }; + var expectedResponse = new ListObjectsResponse { Objects = new List { "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" } }; mockHandler.Protected() .Setup>( "SendAsync", @@ -1465,7 +1465,7 @@ public async Task ListObjectsTest() { ContextualTuples = new ContextualTupleKeys() { TupleKeys = new List { new("folder:product", "editor", "user:81684243-9356-4421-8fbf-a4f8d36aa31b"), - new("document:roadmap", "parent", "folder:product") + new("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", "parent", "folder:product") } } }; @@ -1545,7 +1545,7 @@ public async Task ListUsersTest() { }, ContextualTuples = new List { new("folder:product", "editor", "user:81684243-9356-4421-8fbf-a4f8d36aa31b"), - new("document:roadmap", "parent", "folder:product") + new("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", "parent", "folder:product") }, Context = new { ViewCount = 100 } }; @@ -1576,7 +1576,7 @@ public async Task ReadTest() { new(new TupleKey { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap" + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }, DateTime.Now) } }; @@ -1600,7 +1600,7 @@ public async Task ReadTest() { TupleKey = new ReadRequestTupleKey { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap" + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }, }; var response = await openFgaApi.Read(_storeId, body); @@ -1630,7 +1630,7 @@ public async Task ReadEmptyTest() { new(new TupleKey { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap" + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }, DateTime.Now) } }; @@ -1678,7 +1678,7 @@ public async Task ReadChangesTest() { new(new TupleKey { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap" + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }, TupleOperation.WRITE, DateTime.Now), }, ContinuationToken = "eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==" @@ -1702,8 +1702,9 @@ public async Task ReadChangesTest() { var type = "repo"; var pageSize = 25; + var startTime = DateTime.Parse("2022-01-01T00:00:00Z"); var continuationToken = "eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ=="; - var response = await openFgaApi.ReadChanges(_storeId, type, pageSize, continuationToken); + var response = await openFgaApi.ReadChanges(_storeId, type, pageSize, continuationToken, startTime); mockHandler.Protected().Verify( "SendAsync", @@ -1748,7 +1749,7 @@ public async Task WriteAssertionsTest() { new (new AssertionTupleKey { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap" + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }) }, }; diff --git a/src/OpenFga.Sdk.Test/Client/OpenFgaClientTests.cs b/src/OpenFga.Sdk.Test/Client/OpenFgaClientTests.cs index 584d6cc..a6da9b2 100644 --- a/src/OpenFga.Sdk.Test/Client/OpenFgaClientTests.cs +++ b/src/OpenFga.Sdk.Test/Client/OpenFgaClientTests.cs @@ -147,7 +147,7 @@ public async Task ListStoresTest() { var mockHandler = new Mock(MockBehavior.Strict); var expectedResponse = new ListStoresResponse() { Stores = new List() { - new() {Id = "45678", Name = "TestStore", CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now} + new Store() {Id = "45678", Name = "TestStore", CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now} } }; mockHandler.Protected() @@ -619,7 +619,7 @@ public async Task ReadChangesTest() { new(new TupleKey { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap" + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }, TupleOperation.WRITE, DateTime.Now), }, @@ -645,9 +645,10 @@ public async Task ReadChangesTest() { var type = "repo"; var pageSize = 25; + var startTime = DateTime.Parse("2022-01-01T00:00:00Z"); var continuationToken = "eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ=="; - var response = await fgaClient.ReadChanges(new ClientReadChangesRequest { Type = type }, new ClientReadChangesOptions { + var response = await fgaClient.ReadChanges(new ClientReadChangesRequest { Type = type, StartTime = startTime }, new ClientReadChangesOptions { PageSize = pageSize, ContinuationToken = continuationToken, }); @@ -678,7 +679,7 @@ public async Task ReadTest() { new(new TupleKey { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap" + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }, DateTime.Now) } @@ -703,7 +704,7 @@ public async Task ReadTest() { var body = new ClientReadRequest() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", }; var options = new ClientReadOptions { }; var response = await fgaClient.Read(body, options); @@ -734,7 +735,7 @@ public async Task ReadEmptyTest() { new(new TupleKey { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap" + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }, DateTime.Now) } @@ -802,7 +803,7 @@ public async Task WriteWriteTest() { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", } }, Deletes = new List(), // should not get passed @@ -848,7 +849,7 @@ public async Task WriteDeleteTest() { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", } }, }; @@ -893,14 +894,14 @@ public async Task WriteMixedWithAuthorizationModelIdTest() { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", }, }, Deletes = new List { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "writer", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", } }, }; @@ -953,7 +954,7 @@ public async Task WriteNonTransactionTest() { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", }, new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", @@ -965,7 +966,7 @@ public async Task WriteNonTransactionTest() { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "writer", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", } }, }; @@ -1018,12 +1019,12 @@ public async Task CheckTest() { var body = new ClientCheckRequest { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", ContextualTuples = new List() { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "editor", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", Condition = new RelationshipCondition() { Name = "ViewCountLessThan200", Context = new { Name = "Roadmap", Type = "document" } @@ -1074,12 +1075,12 @@ public async Task CheckWithConsistencyTest() { var body = new ClientCheckRequest { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", ContextualTuples = new List() { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "editor", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", Condition = new RelationshipCondition() { Name = "ViewCountLessThan200", Context = new { Name = "Roadmap", Type = "document" } @@ -1157,36 +1158,36 @@ public async Task BatchCheckTest() { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", ContextualTuples = new List() { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "editor", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", } }, }, new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "admin", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", ContextualTuples = new List() { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "editor", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", } }, }, new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "creator", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", }, new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "deleter", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", } }; var options = new ClientBatchCheckOptions { @@ -1204,7 +1205,7 @@ public async Task BatchCheckTest() { ItExpr.IsAny() ); - Assert.IsType(response); + Assert.IsType(response); var allowedResponses = response.Responses.FindAll(res => res.Allowed); Assert.Equal(2, allowedResponses.Count); @@ -1222,7 +1223,7 @@ public async Task ExpandTest() { var mockHandler = new Mock(MockBehavior.Strict); var jsonResponse = - "{\"tree\":{\"root\":{\"name\":\"document:roadmap#owner\", \"union\":{\"nodes\":[{\"name\":\"document:roadmap#owner\", \"leaf\":{\"users\":{\"users\":[\"team:product#member\"]}}}, {\"name\":\"document:roadmap#owner\", \"leaf\":{\"tupleToUserset\":{\"tupleset\":\"document:roadmap#owner\", \"computed\":[{\"userset\":\"org:contoso#admin\"}]}}}]}}}}"; + "{\"tree\":{\"root\":{\"name\":\"document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#owner\", \"union\":{\"nodes\":[{\"name\":\"document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#owner\", \"leaf\":{\"users\":{\"users\":[\"team:product#member\"]}}}, {\"name\":\"document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#owner\", \"leaf\":{\"tupleToUserset\":{\"tupleset\":\"document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#owner\", \"computed\":[{\"userset\":\"org:contoso#admin\"}]}}}]}}}}"; mockHandler.Protected() .Setup>( "SendAsync", @@ -1242,7 +1243,7 @@ public async Task ExpandTest() { var body = new ClientExpandRequest { Relation = "viewer", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", }; var response = await fgaClient.Expand(body, new ClientExpandOptions() { AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1", @@ -1272,29 +1273,29 @@ public async Task ExpandComplexResponseTest() { var mockHandler = new Mock(MockBehavior.Strict); var mockResponse = new ExpandResponse( tree: new UsersetTree( - root: new Node(name: "document:roadmap1#owner", + root: new Node(name: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a1#owner", union: new Nodes( nodes: new List() { - new Node(name: "document:roadmap2#owner", + new Node(name: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a2#owner", leaf: new Leaf(users: new Users(users: new List() {"team:product#member"}))), - new Node(name: "document:roadmap3#owner", + new Node(name: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a3#owner", leaf: new Leaf(tupleToUserset: new UsersetTreeTupleToUserset( - tupleset: "document:roadmap#owner", + tupleset: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#owner", computed: new List() {new Computed(userset: "org:contoso#admin")}))), }), difference: new UsersetTreeDifference( - _base: new Node(name: "document:roadmap3#owner", + _base: new Node(name: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a3#owner", leaf: new Leaf(users: new Users(users: new List() { "team:product#member" }))), - subtract: new Node(name: "document:roadmap4#owner", + subtract: new Node(name: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a4#owner", leaf: new Leaf(users: new Users(users: new List() { "team:product#member" }))) ), intersection: new Nodes( nodes: new List() { - new Node(name: "document:roadmap5#owner", + new Node(name: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a5#owner", leaf: new Leaf(users: new Users(users: new List() {"team:product#commentor"}))), - new Node(name: "document:roadmap6#owner", + new Node(name: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a6#owner", leaf: new Leaf(tupleToUserset: new UsersetTreeTupleToUserset( - tupleset: "document:roadmap#viewer", + tupleset: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#viewer", computed: new List() {new Computed(userset: "org:contoso#owner")}))), })) )); @@ -1317,7 +1318,7 @@ public async Task ExpandComplexResponseTest() { var body = new ClientExpandRequest { Relation = "viewer", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", }; var response = await fgaClient.Expand(body, new ClientExpandOptions { AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1", @@ -1342,7 +1343,7 @@ public async Task ExpandComplexResponseTest() { [Fact] public async Task ListObjectsTest() { var mockHandler = new Mock(MockBehavior.Strict); - var expectedResponse = new ListObjectsResponse { Objects = new List { "document:roadmap" } }; + var expectedResponse = new ListObjectsResponse { Objects = new List { "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" } }; mockHandler.Protected() .Setup>( "SendAsync", @@ -1373,7 +1374,7 @@ public async Task ListObjectsTest() { new() { User = "folder:product", Relation = "parent", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", }, }, }; @@ -1435,13 +1436,13 @@ public async Task ListRelationsTest() { var body = new ClientListRelationsRequest() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", Relations = new List { "can_view", "can_edit", "can_delete", "can_rename" }, ContextualTuples = new List() { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "editor", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", } } }; @@ -1489,7 +1490,7 @@ public async Task ListRelationsNoRelationsProvidedTest() { var body = new ClientListRelationsRequest() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", Relations = new List { }, }; @@ -1515,20 +1516,20 @@ public async Task ListUsersTest() { var expectedResponse = new ListUsersResponse { // A real API would not return all these for the filter provided, these are just for test purposes Users = new List { - new () { + new User() { Object = new FgaObject { Type = "user", Id = "81684243-9356-4421-8fbf-a4f8d36aa31b" } }, - new () { + new User() { Userset = new UsersetUser() { Type = "team", Id = "fga", Relation = "member" } }, - new () { + new User() { Wildcard = new TypedWildcard() { Type = "user" } @@ -1577,7 +1578,7 @@ public async Task ListUsersTest() { new() { User = "folder:product", Relation = "parent", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", }, }, Context = new { ViewCount = 100 } @@ -1674,7 +1675,7 @@ public async Task WriteAssertionsTest() { var body = new List() {new ClientAssertion() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", - Object = "document:roadmap", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", Expectation = true, }}; diff --git a/src/OpenFga.Sdk.Test/FrameworkCompatibility/FrameworkTests.cs b/src/OpenFga.Sdk.Test/FrameworkCompatibility/FrameworkTests.cs new file mode 100644 index 0000000..9e63705 --- /dev/null +++ b/src/OpenFga.Sdk.Test/FrameworkCompatibility/FrameworkTests.cs @@ -0,0 +1,66 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 1.x +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://openfga.dev/community +// 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.Test.Helpers; +using System; +using System.Collections.Generic; +using Xunit; + +namespace OpenFga.Sdk.Test.FrameworkCompatibility { + public class FrameworkTests { + [Fact] + public void VerifyFrameworkDetection() { + string frameworkName = FrameworkCompat.GetFrameworkName(); + Console.WriteLine($"Running tests on {frameworkName}"); + + // This test just verifies that our multi-targeting configuration works + Assert.NotNull(frameworkName); + } + + [Fact] + public void TestStandardLibraryFeatures() { + // Test .NET Standard 2.0 compatible Dictionary features + var dictionary = new Dictionary(); + dictionary["key1"] = "value1"; + dictionary["key2"] = "value2"; + + // Verify we can use basic LINQ features (.NET Standard 2.0 compatible) + var keys = new List(); + foreach (var kvp in dictionary) { + keys.Add(kvp.Key); + } + + Assert.Equal(2, keys.Count); + Assert.Contains("key1", keys); + Assert.Contains("key2", keys); + } + +#if !NET48 + // Skip on .NET Framework 4.8 as it might not have some of these features + [Fact] + public void TestHttpClientFunctionality() { + // Create an HTTP client (should work across all frameworks) + var client = new System.Net.Http.HttpClient(); + Assert.NotNull(client); + + // Test that we can create basic request messages + var request = new System.Net.Http.HttpRequestMessage( + System.Net.Http.HttpMethod.Get, + "https://example.com"); + + Assert.NotNull(request); + Assert.Equal(System.Net.Http.HttpMethod.Get, request.Method); + } +#endif + } +} \ No newline at end of file diff --git a/src/OpenFga.Sdk.Test/Helpers/FrameworkCompat.cs b/src/OpenFga.Sdk.Test/Helpers/FrameworkCompat.cs new file mode 100644 index 0000000..7e24052 --- /dev/null +++ b/src/OpenFga.Sdk.Test/Helpers/FrameworkCompat.cs @@ -0,0 +1,93 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 1.x +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://openfga.dev/community +// License: [Apache-2.0](https://github.com/openfga/dotnet-sdk/blob/main/LICENSE) +// +// NOTE: This file was auto generated. DO NOT EDIT. +// + + +using System; +using System.Threading.Tasks; + +namespace OpenFga.Sdk.Test.Helpers { + /// + /// Helper utilities for cross-framework testing + /// + public static class FrameworkCompat { + /// + /// Gets a string representation of the current framework + /// + public static string GetFrameworkName() { +#if NET48 + return ".NET Framework 4.8"; +#elif NETCOREAPP3_1 + return ".NET Core 3.1"; +#elif NET6_0 + return ".NET 6.0"; +#else + return "Unknown Framework"; +#endif + } + + /// + /// Run a test with framework-specific code as needed + /// + public static void RunFrameworkSpecificTest( + Action defaultAction, + Action netFrameworkAction = null, + Action netCoreAction = null, + Action net6Action = null) { +#if NET48 + if (netFrameworkAction != null) + netFrameworkAction(); + else + defaultAction(); +#elif NETCOREAPP3_1 + if (netCoreAction != null) + netCoreAction(); + else + defaultAction(); +#elif NET6_0 + if (net6Action != null) + net6Action(); + else + defaultAction(); +#else + defaultAction(); +#endif + } + + /// + /// Run an async test with framework-specific code as needed + /// + public static async Task RunFrameworkSpecificTestAsync( + Func defaultAction, + Func netFrameworkAction = null, + Func netCoreAction = null, + Func net6Action = null) { +#if NET48 + if (netFrameworkAction != null) + await netFrameworkAction(); + else + await defaultAction(); +#elif NETCOREAPP3_1 + if (netCoreAction != null) + await netCoreAction(); + else + await defaultAction(); +#elif NET6_0 + if (net6Action != null) + await net6Action(); + else + await defaultAction(); +#else + await defaultAction(); +#endif + } + } +} \ No newline at end of file diff --git a/src/OpenFga.Sdk.Test/Models/ModelTests.cs b/src/OpenFga.Sdk.Test/Models/ModelTests.cs index 6d126b1..17b878d 100644 --- a/src/OpenFga.Sdk.Test/Models/ModelTests.cs +++ b/src/OpenFga.Sdk.Test/Models/ModelTests.cs @@ -72,7 +72,7 @@ public void DeserializeReadResponse() { [Fact] public void DeserializeReadChangesResponse() { var jsonResponse = - "{\"changes\":[{\"tuple_key\":{\"object\":\"document:planning\",\"relation\":\"viewer\",\"user\":\"user:jane\"},\"operation\":\"TUPLE_OPERATION_WRITE\",\"timestamp\":\"2022-01-01T00:00:00.000000000Z\"},{\"tuple_key\":{\"object\":\"document:roadmap\",\"relation\":\"owner\",\"user\":\"user:anna\"},\"operation\":\"TUPLE_OPERATION_DELETE\",\"timestamp\":\"2022-01-01T00:00:00.000000000Z\"}],\"continuation_token\":\"abcxyz==\"}"; + "{\"changes\":[{\"tuple_key\":{\"object\":\"document:planning\",\"relation\":\"viewer\",\"user\":\"user:jane\"},\"operation\":\"TUPLE_OPERATION_WRITE\",\"timestamp\":\"2022-01-01T00:00:00.000000000Z\"},{\"tuple_key\":{\"object\":\"document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a\",\"relation\":\"owner\",\"user\":\"user:anna\"},\"operation\":\"TUPLE_OPERATION_DELETE\",\"timestamp\":\"2022-01-01T00:00:00.000000000Z\"}],\"continuation_token\":\"abcxyz==\"}"; JsonSerializer.Deserialize(jsonResponse); } @@ -94,7 +94,7 @@ public void DeserializeCheckResponse() { [Fact] public void DeserializeReadAssertionsResponse() { var jsonResponse = - "{\"authorization_model_id\":\"01FQHMTEX3ASF7TAGZZ828KSQ2\",\"assertions\":[{\"tuple_key\":{\"object\":\"document:roadmap\",\"relation\":\"viewer\",\"user\":\"carlos\"},\"expectation\":true}]}"; + "{\"authorization_model_id\":\"01FQHMTEX3ASF7TAGZZ828KSQ2\",\"assertions\":[{\"tuple_key\":{\"object\":\"document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a\",\"relation\":\"viewer\",\"user\":\"carlos\"},\"expectation\":true}]}"; JsonSerializer.Deserialize(jsonResponse); } @@ -105,7 +105,7 @@ public void DeserializeReadAssertionsResponse() { [Fact] public void DeserializeExpandResponse() { var jsonResponse = - "{\"tree\":{\"root\":{\"name\":\"document:roadmap#owner\", \"union\":{\"nodes\":[{\"name\":\"document:roadmap#owner\", \"leaf\":{\"users\":{\"users\":[\"team:product#member\"]}}}, {\"name\":\"document:roadmap#owner\", \"leaf\":{\"tupleToUserset\":{\"tupleset\":\"document:roadmap#owner\", \"computed\":[{\"userset\":\"org:contoso#admin\"}]}}}]}}}}"; + "{\"tree\":{\"root\":{\"name\":\"document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#owner\", \"union\":{\"nodes\":[{\"name\":\"document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#owner\", \"leaf\":{\"users\":{\"users\":[\"team:product#member\"]}}}, {\"name\":\"document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#owner\", \"leaf\":{\"tupleToUserset\":{\"tupleset\":\"document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#owner\", \"computed\":[{\"userset\":\"org:contoso#admin\"}]}}}]}}}}"; JsonSerializer.Deserialize(jsonResponse); } diff --git a/src/OpenFga.Sdk.Test/OpenFga.Sdk.Test.csproj b/src/OpenFga.Sdk.Test/OpenFga.Sdk.Test.csproj index a422fc1..37b71ab 100644 --- a/src/OpenFga.Sdk.Test/OpenFga.Sdk.Test.csproj +++ b/src/OpenFga.Sdk.Test/OpenFga.Sdk.Test.csproj @@ -6,17 +6,19 @@ OpenFga.Sdk.Test net6.0 false + disable + 10.0 - all + all all - all - + all + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers diff --git a/src/OpenFga.Sdk/Api/OpenFgaApi.cs b/src/OpenFga.Sdk/Api/OpenFgaApi.cs index f4fed49..c07fe6e 100644 --- a/src/OpenFga.Sdk/Api/OpenFgaApi.cs +++ b/src/OpenFga.Sdk/Api/OpenFgaApi.cs @@ -36,7 +36,39 @@ public OpenFgaApi( } /// - /// Check whether a user is authorized to access an object The Check API returns whether a given user has a relationship with a given object in a given store. The `user` field of the request can be a specific target, such as `user:anne`, or a userset (set of users) such as `group:marketing#member` or a type-bound public access `user:*`. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). A `contextual_tuples` object may also be included in the body of the request. This object contains one field `tuple_keys`, which is an array of tuple keys. Each of these tuples may have an associated `condition`. You may also provide an `authorization_model_id` in the body. This will be used to assert that the input `tuple_key` is valid for the model specified. If not specified, the assertion will be made against the latest authorization model ID. It is strongly recommended to specify authorization model id for better performance. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will return whether the relationship exists in the field `allowed`. Some exceptions apply, but in general, if a Check API responds with `{allowed: true}`, then you can expect the equivalent ListObjects query to return the object, and viceversa. For example, if `Check(user:anne, reader, document:2021-budget)` responds with `{allowed: true}`, then `ListObjects(user:anne, reader, document)` may include `document:2021-budget` in the response. ## Examples ### Querying with contextual tuples In order to check if user `user:anne` of type `user` has a `reader` relationship with object `document:2021-budget` given the following contextual tuple ```json { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ``` the Check API can be used with the following request body: ```json { \"tuple_key\": { \"user\": \"user:anne\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ] }, \"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\" } ``` ### Querying usersets Some Checks will always return `true`, even without any tuples. For example, for the following authorization model ```python model schema 1.1 type user type document relations define reader: [user] ``` the following query ```json { \"tuple_key\": { \"user\": \"document:2021-budget#reader\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" } } ``` will always return `{ \"allowed\": true }`. This is because usersets are self-defining: the userset `document:2021-budget#reader` will always have the `reader` relation with `document:2021-budget`. ### Querying usersets with difference in the model A Check for a userset can yield results that must be treated carefully if the model involves difference. For example, for the following authorization model ```python model schema 1.1 type user type group relations define member: [user] type document relations define blocked: [user] define reader: [group#member] but not blocked ``` the following query ```json { \"tuple_key\": { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"group:finance\" }, { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, { \"user\": \"user:anne\", \"relation\": \"blocked\", \"object\": \"document:2021-budget\" } ] }, } ``` will return `{ \"allowed\": true }`, even though a specific user of the userset `group:finance#member` does not have the `reader` relationship with the given object. + /// Send a list of `check` operations in a single request The `BatchCheck` API functions nearly identically to `Check`, but instead of checking a single user-object relationship BatchCheck accepts a list of relationships to check and returns a map containing `BatchCheckItem` response for each check it received. An associated `correlation_id` is required for each check in the batch. This ID is used to correlate a check to the appropriate response. It is a string consisting of only alphanumeric characters or hyphens with a maximum length of 36 characters. This `correlation_id` is used to map the result of each check to the item which was checked, so it must be unique for each item in the batch. We recommend using a UUID or ULID as the `correlation_id`, but you can use whatever unique identifier you need as long as it matches this regex pattern: `^[\\w\\d-]{1,36}$` For more details on how `Check` functions, see the docs for `/check`. ### Examples #### A BatchCheckRequest ```json { \"checks\": [ { \"tuple_key\": { \"object\": \"document:2021-budget\" \"relation\": \"reader\", \"user\": \"user:anne\", }, \"contextual_tuples\": {...} \"context\": {} \"correlation_id\": \"01JA8PM3QM7VBPGB8KMPK8SBD5\" }, { \"tuple_key\": { \"object\": \"document:2021-budget\" \"relation\": \"reader\", \"user\": \"user:bob\", }, \"contextual_tuples\": {...} \"context\": {} \"correlation_id\": \"01JA8PMM6A90NV5ET0F28CYSZQ\" } ] } ``` Below is a possible response to the above request. Note that the result map's keys are the `correlation_id` values from the checked items in the request: ```json { \"result\": { \"01JA8PMM6A90NV5ET0F28CYSZQ\": { \"allowed\": false, \"error\": {\"message\": \"\"} }, \"01JA8PM3QM7VBPGB8KMPK8SBD5\": { \"allowed\": true, \"error\": {\"message\": \"\"} } } ``` + /// + /// Thrown when fails to make API call + /// + /// + /// Cancellation Token to cancel the request. + /// Task of BatchCheckResponse + public async Task BatchCheck(string storeId, BatchCheckRequest body, CancellationToken cancellationToken = default) { + var pathParams = new Dictionary { }; + if (string.IsNullOrWhiteSpace(storeId)) { + throw new FgaRequiredParamError("BatchCheck", "StoreId"); + } + + if (storeId != null) { + pathParams.Add("store_id", storeId.ToString()); + } + var queryParams = new Dictionary(); + + var requestBuilder = new RequestBuilder { + Method = new HttpMethod("POST"), + BasePath = _configuration.BasePath, + PathTemplate = "/stores/{store_id}/batch-check", + PathParameters = pathParams, + Body = body, + QueryParameters = queryParams, + }; + + return await _apiClient.SendRequestAsync(requestBuilder, + "BatchCheck", cancellationToken); + } + + /// + /// Check whether a user is authorized to access an object The Check API returns whether a given user has a relationship with a given object in a given store. The `user` field of the request can be a specific target, such as `user:anne`, or a userset (set of users) such as `group:marketing#member` or a type-bound public access `user:*`. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). A `contextual_tuples` object may also be included in the body of the request. This object contains one field `tuple_keys`, which is an array of tuple keys. Each of these tuples may have an associated `condition`. You may also provide an `authorization_model_id` in the body. This will be used to assert that the input `tuple_key` is valid for the model specified. If not specified, the assertion will be made against the latest authorization model ID. It is strongly recommended to specify authorization model id for better performance. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. By default, the Check API caches results for a short time to optimize performance. You may specify a value of `HIGHER_CONSISTENCY` for the optional `consistency` parameter in the body to inform the server that higher conisistency is preferred at the expense of increased latency. Consideration should be given to the increased latency if requesting higher consistency. The response will return whether the relationship exists in the field `allowed`. Some exceptions apply, but in general, if a Check API responds with `{allowed: true}`, then you can expect the equivalent ListObjects query to return the object, and viceversa. For example, if `Check(user:anne, reader, document:2021-budget)` responds with `{allowed: true}`, then `ListObjects(user:anne, reader, document)` may include `document:2021-budget` in the response. ## Examples ### Querying with contextual tuples In order to check if user `user:anne` of type `user` has a `reader` relationship with object `document:2021-budget` given the following contextual tuple ```json { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ``` the Check API can be used with the following request body: ```json { \"tuple_key\": { \"user\": \"user:anne\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ] }, \"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\" } ``` ### Querying usersets Some Checks will always return `true`, even without any tuples. For example, for the following authorization model ```python model schema 1.1 type user type document relations define reader: [user] ``` the following query ```json { \"tuple_key\": { \"user\": \"document:2021-budget#reader\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" } } ``` will always return `{ \"allowed\": true }`. This is because usersets are self-defining: the userset `document:2021-budget#reader` will always have the `reader` relation with `document:2021-budget`. ### Querying usersets with difference in the model A Check for a userset can yield results that must be treated carefully if the model involves difference. For example, for the following authorization model ```python model schema 1.1 type user type group relations define member: [user] type document relations define blocked: [user] define reader: [group#member] but not blocked ``` the following query ```json { \"tuple_key\": { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"group:finance\" }, { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, { \"user\": \"user:anne\", \"relation\": \"blocked\", \"object\": \"document:2021-budget\" } ] }, } ``` will return `{ \"allowed\": true }`, even though a specific user of the userset `group:finance#member` does not have the `reader` relationship with the given object. ### Requesting higher consistency By default, the Check API caches results for a short time to optimize performance. You may request higher consistency to inform the server that higher consistency should be preferred at the expense of increased latency. Care should be taken when requesting higher consistency due to the increased latency. ```json { \"tuple_key\": { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"consistency\": \"HIGHER_CONSISTENCY\" } ``` /// /// Thrown when fails to make API call /// @@ -123,7 +155,7 @@ await _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`. + /// 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. 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`. 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`. ### Expand Request with Contextual Tuples Given the model ```python model schema 1.1 type user type folder relations define owner: [user] type document relations define parent: [folder] define viewer: [user] or writer define writer: [user] or owner from parent ``` and the initial tuples ```json [{ \"user\": \"user:bob\", \"relation\": \"owner\", \"object\": \"folder:1\" }] ``` To expand all `writers` of `document:1` when `document:1` is put in `folder:1`, the first call could be ```json { \"tuple_key\": { \"object\": \"document:1\", \"relation\": \"writer\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"folder:1\", \"relation\": \"parent\", \"object\": \"document:1\" } ] } } ``` this returns: ```json { \"tree\": { \"root\": { \"name\": \"document:1#writer\", \"union\": { \"nodes\": [ { \"name\": \"document:1#writer\", \"leaf\": { \"users\": { \"users\": [] } } }, { \"name\": \"document:1#writer\", \"leaf\": { \"tupleToUserset\": { \"tupleset\": \"document:1#parent\", \"computed\": [ { \"userset\": \"folder:1#owner\" } ] } } } ] } } } } ``` This tells us that the `owner` of `folder:1` may also be a writer. So our next call could be to find the `owners` of `folder:1` ```json { \"tuple_key\": { \"object\": \"folder:1\", \"relation\": \"owner\" } } ``` which gives ```json { \"tree\": { \"root\": { \"name\": \"folder:1#owner\", \"leaf\": { \"users\": { \"users\": [ \"user:bob\" ] } } } } } ``` /// /// Thrown when fails to make API call /// @@ -185,7 +217,7 @@ public async Task GetStore(string storeId, CancellationToken c } /// - /// 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 arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related objects in an array in the \"objects\" field of the response and they will be strings in the object format `<type>:<id>` (e.g. \"document:roadmap\"). The number of objects in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_OBJECTS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_OBJECTS_MAX_RESULTS, whichever is hit first. The objects given will not be sorted, and therefore two identical calls can give a given different set of objects. + /// 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 arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. By default, the Check API caches results for a short time to optimize performance. You may specify a value of `HIGHER_CONSISTENCY` for the optional `consistency` parameter in the body to inform the server that higher conisistency is preferred at the expense of increased latency. Consideration should be given to the increased latency if requesting higher consistency. 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 /// @@ -248,7 +280,7 @@ public async Task ListObjects(string storeId, ListObjectsRe } /// - /// List the users matching the provided filter who have a certain relation to a particular type. The ListUsers API returns a list of all the users of a specific type that have a relation to a given object. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related users in an array in the \"users\" field of the response. These results may include specific objects, usersets or type-bound public access. Each of these types of results is encoded in its own type and not represented as a string.In cases where a type-bound public acces result is returned (e.g. `user:*`), it cannot be inferred that all subjects of that type have a relation to the object; it is possible that negations exist and checks should still be queried on individual subjects to ensure access to that document.The number of users in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_USERS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_USERS_MAX_RESULTS, whichever is hit first. The returned users will not be sorted, and therefore two identical calls may yield different sets of users. + /// List the users matching the provided filter who have a certain relation to a particular type. The ListUsers API returns a list of all the users of a specific type that have a relation to a given object. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related users in an array in the \"users\" field of the response. These results may include specific objects, usersets or type-bound public access. Each of these types of results is encoded in its own type and not represented as a string.In cases where a type-bound public access result is returned (e.g. `user:*`), it cannot be inferred that all subjects of that type have a relation to the object; it is possible that negations exist and checks should still be queried on individual subjects to ensure access to that document.The number of users in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_USERS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_USERS_MAX_RESULTS, whichever is hit first. The returned users will not be sorted, and therefore two identical calls may yield different sets of users. /// /// Thrown when fails to make API call /// @@ -312,7 +344,7 @@ public async Task Read(string storeId, ReadRequest body, Cancellat } /// - /// 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. + /// Read assertions for an authorization model ID The ReadAssertions API will return, for a given authorization model id, all the assertions stored for it. /// /// Thrown when fails to make API call /// @@ -425,9 +457,10 @@ public async Task ReadAuthorizationModel(string /// (optional) /// (optional) /// (optional) + /// Start date and time of changes to read. Format: ISO 8601 timestamp (e.g., 2022-01-01T00:00:00Z) If a continuation_token is provided along side start_time, the continuation_token will take precedence over start_time. (optional) /// Cancellation Token to cancel the request. /// Task of ReadChangesResponse - public async Task ReadChanges(string storeId, 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?), DateTime? startTime = default(DateTime?), CancellationToken cancellationToken = default) { var pathParams = new Dictionary { }; if (string.IsNullOrWhiteSpace(storeId)) { throw new FgaRequiredParamError("ReadChanges", "StoreId"); @@ -446,6 +479,9 @@ public async Task ReadAuthorizationModel(string if (continuationToken != null) { queryParams.Add("continuation_token", continuationToken.ToString()); } + if (startTime != null) { + queryParams.Add("start_time", startTime.ToString()); + } var requestBuilder = new RequestBuilder { Method = new HttpMethod("GET"), @@ -492,7 +528,7 @@ public async Task Write(string storeId, WriteRequest body, CancellationT } /// - /// 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. + /// 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, the expectation of whether a call to the Check API of that tuple key will return true or false, and optionally a list of contextual tuples. /// /// Thrown when fails to make API call /// diff --git a/src/OpenFga.Sdk/ApiClient/ApiClient.cs b/src/OpenFga.Sdk/ApiClient/ApiClient.cs index 923da0d..0b2ea8b 100644 --- a/src/OpenFga.Sdk/ApiClient/ApiClient.cs +++ b/src/OpenFga.Sdk/ApiClient/ApiClient.cs @@ -69,7 +69,8 @@ public ApiClient(Configuration.Configuration configuration, HttpClient? userHttp /// /// /// - /// Response Type + /// Request Type + /// Response Type /// /// public async Task SendRequestAsync(RequestBuilder requestBuilder, string apiName, @@ -108,6 +109,7 @@ await _baseClient.SendRequestAsync(requestBuilder, additionalHeaders /// /// /// + /// Request Type /// public async Task SendRequestAsync(RequestBuilder requestBuilder, string apiName, CancellationToken cancellationToken = default) { diff --git a/src/OpenFga.Sdk/ApiClient/BaseClient.cs b/src/OpenFga.Sdk/ApiClient/BaseClient.cs index 84fc944..fd4db8a 100644 --- a/src/OpenFga.Sdk/ApiClient/BaseClient.cs +++ b/src/OpenFga.Sdk/ApiClient/BaseClient.cs @@ -12,9 +12,6 @@ using OpenFga.Sdk.Exceptions; -using System.Net; -using System.Net.Http.Headers; -using System.Net.Http.Json; namespace OpenFga.Sdk.ApiClient; @@ -124,9 +121,10 @@ public async Task> SendRequestAsync(HttpRequestMessage req T responseContent = default; if (response.Content != null && response.StatusCode != HttpStatusCode.NoContent) { - responseContent = await response.Content.ReadFromJsonAsync(cancellationToken: cancellationToken) - .ConfigureAwait(false) ?? - throw new FgaError(); + var contentString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + if (!string.IsNullOrEmpty(contentString)) { + responseContent = JsonSerializer.Deserialize(contentString) ?? throw new FgaError(); + } } return new ResponseWrapper { rawResponse = response, responseContent = responseContent }; diff --git a/src/OpenFga.Sdk/ApiClient/OAuth2Client.cs b/src/OpenFga.Sdk/ApiClient/OAuth2Client.cs index 32fbabc..e201d43 100644 --- a/src/OpenFga.Sdk/ApiClient/OAuth2Client.cs +++ b/src/OpenFga.Sdk/ApiClient/OAuth2Client.cs @@ -16,7 +16,6 @@ using OpenFga.Sdk.Exceptions; using OpenFga.Sdk.Telemetry; using System.Diagnostics; -using System.Text.Json.Serialization; namespace OpenFga.Sdk.ApiClient; diff --git a/src/OpenFga.Sdk/ApiClient/RequestBuilder.cs b/src/OpenFga.Sdk/ApiClient/RequestBuilder.cs index 355d5ae..daf3533 100644 --- a/src/OpenFga.Sdk/ApiClient/RequestBuilder.cs +++ b/src/OpenFga.Sdk/ApiClient/RequestBuilder.cs @@ -12,9 +12,6 @@ using OpenFga.Sdk.Exceptions; -using System.Text; -using System.Text.Json; -using System.Web; namespace OpenFga.Sdk.ApiClient; diff --git a/src/OpenFga.Sdk/ApiClient/Utils.cs b/src/OpenFga.Sdk/ApiClient/Utils.cs index 0ce521d..ce3c4f5 100644 --- a/src/OpenFga.Sdk/ApiClient/Utils.cs +++ b/src/OpenFga.Sdk/ApiClient/Utils.cs @@ -10,11 +10,6 @@ // NOTE: This file was auto generated. DO NOT EDIT. // - -using System.Text; -using System.Text.Json; -using System.Web; - namespace OpenFga.Sdk.ApiClient; /// diff --git a/src/OpenFga.Sdk/Client/Client.cs b/src/OpenFga.Sdk/Client/Client.cs index 3e71470..5ae6da5 100644 --- a/src/OpenFga.Sdk/Client/Client.cs +++ b/src/OpenFga.Sdk/Client/Client.cs @@ -164,9 +164,9 @@ public async Task ReadAuthorizationModel( * Read Changes - Read the list of historical relationship tuple writes and deletes */ public async Task ReadChanges(ClientReadChangesRequest? body = default, - IClientReadChangesOptions? options = default, + ClientReadChangesOptions? options = default, CancellationToken cancellationToken = default) => - await api.ReadChanges(GetStoreId(options), body?.Type, options?.PageSize, options?.ContinuationToken, cancellationToken); + await api.ReadChanges(GetStoreId(options), body?.Type, options?.PageSize, options?.ContinuationToken, body?.StartTime, cancellationToken); /** * Read - Read tuples previously written to the store (does not evaluate) @@ -225,58 +225,56 @@ 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 writeChunks = body.Writes == null ? new List>() : body.Writes.Chunk(maxPerChunk).ToList(); + var deleteChunks = body.Deletes == null ? new List>() : body.Deletes.Chunk(maxPerChunk).ToList(); var writeResponses = new ConcurrentBag(); var deleteResponses = new ConcurrentBag(); - await Parallel.ForEachAsync(writeChunks, - new ParallelOptions { MaxDegreeOfParallelism = maxParallelReqs }, async (request, token) => { - var writes = request.ToList(); - try { - await this.Write(new ClientWriteRequest() { Writes = writes }, clientWriteOpts, cancellationToken); - - foreach (var tupleKey in writes) { - writeResponses.Add(new ClientWriteSingleResponse { - TupleKey = tupleKey.ToTupleKey(), - Status = ClientWriteStatus.SUCCESS, - }); - } + await writeChunks.ForEachAsync(async (request) => { + var writes = request.ToList(); + try { + await this.Write(new ClientWriteRequest() { Writes = writes }, clientWriteOpts, cancellationToken); + + foreach (var tupleKey in writes) { + writeResponses.Add(new ClientWriteSingleResponse { + TupleKey = tupleKey.ToTupleKey(), + Status = ClientWriteStatus.SUCCESS, + }); } - catch (Exception e) { - foreach (var tupleKey in writes) { - writeResponses.Add(new ClientWriteSingleResponse { - TupleKey = tupleKey.ToTupleKey(), - Status = ClientWriteStatus.FAILURE, - Error = e, - }); - } + } + catch (Exception e) { + foreach (var tupleKey in writes) { + writeResponses.Add(new ClientWriteSingleResponse { + TupleKey = tupleKey.ToTupleKey(), + Status = ClientWriteStatus.FAILURE, + Error = e, + }); } - }); + } + }); + + await deleteChunks.ForEachAsync(async (request) => { + var deletes = request.ToList(); + try { + await this.Write(new ClientWriteRequest() { Deletes = deletes }, clientWriteOpts, cancellationToken); - await Parallel.ForEachAsync(deleteChunks, - new ParallelOptions { MaxDegreeOfParallelism = maxParallelReqs }, async (request, token) => { - var deletes = request.ToList(); - try { - await this.Write(new ClientWriteRequest() { Deletes = deletes }, clientWriteOpts, cancellationToken); - - foreach (var tupleKey in deletes) { - deleteResponses.Add(new ClientWriteSingleResponse { - TupleKey = tupleKey.ToTupleKey(), - Status = ClientWriteStatus.SUCCESS, - }); - } + foreach (var tupleKey in deletes) { + deleteResponses.Add(new ClientWriteSingleResponse { + TupleKey = tupleKey.ToTupleKey(), + Status = ClientWriteStatus.SUCCESS, + }); } - catch (Exception e) { - foreach (var tupleKey in deletes) { - deleteResponses.Add(new ClientWriteSingleResponse { - TupleKey = tupleKey.ToTupleKey(), - Status = ClientWriteStatus.FAILURE, - Error = e, - }); - } + } + catch (Exception e) { + foreach (var tupleKey in deletes) { + deleteResponses.Add(new ClientWriteSingleResponse { + TupleKey = tupleKey.ToTupleKey(), + Status = ClientWriteStatus.FAILURE, + Error = e, + }); } - }); + } + }); return new ClientWriteResponse { Writes = writeResponses.ToList(), Deletes = deleteResponses.ToList() }; } @@ -322,27 +320,26 @@ await api.Check( /** * BatchCheck - Run a set of checks (evaluates) */ - public async Task BatchCheck(List body, + public async Task BatchCheck(List body, IClientBatchCheckOptions? options = default, CancellationToken cancellationToken = default) { var responses = new ConcurrentBag(); - await Parallel.ForEachAsync(body, - new ParallelOptions { MaxDegreeOfParallelism = options?.MaxParallelRequests ?? DEFAULT_MAX_METHOD_PARALLEL_REQS }, async (request, token) => { - try { - var response = await Check(request, options, cancellationToken); - - responses.Add(new BatchCheckSingleResponse { - Allowed = response.Allowed ?? false, - Request = request, - Error = null - }); - } - catch (Exception e) { - responses.Add(new BatchCheckSingleResponse { Allowed = false, Request = request, Error = e }); - } - }); + await body.ForEachAsync(async (request) => { + try { + var response = await Check(request, options, cancellationToken); + + responses.Add(new BatchCheckSingleResponse { + Allowed = response.Allowed ?? false, + Request = request, + Error = null + }); + } + catch (Exception e) { + responses.Add(new BatchCheckSingleResponse { Allowed = false, Request = request, Error = e }); + } + }); - return new BatchCheckResponse { Responses = responses.ToList() }; + return new ClientBatchCheckClientResponse { Responses = responses.ToList() }; } /** diff --git a/src/OpenFga.Sdk/Client/ClientConfiguration.cs b/src/OpenFga.Sdk/Client/ClientConfiguration.cs index 9046971..b0b3348 100644 --- a/src/OpenFga.Sdk/Client/ClientConfiguration.cs +++ b/src/OpenFga.Sdk/Client/ClientConfiguration.cs @@ -13,7 +13,6 @@ using OpenFga.Sdk.Client.Model; using OpenFga.Sdk.Exceptions; -using System.Text.RegularExpressions; namespace OpenFga.Sdk.Client; diff --git a/src/OpenFga.Sdk/Client/ClientExtensions.cs b/src/OpenFga.Sdk/Client/ClientExtensions.cs new file mode 100644 index 0000000..8bcfb85 --- /dev/null +++ b/src/OpenFga.Sdk/Client/ClientExtensions.cs @@ -0,0 +1,59 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 1.x +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://openfga.dev/community +// 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 { + /// + /// Extensions methods for collections + /// + internal static class Extensions { + /// + /// Splits a list into chunks of a specified size. + /// + /// The type of the elements in the list. + /// The source list to chunk. + /// The size of each chunk. + /// An enumerable of chunks. + public static IEnumerable> Chunk(this List source, int chunkSize) { + for (int i = 0; i < source.Count; i += chunkSize) { + yield return source.GetRange(i, Math.Min(chunkSize, source.Count - i)); + } + } + + /// + /// Asynchronously executes an action for each element in a collection. + /// + /// The type of the elements in the source. + /// The source enumerable. + /// The action to execute for each element. + /// The maximum degree of parallelism. + /// A task that represents the completion of all parallel operations. + public static async Task ForEachAsync(this IEnumerable source, Func action, int maxDegreeOfParallelism = 5) { + var tasks = new List(); + var throttler = new SemaphoreSlim(initialCount: maxDegreeOfParallelism); + + foreach (var item in source) { + await throttler.WaitAsync(); + + tasks.Add(Task.Run(async () => { + try { + await action(item); + } + finally { + throttler.Release(); + } + })); + } + + await Task.WhenAll(tasks); + } + } +} \ No newline at end of file diff --git a/src/OpenFga.Sdk/Client/DictionaryExtensions.cs b/src/OpenFga.Sdk/Client/DictionaryExtensions.cs new file mode 100644 index 0000000..4df1f09 --- /dev/null +++ b/src/OpenFga.Sdk/Client/DictionaryExtensions.cs @@ -0,0 +1,35 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 1.x +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://openfga.dev/community +// 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 { + /// + /// Extensions for Dictionary + /// + public static class DictionaryExtensions { + /// + /// Gets the value associated with the specified key if the key exists in the dictionary, or returns the default value. + /// + /// The type of the keys in the dictionary. + /// The type of the values in the dictionary. + /// The dictionary to search in. + /// The key to find. + /// The default value to return if the key is not found. + /// The value associated with the key, or the default value if the key is not found. + public static TValue GetValueOrDefault(this Dictionary dictionary, TKey key, TValue defaultValue = default) { + if (dictionary == null) { + return defaultValue; + } + + return dictionary.TryGetValue(key, out var value) ? value : defaultValue; + } + } +} \ No newline at end of file diff --git a/src/OpenFga.Sdk/Client/Model/ClientBatchCheckResponse.cs b/src/OpenFga.Sdk/Client/Model/ClientBatchCheckResponse.cs index 1067aec..b13d0e9 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientBatchCheckResponse.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientBatchCheckResponse.cs @@ -10,11 +10,6 @@ // NOTE: This file was auto generated. DO NOT EDIT. // - -using System.ComponentModel.DataAnnotations; -using System.Runtime.Serialization; -using System.Text.Json.Serialization; - namespace OpenFga.Sdk.Client.Model; [DataContract(Name = "BatchCheckSingleResponse")] @@ -63,19 +58,19 @@ public IEnumerable Validate(ValidationContext validationContex /// /// CheckResponse /// -[DataContract(Name = "BatchCheckResponse")] -public class BatchCheckResponse : IEquatable, IValidatableObject { +[DataContract(Name = "ClientBatchCheckClientResponse")] +public class ClientBatchCheckClientResponse : IEquatable, IValidatableObject { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - public BatchCheckResponse() { + public ClientBatchCheckClientResponse() { Responses = new List(); } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - public BatchCheckResponse(List responses) { + public ClientBatchCheckClientResponse(List responses) { Responses = responses; } @@ -83,7 +78,7 @@ public BatchCheckResponse(List responses) { [JsonPropertyName("responses")] public List Responses { get; set; } - public bool Equals(BatchCheckResponse? other) => throw new NotImplementedException(); + public bool Equals(ClientBatchCheckClientResponse? other) => throw new NotImplementedException(); public IEnumerable Validate(ValidationContext validationContext) => throw new NotImplementedException(); diff --git a/src/OpenFga.Sdk/Client/Model/ClientCheckRequest.cs b/src/OpenFga.Sdk/Client/Model/ClientCheckRequest.cs index b35efaf..d12d59a 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientCheckRequest.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientCheckRequest.cs @@ -10,12 +10,6 @@ // 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.Client.Model; public interface IClientCheckRequest : IClientQueryContextWrapper { diff --git a/src/OpenFga.Sdk/Client/Model/ClientExpandRequest.cs b/src/OpenFga.Sdk/Client/Model/ClientExpandRequest.cs index a7f3bec..4ef9acf 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientExpandRequest.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientExpandRequest.cs @@ -10,12 +10,6 @@ // 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.Client.Model; /// diff --git a/src/OpenFga.Sdk/Client/Model/ClientListObjectsRequest.cs b/src/OpenFga.Sdk/Client/Model/ClientListObjectsRequest.cs index 41f4b72..7aa24ab 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientListObjectsRequest.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientListObjectsRequest.cs @@ -10,12 +10,6 @@ // 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.Client.Model; public interface IClientListObjectsRequest : IClientQueryContextWrapper { diff --git a/src/OpenFga.Sdk/Client/Model/ClientListRelationsRequest.cs b/src/OpenFga.Sdk/Client/Model/ClientListRelationsRequest.cs index 4a36af1..068cf02 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientListRelationsRequest.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientListRelationsRequest.cs @@ -10,12 +10,6 @@ // 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.Client.Model; public interface IClientListRelationsRequest : IClientQueryContextWrapper { diff --git a/src/OpenFga.Sdk/Client/Model/ClientListRelationsResponse.cs b/src/OpenFga.Sdk/Client/Model/ClientListRelationsResponse.cs index 0e5847e..6ff7ae0 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientListRelationsResponse.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientListRelationsResponse.cs @@ -10,10 +10,6 @@ // NOTE: This file was auto generated. DO NOT EDIT. // - -using System.ComponentModel.DataAnnotations; -using System.Text.Json; - namespace OpenFga.Sdk.Client.Model; internal interface IListRelationsResponse { diff --git a/src/OpenFga.Sdk/Client/Model/ClientListUsersRequest.cs b/src/OpenFga.Sdk/Client/Model/ClientListUsersRequest.cs index 1cc7c2d..6397d1f 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientListUsersRequest.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientListUsersRequest.cs @@ -12,10 +12,6 @@ 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; diff --git a/src/OpenFga.Sdk/Client/Model/ClientReadChangesRequest.cs b/src/OpenFga.Sdk/Client/Model/ClientReadChangesRequest.cs index a154158..6362f72 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientReadChangesRequest.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientReadChangesRequest.cs @@ -10,19 +10,17 @@ // NOTE: This file was auto generated. DO NOT EDIT. // - -using System.ComponentModel.DataAnnotations; -using System.Text.Json; - namespace OpenFga.Sdk.Client.Model; public interface IClientReadChangesRequest { string Type { get; set; } + DateTime? StartTime { get; set; } } public class ClientReadChangesRequest : IClientReadChangesRequest, IEquatable, IValidatableObject { public string Type { get; set; } + public DateTime? StartTime { get; set; } public bool Equals(ClientReadChangesRequest input) { if (input == null) { diff --git a/src/OpenFga.Sdk/Client/Model/ClientTupleKey.cs b/src/OpenFga.Sdk/Client/Model/ClientTupleKey.cs index ee20a6e..c1234fd 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientTupleKey.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientTupleKey.cs @@ -12,10 +12,6 @@ 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; diff --git a/src/OpenFga.Sdk/Client/Model/ClientTupleKeyWithoutCondition.cs b/src/OpenFga.Sdk/Client/Model/ClientTupleKeyWithoutCondition.cs index 9b90069..756c87b 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientTupleKeyWithoutCondition.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientTupleKeyWithoutCondition.cs @@ -12,10 +12,6 @@ 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; diff --git a/src/OpenFga.Sdk/Client/Model/ClientWriteAssertionsRequest.cs b/src/OpenFga.Sdk/Client/Model/ClientWriteAssertionsRequest.cs index fe499d6..63e182a 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientWriteAssertionsRequest.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientWriteAssertionsRequest.cs @@ -10,12 +10,6 @@ // 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.Client.Model; public interface IClientAssertion { diff --git a/src/OpenFga.Sdk/Client/Model/ClientWriteRequest.cs b/src/OpenFga.Sdk/Client/Model/ClientWriteRequest.cs index ae63dda..641d57c 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientWriteRequest.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientWriteRequest.cs @@ -12,10 +12,6 @@ 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; diff --git a/src/OpenFga.Sdk/Client/Model/ClientWriteResponse.cs b/src/OpenFga.Sdk/Client/Model/ClientWriteResponse.cs index a0c77a5..4342485 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientWriteResponse.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientWriteResponse.cs @@ -12,10 +12,6 @@ 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; diff --git a/src/OpenFga.Sdk/Client/Model/ClientWriteStatus.cs b/src/OpenFga.Sdk/Client/Model/ClientWriteStatus.cs index 7a7b994..ed07d12 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientWriteStatus.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientWriteStatus.cs @@ -10,10 +10,6 @@ // NOTE: This file was auto generated. DO NOT EDIT. // - -using System.Runtime.Serialization; -using System.Text.Json.Serialization; - namespace OpenFga.Sdk.Client.Model; /// diff --git a/src/OpenFga.Sdk/Configuration/Configuration.cs b/src/OpenFga.Sdk/Configuration/Configuration.cs index f9042df..bc993a1 100644 --- a/src/OpenFga.Sdk/Configuration/Configuration.cs +++ b/src/OpenFga.Sdk/Configuration/Configuration.cs @@ -148,7 +148,7 @@ public string BasePath { /// Max number of times to retry after a request is rate limited /// /// MaxRetry - public int MaxRetry { get; set; } = 15; + public int MaxRetry { get; set; } = 3; /// /// Minimum time in ms to wait before retrying diff --git a/src/OpenFga.Sdk/Configuration/Credentials.cs b/src/OpenFga.Sdk/Configuration/Credentials.cs index 868b6ef..31a3032 100644 --- a/src/OpenFga.Sdk/Configuration/Credentials.cs +++ b/src/OpenFga.Sdk/Configuration/Credentials.cs @@ -1,5 +1,4 @@ using OpenFga.Sdk.Exceptions; -using System.Runtime.Serialization; namespace OpenFga.Sdk.Configuration; diff --git a/src/OpenFga.Sdk/Configuration/TelemetryConfig.cs b/src/OpenFga.Sdk/Configuration/TelemetryConfig.cs index 5c6b321..4771ee6 100644 --- a/src/OpenFga.Sdk/Configuration/TelemetryConfig.cs +++ b/src/OpenFga.Sdk/Configuration/TelemetryConfig.cs @@ -62,32 +62,24 @@ public TelemetryConfig UseDefaultConfig() { /// /// private static IDictionary GetDefaultMetricsConfiguration() { - var defaultAttributes = new HashSet { - TelemetryAttribute.HttpHost, - TelemetryAttribute.HttpStatus, - TelemetryAttribute.HttpUserAgent, - TelemetryAttribute.RequestMethod, - TelemetryAttribute.RequestClientId, - TelemetryAttribute.RequestStoreId, - TelemetryAttribute.RequestModelId, - TelemetryAttribute.RequestRetryCount, - TelemetryAttribute.ResponseModelId + var defaultAttributes = new HashSet(); + defaultAttributes.Add(TelemetryAttribute.HttpHost); + defaultAttributes.Add(TelemetryAttribute.HttpStatus); + defaultAttributes.Add(TelemetryAttribute.HttpUserAgent); + defaultAttributes.Add(TelemetryAttribute.RequestMethod); + defaultAttributes.Add(TelemetryAttribute.RequestClientId); + defaultAttributes.Add(TelemetryAttribute.RequestStoreId); + defaultAttributes.Add(TelemetryAttribute.RequestModelId); + defaultAttributes.Add(TelemetryAttribute.RequestRetryCount); + defaultAttributes.Add(TelemetryAttribute.ResponseModelId); - // These metrics are not included by default because they are usually less useful - // TelemetryAttribute.HttpScheme, - // TelemetryAttribute.HttpMethod, - // TelemetryAttribute.HttpUrl, + var metricsConfig = new Dictionary(); + metricsConfig.Add(TelemetryMeter.TokenExchangeCount, new MetricConfig { Attributes = defaultAttributes }); + metricsConfig.Add(TelemetryMeter.RequestDuration, new MetricConfig { Attributes = defaultAttributes }); + metricsConfig.Add(TelemetryMeter.QueryDuration, new MetricConfig { Attributes = defaultAttributes }); + // metricsConfig.Add(TelemetryMeter.RequestCount, new MetricConfig { Attributes = defaultAttributes }); - // This not included by default as it has a very high cardinality which could increase costs for users - // TelemetryAttribute.FgaRequestUser - }; - - return new Dictionary { - { TelemetryMeter.TokenExchangeCount, new MetricConfig { Attributes = defaultAttributes } }, - { TelemetryMeter.RequestDuration, new MetricConfig { Attributes = defaultAttributes } }, - { TelemetryMeter.QueryDuration, new MetricConfig { Attributes = defaultAttributes } }, - // { TelemetryMeters.RequestCount, new MetricConfig { Attributes = defaultAttributes } } - }; + return metricsConfig; } /// diff --git a/src/OpenFga.Sdk/Exceptions/ApiAuthenticationError.cs b/src/OpenFga.Sdk/Exceptions/ApiAuthenticationError.cs index 08af8c8..770dc3d 100644 --- a/src/OpenFga.Sdk/Exceptions/ApiAuthenticationError.cs +++ b/src/OpenFga.Sdk/Exceptions/ApiAuthenticationError.cs @@ -12,7 +12,6 @@ using OpenFga.Sdk.Exceptions.Parsers; -using System.Net; namespace OpenFga.Sdk.Exceptions; diff --git a/src/OpenFga.Sdk/Exceptions/ApiError.cs b/src/OpenFga.Sdk/Exceptions/ApiError.cs index 81993ba..3fe9d98 100644 --- a/src/OpenFga.Sdk/Exceptions/ApiError.cs +++ b/src/OpenFga.Sdk/Exceptions/ApiError.cs @@ -12,9 +12,6 @@ using OpenFga.Sdk.Exceptions.Parsers; -using System.Net; -using System.Net.Http.Headers; -using System.Text.Json.Serialization; namespace OpenFga.Sdk.Exceptions; @@ -143,7 +140,7 @@ public FgaApiError(HttpStatusCode statusCode, ApiErrorParser? apiError = null) /// public FgaApiError(HttpResponseMessage? response, HttpRequestMessage request, string? apiName, ApiErrorParser? apiError = null, bool shouldRetry = false) : this((apiError == null ? (response?.StatusCode.ToString()) : apiError.Message) ?? string.Empty) { - var requestPaths = request.RequestUri?.LocalPath.Split("/") ?? Array.Empty(); + var requestPaths = request.RequestUri?.LocalPath.Split(new[] { '/' }) ?? Array.Empty(); var storeId = requestPaths.Length > 2 ? requestPaths[2] : null; StatusCode = response?.StatusCode ?? HttpStatusCode.InternalServerError; diff --git a/src/OpenFga.Sdk/Exceptions/ApiException.cs b/src/OpenFga.Sdk/Exceptions/ApiException.cs index 803f96b..3c8e4ba 100644 --- a/src/OpenFga.Sdk/Exceptions/ApiException.cs +++ b/src/OpenFga.Sdk/Exceptions/ApiException.cs @@ -10,10 +10,6 @@ // NOTE: This file was auto generated. DO NOT EDIT. // - -using System.Net; -using System.Runtime.Serialization; - namespace OpenFga.Sdk.Exceptions; public class ApiException : Exception { @@ -58,22 +54,34 @@ protected ApiException(SerializationInfo serializationInfo, StreamingContext str public static async Task CreateSpecificExceptionAsync(HttpResponseMessage? response, HttpRequestMessage request, string? apiName = null) { var statusCode = response?.StatusCode; - switch (statusCode) { - case HttpStatusCode.Unauthorized: - case HttpStatusCode.Forbidden: - return await FgaApiAuthenticationError.CreateAsync(response, request, apiName).ConfigureAwait(false); - case HttpStatusCode.BadRequest: - case HttpStatusCode.UnprocessableEntity: - return await FgaApiValidationError.CreateAsync(response, request, apiName).ConfigureAwait(false); - case HttpStatusCode.NotFound: - return await FgaApiNotFoundError.CreateAsync(response, request, apiName).ConfigureAwait(false); - case HttpStatusCode.TooManyRequests: - return await FgaApiRateLimitExceededError.CreateAsync(response, request, apiName).ConfigureAwait(false); - default: - if (statusCode >= HttpStatusCode.InternalServerError && statusCode != HttpStatusCode.NotImplemented) { - return await FgaApiInternalError.CreateAsync(response, request, apiName).ConfigureAwait(false); - } - return await FgaApiError.CreateAsync(response, request, apiName).ConfigureAwait(false); + + // Handle authentication errors + if (statusCode == HttpStatusCode.Unauthorized || statusCode == HttpStatusCode.Forbidden) { + return await FgaApiAuthenticationError.CreateAsync(response, request, apiName).ConfigureAwait(false); + } + + // Handle validation errors + if (statusCode == HttpStatusCode.BadRequest || + statusCode == HttpStatusCodeExtensions.UnprocessableEntity) { + return await FgaApiValidationError.CreateAsync(response, request, apiName).ConfigureAwait(false); + } + + // Handle not found errors + if (statusCode == HttpStatusCode.NotFound) { + return await FgaApiNotFoundError.CreateAsync(response, request, apiName).ConfigureAwait(false); + } + + // Handle rate limit errors + if (statusCode == HttpStatusCodeExtensions.TooManyRequests) { + return await FgaApiRateLimitExceededError.CreateAsync(response, request, apiName).ConfigureAwait(false); } + + // Handle other errors + if (statusCode >= HttpStatusCode.InternalServerError && statusCode != HttpStatusCode.NotImplemented) { + return await FgaApiInternalError.CreateAsync(response, request, apiName).ConfigureAwait(false); + } + + // Default case + return await FgaApiError.CreateAsync(response, request, apiName).ConfigureAwait(false); } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Exceptions/Parsers/ApiErrorParser.cs b/src/OpenFga.Sdk/Exceptions/Parsers/ApiErrorParser.cs index bc2be93..6659fd6 100644 --- a/src/OpenFga.Sdk/Exceptions/Parsers/ApiErrorParser.cs +++ b/src/OpenFga.Sdk/Exceptions/Parsers/ApiErrorParser.cs @@ -10,10 +10,6 @@ // NOTE: This file was auto generated. DO NOT EDIT. // - -using System.Text.Json; -using System.Text.Json.Serialization; - namespace OpenFga.Sdk.Exceptions.Parsers; public class ApiErrorParser { diff --git a/src/OpenFga.Sdk/Exceptions/Parsers/RateLimitParser.cs b/src/OpenFga.Sdk/Exceptions/Parsers/RateLimitParser.cs index 0603dfb..6dab503 100644 --- a/src/OpenFga.Sdk/Exceptions/Parsers/RateLimitParser.cs +++ b/src/OpenFga.Sdk/Exceptions/Parsers/RateLimitParser.cs @@ -10,10 +10,6 @@ // NOTE: This file was auto generated. DO NOT EDIT. // - -using System.Net.Http.Headers; -using System.Runtime.Serialization; - namespace OpenFga.Sdk.Exceptions.Parsers; /// diff --git a/src/OpenFga.Sdk/GlobalUsings.cs b/src/OpenFga.Sdk/GlobalUsings.cs new file mode 100644 index 0000000..01f8b59 --- /dev/null +++ b/src/OpenFga.Sdk/GlobalUsings.cs @@ -0,0 +1,28 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 1.x +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://openfga.dev/community +// License: [Apache-2.0](https://github.com/openfga/dotnet-sdk/blob/main/LICENSE) +// +// NOTE: This file was auto generated. DO NOT EDIT. +// + + +global using System; +global using System.Collections.Generic; +global using System.ComponentModel.DataAnnotations; +global using System.Linq; +global using System.Net; +global using System.Net.Http; +global using System.Net.Http.Headers; +global using System.Runtime.Serialization; +global using System.Text; +global using System.Text.Json; +global using System.Text.Json.Serialization; +global using System.Text.RegularExpressions; +global using System.Threading; +global using System.Threading.Tasks; +global using System.Web; \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/AbortedMessageResponse.cs b/src/OpenFga.Sdk/Model/AbortedMessageResponse.cs index eef8731..775ec79 100644 --- a/src/OpenFga.Sdk/Model/AbortedMessageResponse.cs +++ b/src/OpenFga.Sdk/Model/AbortedMessageResponse.cs @@ -10,12 +10,6 @@ // 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 diff --git a/src/OpenFga.Sdk/Model/Any.cs b/src/OpenFga.Sdk/Model/Any.cs index b08db5d..0ab3d3c 100644 --- a/src/OpenFga.Sdk/Model/Any.cs +++ b/src/OpenFga.Sdk/Model/Any.cs @@ -10,12 +10,6 @@ // 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 { /// /// Any diff --git a/src/OpenFga.Sdk/Model/Assertion.cs b/src/OpenFga.Sdk/Model/Assertion.cs index 0827ac6..d318949 100644 --- a/src/OpenFga.Sdk/Model/Assertion.cs +++ b/src/OpenFga.Sdk/Model/Assertion.cs @@ -10,12 +10,6 @@ // 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 { /// /// Assertion @@ -35,13 +29,17 @@ public Assertion() { /// /// tupleKey (required). /// expectation (required). - public Assertion(AssertionTupleKey tupleKey = default(AssertionTupleKey), bool expectation = default(bool)) { + /// contextualTuples. + /// Additional request context that will be used to evaluate any ABAC conditions encountered in the query evaluation.. + public Assertion(AssertionTupleKey tupleKey = default(AssertionTupleKey), bool expectation = default(bool), List contextualTuples = default(List), Object context = default(Object)) { // to ensure "tupleKey" is required (not null) if (tupleKey == null) { throw new ArgumentNullException("tupleKey is a required property for Assertion and cannot be null"); } this.TupleKey = tupleKey; this.Expectation = expectation; + this.ContextualTuples = contextualTuples; + this.Context = context; this.AdditionalProperties = new Dictionary(); } @@ -61,6 +59,23 @@ public Assertion() { [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool Expectation { get; set; } + /// + /// Gets or Sets ContextualTuples + /// + [DataMember(Name = "contextual_tuples", EmitDefaultValue = false)] + [JsonPropertyName("contextual_tuples")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public List? 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 /// @@ -111,6 +126,17 @@ public bool Equals(Assertion input) { ( this.Expectation == input.Expectation || this.Expectation.Equals(input.Expectation) + ) && + ( + this.ContextualTuples == input.ContextualTuples || + this.ContextualTuples != null && + input.ContextualTuples != null && + this.ContextualTuples.SequenceEqual(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()); } @@ -127,6 +153,12 @@ public override int GetHashCode() { hashCode = (hashCode * 9923) + this.TupleKey.GetHashCode(); } hashCode = (hashCode * 9923) + this.Expectation.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/AssertionTupleKey.cs b/src/OpenFga.Sdk/Model/AssertionTupleKey.cs index e0737b5..3526acf 100644 --- a/src/OpenFga.Sdk/Model/AssertionTupleKey.cs +++ b/src/OpenFga.Sdk/Model/AssertionTupleKey.cs @@ -10,12 +10,6 @@ // 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 diff --git a/src/OpenFga.Sdk/Model/AuthErrorCode.cs b/src/OpenFga.Sdk/Model/AuthErrorCode.cs new file mode 100644 index 0000000..f39bad5 --- /dev/null +++ b/src/OpenFga.Sdk/Model/AuthErrorCode.cs @@ -0,0 +1,75 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 1.x +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://openfga.dev/community +// 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.Model { + /// + /// Defines AuthErrorCode + /// + [JsonConverter(typeof(JsonStringEnumMemberConverter))] + public enum AuthErrorCode { + /// + /// Enum NoAuthError for value: no_auth_error + /// + [EnumMember(Value = "no_auth_error")] + NoAuthError = 1, + + /// + /// Enum AuthFailedInvalidSubject for value: auth_failed_invalid_subject + /// + [EnumMember(Value = "auth_failed_invalid_subject")] + AuthFailedInvalidSubject = 2, + + /// + /// Enum AuthFailedInvalidAudience for value: auth_failed_invalid_audience + /// + [EnumMember(Value = "auth_failed_invalid_audience")] + AuthFailedInvalidAudience = 3, + + /// + /// Enum AuthFailedInvalidIssuer for value: auth_failed_invalid_issuer + /// + [EnumMember(Value = "auth_failed_invalid_issuer")] + AuthFailedInvalidIssuer = 4, + + /// + /// Enum InvalidClaims for value: invalid_claims + /// + [EnumMember(Value = "invalid_claims")] + InvalidClaims = 5, + + /// + /// Enum AuthFailedInvalidBearerToken for value: auth_failed_invalid_bearer_token + /// + [EnumMember(Value = "auth_failed_invalid_bearer_token")] + AuthFailedInvalidBearerToken = 6, + + /// + /// Enum BearerTokenMissing for value: bearer_token_missing + /// + [EnumMember(Value = "bearer_token_missing")] + BearerTokenMissing = 7, + + /// + /// Enum Unauthenticated for value: unauthenticated + /// + [EnumMember(Value = "unauthenticated")] + Unauthenticated = 8, + + /// + /// Enum Forbidden for value: forbidden + /// + [EnumMember(Value = "forbidden")] + Forbidden = 9 + + } + +} \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/AuthorizationModel.cs b/src/OpenFga.Sdk/Model/AuthorizationModel.cs index 9a56bf2..002259e 100644 --- a/src/OpenFga.Sdk/Model/AuthorizationModel.cs +++ b/src/OpenFga.Sdk/Model/AuthorizationModel.cs @@ -10,12 +10,6 @@ // 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 { /// /// AuthorizationModel diff --git a/src/OpenFga.Sdk/Model/BatchCheckItem.cs b/src/OpenFga.Sdk/Model/BatchCheckItem.cs new file mode 100644 index 0000000..d8239e7 --- /dev/null +++ b/src/OpenFga.Sdk/Model/BatchCheckItem.cs @@ -0,0 +1,186 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 1.x +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://openfga.dev/community +// 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.Model { + /// + /// BatchCheckItem + /// + [DataContract(Name = "BatchCheckItem")] + public partial class BatchCheckItem : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public BatchCheckItem() { + this.AdditionalProperties = new Dictionary(); + } + + /// + /// Initializes a new instance of the class. + /// + /// tupleKey (required). + /// contextualTuples. + /// context. + /// correlation_id must be a string containing only letters, numbers, or hyphens, with length ≤ 36 characters. (required). + public BatchCheckItem(CheckRequestTupleKey tupleKey = default(CheckRequestTupleKey), ContextualTupleKeys contextualTuples = default(ContextualTupleKeys), Object context = default(Object), string correlationId = default(string)) { + // to ensure "tupleKey" is required (not null) + if (tupleKey == null) { + throw new ArgumentNullException("tupleKey is a required property for BatchCheckItem and cannot be null"); + } + this.TupleKey = tupleKey; + // to ensure "correlationId" is required (not null) + if (correlationId == null) { + throw new ArgumentNullException("correlationId is a required property for BatchCheckItem and cannot be null"); + } + this.CorrelationId = correlationId; + this.ContextualTuples = contextualTuples; + this.Context = context; + this.AdditionalProperties = new Dictionary(); + } + + /// + /// Gets or Sets TupleKey + /// + [DataMember(Name = "tuple_key", IsRequired = true, EmitDefaultValue = false)] + [JsonPropertyName("tuple_key")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public CheckRequestTupleKey TupleKey { get; set; } + + /// + /// Gets or Sets ContextualTuples + /// + [DataMember(Name = "contextual_tuples", EmitDefaultValue = false)] + [JsonPropertyName("contextual_tuples")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public ContextualTupleKeys? ContextualTuples { get; set; } + + /// + /// Gets or Sets Context + /// + [DataMember(Name = "context", EmitDefaultValue = false)] + [JsonPropertyName("context")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public Object? Context { get; set; } + + /// + /// correlation_id must be a string containing only letters, numbers, or hyphens, with length ≤ 36 characters. + /// + /// correlation_id must be a string containing only letters, numbers, or hyphens, with length ≤ 36 characters. + [DataMember(Name = "correlation_id", IsRequired = true, EmitDefaultValue = false)] + [JsonPropertyName("correlation_id")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string CorrelationId { 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 BatchCheckItem from the JSON string presentation of the object + /// + /// BatchCheckItem + public static BatchCheckItem 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 BatchCheckItem); + } + + /// + /// Returns true if BatchCheckItem instances are equal + /// + /// Instance of BatchCheckItem to be compared + /// Boolean + public bool Equals(BatchCheckItem input) { + if (input == null) { + return false; + } + return + ( + this.TupleKey == input.TupleKey || + (this.TupleKey != null && + this.TupleKey.Equals(input.TupleKey)) + ) && + ( + 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.CorrelationId == input.CorrelationId || + (this.CorrelationId != null && + this.CorrelationId.Equals(input.CorrelationId)) + ) + && (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.TupleKey != null) { + hashCode = (hashCode * 9923) + this.TupleKey.GetHashCode(); + } + if (this.ContextualTuples != null) { + hashCode = (hashCode * 9923) + this.ContextualTuples.GetHashCode(); + } + if (this.Context != null) { + hashCode = (hashCode * 9923) + this.Context.GetHashCode(); + } + if (this.CorrelationId != null) { + hashCode = (hashCode * 9923) + this.CorrelationId.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/BatchCheckRequest.cs b/src/OpenFga.Sdk/Model/BatchCheckRequest.cs new file mode 100644 index 0000000..e3508fe --- /dev/null +++ b/src/OpenFga.Sdk/Model/BatchCheckRequest.cs @@ -0,0 +1,160 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 1.x +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://openfga.dev/community +// 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.Model { + /// + /// BatchCheckRequest + /// + [DataContract(Name = "BatchCheck_request")] + public partial class BatchCheckRequest : IEquatable, IValidatableObject { + + /// + /// Gets or Sets Consistency + /// + [DataMember(Name = "consistency", EmitDefaultValue = false)] + [JsonPropertyName("consistency")] + public ConsistencyPreference? Consistency { get; set; } + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public BatchCheckRequest() { + this.AdditionalProperties = new Dictionary(); + } + + /// + /// Initializes a new instance of the class. + /// + /// checks (required). + /// authorizationModelId. + /// consistency. + public BatchCheckRequest(List checks = default(List), string authorizationModelId = default(string), ConsistencyPreference? consistency = default(ConsistencyPreference?)) { + // to ensure "checks" is required (not null) + if (checks == null) { + throw new ArgumentNullException("checks is a required property for BatchCheckRequest and cannot be null"); + } + this.Checks = checks; + this.AuthorizationModelId = authorizationModelId; + this.Consistency = consistency; + this.AdditionalProperties = new Dictionary(); + } + + /// + /// Gets or Sets Checks + /// + [DataMember(Name = "checks", IsRequired = true, EmitDefaultValue = false)] + [JsonPropertyName("checks")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public List Checks { get; set; } + + /// + /// Gets or Sets AuthorizationModelId + /// + [DataMember(Name = "authorization_model_id", EmitDefaultValue = false)] + [JsonPropertyName("authorization_model_id")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string? AuthorizationModelId { 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 BatchCheckRequest from the JSON string presentation of the object + /// + /// BatchCheckRequest + public static BatchCheckRequest 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 BatchCheckRequest); + } + + /// + /// Returns true if BatchCheckRequest instances are equal + /// + /// Instance of BatchCheckRequest to be compared + /// Boolean + public bool Equals(BatchCheckRequest input) { + if (input == null) { + return false; + } + return + ( + this.Checks == input.Checks || + this.Checks != null && + input.Checks != null && + this.Checks.SequenceEqual(input.Checks) + ) && + ( + this.AuthorizationModelId == input.AuthorizationModelId || + (this.AuthorizationModelId != null && + this.AuthorizationModelId.Equals(input.AuthorizationModelId)) + ) && + ( + this.Consistency == input.Consistency || + this.Consistency.Equals(input.Consistency) + ) + && (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.Checks != null) { + hashCode = (hashCode * 9923) + this.Checks.GetHashCode(); + } + if (this.AuthorizationModelId != null) { + hashCode = (hashCode * 9923) + this.AuthorizationModelId.GetHashCode(); + } + hashCode = (hashCode * 9923) + this.Consistency.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/BatchCheckResponse.cs b/src/OpenFga.Sdk/Model/BatchCheckResponse.cs new file mode 100644 index 0000000..cc4799e --- /dev/null +++ b/src/OpenFga.Sdk/Model/BatchCheckResponse.cs @@ -0,0 +1,125 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 1.x +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://openfga.dev/community +// 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.Model { + /// + /// BatchCheckResponse + /// + [DataContract(Name = "BatchCheckResponse")] + public partial class BatchCheckResponse : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public BatchCheckResponse() { + this.AdditionalProperties = new Dictionary(); + } + + /// + /// Initializes a new instance of the class. + /// + /// map keys are the correlation_id values from the BatchCheckItems in the request. + public BatchCheckResponse(Dictionary result = default(Dictionary)) { + this.Result = result; + this.AdditionalProperties = new Dictionary(); + } + + /// + /// map keys are the correlation_id values from the BatchCheckItems in the request + /// + /// map keys are the correlation_id values from the BatchCheckItems in the request + [DataMember(Name = "result", EmitDefaultValue = false)] + [JsonPropertyName("result")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public Dictionary? Result { 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 BatchCheckResponse from the JSON string presentation of the object + /// + /// BatchCheckResponse + public static BatchCheckResponse 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 BatchCheckResponse); + } + + /// + /// Returns true if BatchCheckResponse instances are equal + /// + /// Instance of BatchCheckResponse to be compared + /// Boolean + public bool Equals(BatchCheckResponse input) { + if (input == null) { + return false; + } + return + ( + this.Result == input.Result || + this.Result != null && + input.Result != null && + this.Result.SequenceEqual(input.Result) + ) + && (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.Result != null) { + hashCode = (hashCode * 9923) + this.Result.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/BatchCheckSingleResult.cs b/src/OpenFga.Sdk/Model/BatchCheckSingleResult.cs new file mode 100644 index 0000000..495de35 --- /dev/null +++ b/src/OpenFga.Sdk/Model/BatchCheckSingleResult.cs @@ -0,0 +1,138 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 1.x +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://openfga.dev/community +// 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.Model { + /// + /// BatchCheckSingleResult + /// + [DataContract(Name = "BatchCheckSingleResult")] + public partial class BatchCheckSingleResult : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public BatchCheckSingleResult() { + this.AdditionalProperties = new Dictionary(); + } + + /// + /// Initializes a new instance of the class. + /// + /// allowed. + /// error. + public BatchCheckSingleResult(bool allowed = default(bool), CheckError error = default(CheckError)) { + this.Allowed = allowed; + this.Error = error; + this.AdditionalProperties = new Dictionary(); + } + + /// + /// Gets or Sets Allowed + /// + [DataMember(Name = "allowed", EmitDefaultValue = true)] + [JsonPropertyName("allowed")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool? Allowed { get; set; } + + /// + /// Gets or Sets Error + /// + [DataMember(Name = "error", EmitDefaultValue = false)] + [JsonPropertyName("error")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public CheckError? Error { 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 BatchCheckSingleResult from the JSON string presentation of the object + /// + /// BatchCheckSingleResult + public static BatchCheckSingleResult 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 BatchCheckSingleResult); + } + + /// + /// Returns true if BatchCheckSingleResult instances are equal + /// + /// Instance of BatchCheckSingleResult to be compared + /// Boolean + public bool Equals(BatchCheckSingleResult input) { + if (input == null) { + return false; + } + return + ( + this.Allowed == input.Allowed || + this.Allowed.Equals(input.Allowed) + ) && + ( + this.Error == input.Error || + (this.Error != null && + this.Error.Equals(input.Error)) + ) + && (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.Allowed.GetHashCode(); + if (this.Error != null) { + hashCode = (hashCode * 9923) + this.Error.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/CheckError.cs b/src/OpenFga.Sdk/Model/CheckError.cs new file mode 100644 index 0000000..ac32838 --- /dev/null +++ b/src/OpenFga.Sdk/Model/CheckError.cs @@ -0,0 +1,151 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 1.x +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://openfga.dev/community +// 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.Model { + /// + /// CheckError + /// + [DataContract(Name = "CheckError")] + public partial class CheckError : IEquatable, IValidatableObject { + + /// + /// Gets or Sets InputError + /// + [DataMember(Name = "input_error", EmitDefaultValue = false)] + [JsonPropertyName("input_error")] + public ErrorCode? InputError { get; set; } + + /// + /// Gets or Sets InternalError + /// + [DataMember(Name = "internal_error", EmitDefaultValue = false)] + [JsonPropertyName("internal_error")] + public InternalErrorCode? InternalError { get; set; } + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public CheckError() { + this.AdditionalProperties = new Dictionary(); + } + + /// + /// Initializes a new instance of the class. + /// + /// inputError. + /// internalError. + /// message. + public CheckError(ErrorCode? inputError = default(ErrorCode?), InternalErrorCode? internalError = default(InternalErrorCode?), string message = default(string)) { + this.InputError = inputError; + this.InternalError = internalError; + this.Message = message; + this.AdditionalProperties = new Dictionary(); + } + + /// + /// 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 CheckError from the JSON string presentation of the object + /// + /// CheckError + public static CheckError 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 CheckError); + } + + /// + /// Returns true if CheckError instances are equal + /// + /// Instance of CheckError to be compared + /// Boolean + public bool Equals(CheckError input) { + if (input == null) { + return false; + } + return + ( + this.InputError == input.InputError || + this.InputError.Equals(input.InputError) + ) && + ( + this.InternalError == input.InternalError || + this.InternalError.Equals(input.InternalError) + ) && + ( + 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; + hashCode = (hashCode * 9923) + this.InputError.GetHashCode(); + hashCode = (hashCode * 9923) + this.InternalError.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/CheckRequest.cs b/src/OpenFga.Sdk/Model/CheckRequest.cs index a907d6d..e21cff8 100644 --- a/src/OpenFga.Sdk/Model/CheckRequest.cs +++ b/src/OpenFga.Sdk/Model/CheckRequest.cs @@ -10,12 +10,6 @@ // 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 { /// /// CheckRequest diff --git a/src/OpenFga.Sdk/Model/CheckRequestTupleKey.cs b/src/OpenFga.Sdk/Model/CheckRequestTupleKey.cs index 5bfcb1a..f69b8ae 100644 --- a/src/OpenFga.Sdk/Model/CheckRequestTupleKey.cs +++ b/src/OpenFga.Sdk/Model/CheckRequestTupleKey.cs @@ -10,12 +10,6 @@ // 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 diff --git a/src/OpenFga.Sdk/Model/CheckResponse.cs b/src/OpenFga.Sdk/Model/CheckResponse.cs index 45f1dd7..87f1dee 100644 --- a/src/OpenFga.Sdk/Model/CheckResponse.cs +++ b/src/OpenFga.Sdk/Model/CheckResponse.cs @@ -10,12 +10,6 @@ // 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 { /// /// CheckResponse diff --git a/src/OpenFga.Sdk/Model/Computed.cs b/src/OpenFga.Sdk/Model/Computed.cs index 5658d39..e8d1eb3 100644 --- a/src/OpenFga.Sdk/Model/Computed.cs +++ b/src/OpenFga.Sdk/Model/Computed.cs @@ -10,12 +10,6 @@ // 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 { /// /// Computed diff --git a/src/OpenFga.Sdk/Model/Condition.cs b/src/OpenFga.Sdk/Model/Condition.cs index e27cadc..77aa505 100644 --- a/src/OpenFga.Sdk/Model/Condition.cs +++ b/src/OpenFga.Sdk/Model/Condition.cs @@ -10,12 +10,6 @@ // 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 diff --git a/src/OpenFga.Sdk/Model/ConditionMetadata.cs b/src/OpenFga.Sdk/Model/ConditionMetadata.cs index 0a175ec..0c888ab 100644 --- a/src/OpenFga.Sdk/Model/ConditionMetadata.cs +++ b/src/OpenFga.Sdk/Model/ConditionMetadata.cs @@ -10,12 +10,6 @@ // 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 { /// /// ConditionMetadata diff --git a/src/OpenFga.Sdk/Model/ConditionParamTypeRef.cs b/src/OpenFga.Sdk/Model/ConditionParamTypeRef.cs index 17a33d4..1b0a48d 100644 --- a/src/OpenFga.Sdk/Model/ConditionParamTypeRef.cs +++ b/src/OpenFga.Sdk/Model/ConditionParamTypeRef.cs @@ -10,12 +10,6 @@ // 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 diff --git a/src/OpenFga.Sdk/Model/ConsistencyPreference.cs b/src/OpenFga.Sdk/Model/ConsistencyPreference.cs index eb2c556..8658648 100644 --- a/src/OpenFga.Sdk/Model/ConsistencyPreference.cs +++ b/src/OpenFga.Sdk/Model/ConsistencyPreference.cs @@ -10,15 +10,11 @@ // NOTE: This file was auto generated. DO NOT EDIT. // - -using System.Runtime.Serialization; -using System.Text.Json.Serialization; - namespace OpenFga.Sdk.Model { /// - /// - UNSPECIFIED: Default if not set. Behavior will be the same as MINIMIZE_LATENCY - MINIMIZE_LATENCY: Minimize latency at the potential expense of lower consistency. - HIGHER_CONSISTENCY: Prefer higher consistency, at the potential expense of increased latency. + /// Controls the consistency preferences when calling the query APIs. - UNSPECIFIED: Default if not set. Behavior will be the same as MINIMIZE_LATENCY. - MINIMIZE_LATENCY: Minimize latency at the potential expense of lower consistency. - HIGHER_CONSISTENCY: Prefer higher consistency, at the potential expense of increased latency. /// - /// - UNSPECIFIED: Default if not set. Behavior will be the same as MINIMIZE_LATENCY - MINIMIZE_LATENCY: Minimize latency at the potential expense of lower consistency. - HIGHER_CONSISTENCY: Prefer higher consistency, at the potential expense of increased latency. + /// Controls the consistency preferences when calling the query APIs. - UNSPECIFIED: Default if not set. Behavior will be the same as MINIMIZE_LATENCY. - MINIMIZE_LATENCY: Minimize latency at the potential expense of lower consistency. - HIGHER_CONSISTENCY: Prefer higher consistency, at the potential expense of increased latency. [JsonConverter(typeof(JsonStringEnumMemberConverter))] public enum ConsistencyPreference { /// diff --git a/src/OpenFga.Sdk/Model/ContextualTupleKeys.cs b/src/OpenFga.Sdk/Model/ContextualTupleKeys.cs index bf08cf3..c912c04 100644 --- a/src/OpenFga.Sdk/Model/ContextualTupleKeys.cs +++ b/src/OpenFga.Sdk/Model/ContextualTupleKeys.cs @@ -10,12 +10,6 @@ // 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 { /// /// ContextualTupleKeys diff --git a/src/OpenFga.Sdk/Model/CreateStoreRequest.cs b/src/OpenFga.Sdk/Model/CreateStoreRequest.cs index 441af4e..58c9cef 100644 --- a/src/OpenFga.Sdk/Model/CreateStoreRequest.cs +++ b/src/OpenFga.Sdk/Model/CreateStoreRequest.cs @@ -10,12 +10,6 @@ // 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 { /// /// CreateStoreRequest diff --git a/src/OpenFga.Sdk/Model/CreateStoreResponse.cs b/src/OpenFga.Sdk/Model/CreateStoreResponse.cs index 3bad1fb..b962a59 100644 --- a/src/OpenFga.Sdk/Model/CreateStoreResponse.cs +++ b/src/OpenFga.Sdk/Model/CreateStoreResponse.cs @@ -10,12 +10,6 @@ // 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 { /// /// CreateStoreResponse diff --git a/src/OpenFga.Sdk/Model/Difference.cs b/src/OpenFga.Sdk/Model/Difference.cs index 32b33d6..1c35d3f 100644 --- a/src/OpenFga.Sdk/Model/Difference.cs +++ b/src/OpenFga.Sdk/Model/Difference.cs @@ -10,12 +10,6 @@ // 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 { /// /// Difference diff --git a/src/OpenFga.Sdk/Model/ErrorCode.cs b/src/OpenFga.Sdk/Model/ErrorCode.cs index ef0758b..34ff805 100644 --- a/src/OpenFga.Sdk/Model/ErrorCode.cs +++ b/src/OpenFga.Sdk/Model/ErrorCode.cs @@ -10,10 +10,6 @@ // NOTE: This file was auto generated. DO NOT EDIT. // - -using System.Runtime.Serialization; -using System.Text.Json.Serialization; - namespace OpenFga.Sdk.Model { /// /// Defines ErrorCode @@ -306,7 +302,19 @@ public enum ErrorCode { /// Enum UnsupportedSchemaVersion for value: unsupported_schema_version /// [EnumMember(Value = "unsupported_schema_version")] - UnsupportedSchemaVersion = 48 + UnsupportedSchemaVersion = 48, + + /// + /// Enum Cancelled for value: cancelled + /// + [EnumMember(Value = "cancelled")] + Cancelled = 49, + + /// + /// Enum InvalidStartTime for value: invalid_start_time + /// + [EnumMember(Value = "invalid_start_time")] + InvalidStartTime = 50 } diff --git a/src/OpenFga.Sdk/Model/ExpandRequest.cs b/src/OpenFga.Sdk/Model/ExpandRequest.cs index 73a43c7..50c2fb6 100644 --- a/src/OpenFga.Sdk/Model/ExpandRequest.cs +++ b/src/OpenFga.Sdk/Model/ExpandRequest.cs @@ -10,12 +10,6 @@ // 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 { /// /// ExpandRequest @@ -43,7 +37,8 @@ public ExpandRequest() { /// tupleKey (required). /// authorizationModelId. /// consistency. - public ExpandRequest(ExpandRequestTupleKey tupleKey = default(ExpandRequestTupleKey), string authorizationModelId = default(string), ConsistencyPreference? consistency = default(ConsistencyPreference?)) { + /// contextualTuples. + public ExpandRequest(ExpandRequestTupleKey tupleKey = default(ExpandRequestTupleKey), string authorizationModelId = default(string), ConsistencyPreference? consistency = default(ConsistencyPreference?), ContextualTupleKeys contextualTuples = default(ContextualTupleKeys)) { // 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,6 +46,7 @@ public ExpandRequest() { this.TupleKey = tupleKey; this.AuthorizationModelId = authorizationModelId; this.Consistency = consistency; + this.ContextualTuples = contextualTuples; this.AdditionalProperties = new Dictionary(); } @@ -70,6 +66,14 @@ public ExpandRequest() { [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string? AuthorizationModelId { get; set; } + /// + /// Gets or Sets ContextualTuples + /// + [DataMember(Name = "contextual_tuples", EmitDefaultValue = false)] + [JsonPropertyName("contextual_tuples")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public ContextualTupleKeys? ContextualTuples { get; set; } + /// /// Gets or Sets additional properties /// @@ -125,6 +129,11 @@ public bool Equals(ExpandRequest input) { ( this.Consistency == input.Consistency || this.Consistency.Equals(input.Consistency) + ) && + ( + this.ContextualTuples == input.ContextualTuples || + (this.ContextualTuples != null && + this.ContextualTuples.Equals(input.ContextualTuples)) ) && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); } @@ -144,6 +153,9 @@ public override int GetHashCode() { hashCode = (hashCode * 9923) + this.AuthorizationModelId.GetHashCode(); } hashCode = (hashCode * 9923) + this.Consistency.GetHashCode(); + if (this.ContextualTuples != null) { + hashCode = (hashCode * 9923) + this.ContextualTuples.GetHashCode(); + } if (this.AdditionalProperties != null) { hashCode = (hashCode * 9923) + this.AdditionalProperties.GetHashCode(); } diff --git a/src/OpenFga.Sdk/Model/ExpandRequestTupleKey.cs b/src/OpenFga.Sdk/Model/ExpandRequestTupleKey.cs index 755043f..98e529b 100644 --- a/src/OpenFga.Sdk/Model/ExpandRequestTupleKey.cs +++ b/src/OpenFga.Sdk/Model/ExpandRequestTupleKey.cs @@ -10,12 +10,6 @@ // 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 diff --git a/src/OpenFga.Sdk/Model/ExpandResponse.cs b/src/OpenFga.Sdk/Model/ExpandResponse.cs index 18b8e73..d77f2ea 100644 --- a/src/OpenFga.Sdk/Model/ExpandResponse.cs +++ b/src/OpenFga.Sdk/Model/ExpandResponse.cs @@ -10,12 +10,6 @@ // 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 { /// /// ExpandResponse diff --git a/src/OpenFga.Sdk/Model/FgaObject.cs b/src/OpenFga.Sdk/Model/FgaObject.cs index bd73df0..56aa2da 100644 --- a/src/OpenFga.Sdk/Model/FgaObject.cs +++ b/src/OpenFga.Sdk/Model/FgaObject.cs @@ -10,12 +10,6 @@ // 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 { /// /// Object represents an OpenFGA Object. An Object is composed of a type and identifier (e.g. 'document:1') See https://openfga.dev/docs/concepts#what-is-an-object diff --git a/src/OpenFga.Sdk/Model/ForbiddenResponse.cs b/src/OpenFga.Sdk/Model/ForbiddenResponse.cs new file mode 100644 index 0000000..1e5951e --- /dev/null +++ b/src/OpenFga.Sdk/Model/ForbiddenResponse.cs @@ -0,0 +1,137 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 1.x +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://openfga.dev/community +// 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.Model { + /// + /// ForbiddenResponse + /// + [DataContract(Name = "ForbiddenResponse")] + public partial class ForbiddenResponse : IEquatable, IValidatableObject { + + /// + /// Gets or Sets Code + /// + [DataMember(Name = "code", EmitDefaultValue = false)] + [JsonPropertyName("code")] + public AuthErrorCode? Code { get; set; } + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public ForbiddenResponse() { + this.AdditionalProperties = new Dictionary(); + } + + /// + /// Initializes a new instance of the class. + /// + /// code. + /// message. + public ForbiddenResponse(AuthErrorCode? code = default(AuthErrorCode?), string message = default(string)) { + this.Code = code; + this.Message = message; + this.AdditionalProperties = new Dictionary(); + } + + /// + /// 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 ForbiddenResponse from the JSON string presentation of the object + /// + /// ForbiddenResponse + public static ForbiddenResponse 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 ForbiddenResponse); + } + + /// + /// Returns true if ForbiddenResponse instances are equal + /// + /// Instance of ForbiddenResponse to be compared + /// Boolean + public bool Equals(ForbiddenResponse input) { + if (input == null) { + return false; + } + return + ( + this.Code == input.Code || + 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; + 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/GetStoreResponse.cs b/src/OpenFga.Sdk/Model/GetStoreResponse.cs index 6d708d7..34af149 100644 --- a/src/OpenFga.Sdk/Model/GetStoreResponse.cs +++ b/src/OpenFga.Sdk/Model/GetStoreResponse.cs @@ -10,12 +10,6 @@ // 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 { /// /// GetStoreResponse diff --git a/src/OpenFga.Sdk/Model/InternalErrorCode.cs b/src/OpenFga.Sdk/Model/InternalErrorCode.cs index 34b55ac..213cbc7 100644 --- a/src/OpenFga.Sdk/Model/InternalErrorCode.cs +++ b/src/OpenFga.Sdk/Model/InternalErrorCode.cs @@ -10,10 +10,6 @@ // NOTE: This file was auto generated. DO NOT EDIT. // - -using System.Runtime.Serialization; -using System.Text.Json.Serialization; - namespace OpenFga.Sdk.Model { /// /// Defines InternalErrorCode @@ -32,59 +28,53 @@ public enum InternalErrorCode { [EnumMember(Value = "internal_error")] InternalError = 2, - /// - /// Enum Cancelled for value: cancelled - /// - [EnumMember(Value = "cancelled")] - Cancelled = 3, - /// /// Enum DeadlineExceeded for value: deadline_exceeded /// [EnumMember(Value = "deadline_exceeded")] - DeadlineExceeded = 4, + DeadlineExceeded = 3, /// /// Enum AlreadyExists for value: already_exists /// [EnumMember(Value = "already_exists")] - AlreadyExists = 5, + AlreadyExists = 4, /// /// Enum ResourceExhausted for value: resource_exhausted /// [EnumMember(Value = "resource_exhausted")] - ResourceExhausted = 6, + ResourceExhausted = 5, /// /// Enum FailedPrecondition for value: failed_precondition /// [EnumMember(Value = "failed_precondition")] - FailedPrecondition = 7, + FailedPrecondition = 6, /// /// Enum Aborted for value: aborted /// [EnumMember(Value = "aborted")] - Aborted = 8, + Aborted = 7, /// /// Enum OutOfRange for value: out_of_range /// [EnumMember(Value = "out_of_range")] - OutOfRange = 9, + OutOfRange = 8, /// /// Enum Unavailable for value: unavailable /// [EnumMember(Value = "unavailable")] - Unavailable = 10, + Unavailable = 9, /// /// Enum DataLoss for value: data_loss /// [EnumMember(Value = "data_loss")] - DataLoss = 11 + DataLoss = 10 } diff --git a/src/OpenFga.Sdk/Model/InternalErrorMessageResponse.cs b/src/OpenFga.Sdk/Model/InternalErrorMessageResponse.cs index b51c635..d385be5 100644 --- a/src/OpenFga.Sdk/Model/InternalErrorMessageResponse.cs +++ b/src/OpenFga.Sdk/Model/InternalErrorMessageResponse.cs @@ -10,12 +10,6 @@ // 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 { /// /// InternalErrorMessageResponse diff --git a/src/OpenFga.Sdk/Model/JsonStringEnumMemberConverter.cs b/src/OpenFga.Sdk/Model/JsonStringEnumMemberConverter.cs index 8d99d4b..5080ee9 100644 --- a/src/OpenFga.Sdk/Model/JsonStringEnumMemberConverter.cs +++ b/src/OpenFga.Sdk/Model/JsonStringEnumMemberConverter.cs @@ -11,9 +11,6 @@ // -using System.Runtime.Serialization; -using System.Text.Json; -using System.Text.Json.Serialization; /// This class is based on suggestions from https://github.com/dotnet/runtime/issues/31081 @@ -30,7 +27,7 @@ public class JsonStringEnumMemberConverter : JsonConverter public JsonStringEnumMemberConverter() { var type = typeof(EnumTemplate); - var values = Enum.GetValues(); + var values = (EnumTemplate[])Enum.GetValues(typeof(EnumTemplate)); foreach (var value in values) { var enumMember = type.GetMember(value.ToString())[0]; diff --git a/src/OpenFga.Sdk/Model/Leaf.cs b/src/OpenFga.Sdk/Model/Leaf.cs index 1f1769d..cb84c45 100644 --- a/src/OpenFga.Sdk/Model/Leaf.cs +++ b/src/OpenFga.Sdk/Model/Leaf.cs @@ -10,12 +10,6 @@ // 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 { /// /// A leaf node contains either - a set of users (which may be individual users, or usersets referencing other relations) - a computed node, which is the result of a computed userset value in the authorization model - a tupleToUserset nodes, containing the result of expanding a tupleToUserset value in a authorization model. diff --git a/src/OpenFga.Sdk/Model/ListObjectsRequest.cs b/src/OpenFga.Sdk/Model/ListObjectsRequest.cs index d29b4d3..a873bcb 100644 --- a/src/OpenFga.Sdk/Model/ListObjectsRequest.cs +++ b/src/OpenFga.Sdk/Model/ListObjectsRequest.cs @@ -10,12 +10,6 @@ // 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 { /// /// ListObjectsRequest diff --git a/src/OpenFga.Sdk/Model/ListObjectsResponse.cs b/src/OpenFga.Sdk/Model/ListObjectsResponse.cs index 29759d2..f2ab927 100644 --- a/src/OpenFga.Sdk/Model/ListObjectsResponse.cs +++ b/src/OpenFga.Sdk/Model/ListObjectsResponse.cs @@ -10,12 +10,6 @@ // 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 { /// /// ListObjectsResponse diff --git a/src/OpenFga.Sdk/Model/ListStoresResponse.cs b/src/OpenFga.Sdk/Model/ListStoresResponse.cs index e84e4f8..74d46b3 100644 --- a/src/OpenFga.Sdk/Model/ListStoresResponse.cs +++ b/src/OpenFga.Sdk/Model/ListStoresResponse.cs @@ -10,12 +10,6 @@ // 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 { /// /// ListStoresResponse diff --git a/src/OpenFga.Sdk/Model/ListUsersRequest.cs b/src/OpenFga.Sdk/Model/ListUsersRequest.cs index e581658..5c144b3 100644 --- a/src/OpenFga.Sdk/Model/ListUsersRequest.cs +++ b/src/OpenFga.Sdk/Model/ListUsersRequest.cs @@ -10,12 +10,6 @@ // 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 { /// /// ListUsersRequest diff --git a/src/OpenFga.Sdk/Model/ListUsersResponse.cs b/src/OpenFga.Sdk/Model/ListUsersResponse.cs index c92d3a8..ec0cf40 100644 --- a/src/OpenFga.Sdk/Model/ListUsersResponse.cs +++ b/src/OpenFga.Sdk/Model/ListUsersResponse.cs @@ -10,12 +10,6 @@ // 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 { /// /// ListUsersResponse diff --git a/src/OpenFga.Sdk/Model/Metadata.cs b/src/OpenFga.Sdk/Model/Metadata.cs index ecd13a4..bb704e2 100644 --- a/src/OpenFga.Sdk/Model/Metadata.cs +++ b/src/OpenFga.Sdk/Model/Metadata.cs @@ -10,12 +10,6 @@ // 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 { /// /// Metadata diff --git a/src/OpenFga.Sdk/Model/Node.cs b/src/OpenFga.Sdk/Model/Node.cs index 0167674..be296f9 100644 --- a/src/OpenFga.Sdk/Model/Node.cs +++ b/src/OpenFga.Sdk/Model/Node.cs @@ -10,12 +10,6 @@ // 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 { /// /// Node diff --git a/src/OpenFga.Sdk/Model/Nodes.cs b/src/OpenFga.Sdk/Model/Nodes.cs index 32aba13..9b798d1 100644 --- a/src/OpenFga.Sdk/Model/Nodes.cs +++ b/src/OpenFga.Sdk/Model/Nodes.cs @@ -10,12 +10,6 @@ // 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 { /// /// Nodes diff --git a/src/OpenFga.Sdk/Model/NotFoundErrorCode.cs b/src/OpenFga.Sdk/Model/NotFoundErrorCode.cs index c4399d1..ab27066 100644 --- a/src/OpenFga.Sdk/Model/NotFoundErrorCode.cs +++ b/src/OpenFga.Sdk/Model/NotFoundErrorCode.cs @@ -10,10 +10,6 @@ // NOTE: This file was auto generated. DO NOT EDIT. // - -using System.Runtime.Serialization; -using System.Text.Json.Serialization; - namespace OpenFga.Sdk.Model { /// /// Defines NotFoundErrorCode diff --git a/src/OpenFga.Sdk/Model/NullValue.cs b/src/OpenFga.Sdk/Model/NullValue.cs index bfdb59e..ae9af38 100644 --- a/src/OpenFga.Sdk/Model/NullValue.cs +++ b/src/OpenFga.Sdk/Model/NullValue.cs @@ -10,10 +10,6 @@ // 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. diff --git a/src/OpenFga.Sdk/Model/ObjectRelation.cs b/src/OpenFga.Sdk/Model/ObjectRelation.cs index f91d4d6..49e10a4 100644 --- a/src/OpenFga.Sdk/Model/ObjectRelation.cs +++ b/src/OpenFga.Sdk/Model/ObjectRelation.cs @@ -10,12 +10,6 @@ // 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 { /// /// ObjectRelation diff --git a/src/OpenFga.Sdk/Model/PathUnknownErrorMessageResponse.cs b/src/OpenFga.Sdk/Model/PathUnknownErrorMessageResponse.cs index 5fb443e..4b5aae0 100644 --- a/src/OpenFga.Sdk/Model/PathUnknownErrorMessageResponse.cs +++ b/src/OpenFga.Sdk/Model/PathUnknownErrorMessageResponse.cs @@ -10,12 +10,6 @@ // 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 { /// /// PathUnknownErrorMessageResponse diff --git a/src/OpenFga.Sdk/Model/ReadAssertionsResponse.cs b/src/OpenFga.Sdk/Model/ReadAssertionsResponse.cs index b23c7c4..9da68c5 100644 --- a/src/OpenFga.Sdk/Model/ReadAssertionsResponse.cs +++ b/src/OpenFga.Sdk/Model/ReadAssertionsResponse.cs @@ -10,12 +10,6 @@ // 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 { /// /// ReadAssertionsResponse diff --git a/src/OpenFga.Sdk/Model/ReadAuthorizationModelResponse.cs b/src/OpenFga.Sdk/Model/ReadAuthorizationModelResponse.cs index 9b23c4e..2b637a9 100644 --- a/src/OpenFga.Sdk/Model/ReadAuthorizationModelResponse.cs +++ b/src/OpenFga.Sdk/Model/ReadAuthorizationModelResponse.cs @@ -10,12 +10,6 @@ // 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 { /// /// ReadAuthorizationModelResponse diff --git a/src/OpenFga.Sdk/Model/ReadAuthorizationModelsResponse.cs b/src/OpenFga.Sdk/Model/ReadAuthorizationModelsResponse.cs index 9ee3219..2ac4991 100644 --- a/src/OpenFga.Sdk/Model/ReadAuthorizationModelsResponse.cs +++ b/src/OpenFga.Sdk/Model/ReadAuthorizationModelsResponse.cs @@ -10,12 +10,6 @@ // 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 { /// /// ReadAuthorizationModelsResponse diff --git a/src/OpenFga.Sdk/Model/ReadChangesResponse.cs b/src/OpenFga.Sdk/Model/ReadChangesResponse.cs index 02dd499..db0fe79 100644 --- a/src/OpenFga.Sdk/Model/ReadChangesResponse.cs +++ b/src/OpenFga.Sdk/Model/ReadChangesResponse.cs @@ -10,12 +10,6 @@ // 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 { /// /// ReadChangesResponse diff --git a/src/OpenFga.Sdk/Model/ReadRequest.cs b/src/OpenFga.Sdk/Model/ReadRequest.cs index f605138..39dbb2d 100644 --- a/src/OpenFga.Sdk/Model/ReadRequest.cs +++ b/src/OpenFga.Sdk/Model/ReadRequest.cs @@ -10,12 +10,6 @@ // 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 { /// /// ReadRequest @@ -168,6 +162,16 @@ public override int GetHashCode() { /// Validation context /// Validation Result public IEnumerable Validate(ValidationContext validationContext) { + // PageSize (int) maximum + if (this.PageSize > 100) { + yield return new ValidationResult("Invalid value for PageSize, must be a value less than or equal to 100.", new[] { "PageSize" }); + } + + // PageSize (int) minimum + if (this.PageSize < 1) { + yield return new ValidationResult("Invalid value for PageSize, must be a value greater than or equal to 1.", new[] { "PageSize" }); + } + yield break; } diff --git a/src/OpenFga.Sdk/Model/ReadRequestTupleKey.cs b/src/OpenFga.Sdk/Model/ReadRequestTupleKey.cs index 85665e1..5f4c3b9 100644 --- a/src/OpenFga.Sdk/Model/ReadRequestTupleKey.cs +++ b/src/OpenFga.Sdk/Model/ReadRequestTupleKey.cs @@ -10,12 +10,6 @@ // 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 diff --git a/src/OpenFga.Sdk/Model/ReadResponse.cs b/src/OpenFga.Sdk/Model/ReadResponse.cs index 2ddde32..434a39d 100644 --- a/src/OpenFga.Sdk/Model/ReadResponse.cs +++ b/src/OpenFga.Sdk/Model/ReadResponse.cs @@ -10,12 +10,6 @@ // 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 { /// /// ReadResponse diff --git a/src/OpenFga.Sdk/Model/RelationMetadata.cs b/src/OpenFga.Sdk/Model/RelationMetadata.cs index 19c9de4..84adaf0 100644 --- a/src/OpenFga.Sdk/Model/RelationMetadata.cs +++ b/src/OpenFga.Sdk/Model/RelationMetadata.cs @@ -10,12 +10,6 @@ // 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 { /// /// RelationMetadata diff --git a/src/OpenFga.Sdk/Model/RelationReference.cs b/src/OpenFga.Sdk/Model/RelationReference.cs index 4f23108..09ff8db 100644 --- a/src/OpenFga.Sdk/Model/RelationReference.cs +++ b/src/OpenFga.Sdk/Model/RelationReference.cs @@ -10,12 +10,6 @@ // 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 { /// /// RelationReference represents a relation of a particular object type (e.g. 'document#viewer'). diff --git a/src/OpenFga.Sdk/Model/RelationshipCondition.cs b/src/OpenFga.Sdk/Model/RelationshipCondition.cs index b1ef041..c51b275 100644 --- a/src/OpenFga.Sdk/Model/RelationshipCondition.cs +++ b/src/OpenFga.Sdk/Model/RelationshipCondition.cs @@ -10,12 +10,6 @@ // 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 diff --git a/src/OpenFga.Sdk/Model/SourceInfo.cs b/src/OpenFga.Sdk/Model/SourceInfo.cs index b793e24..31f1133 100644 --- a/src/OpenFga.Sdk/Model/SourceInfo.cs +++ b/src/OpenFga.Sdk/Model/SourceInfo.cs @@ -10,12 +10,6 @@ // 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 { /// /// SourceInfo diff --git a/src/OpenFga.Sdk/Model/Status.cs b/src/OpenFga.Sdk/Model/Status.cs index 2d1ed6b..2ee9896 100644 --- a/src/OpenFga.Sdk/Model/Status.cs +++ b/src/OpenFga.Sdk/Model/Status.cs @@ -10,12 +10,6 @@ // 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 { /// /// Status diff --git a/src/OpenFga.Sdk/Model/Store.cs b/src/OpenFga.Sdk/Model/Store.cs index 1745a9e..7b7e4fa 100644 --- a/src/OpenFga.Sdk/Model/Store.cs +++ b/src/OpenFga.Sdk/Model/Store.cs @@ -10,12 +10,6 @@ // 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 { /// /// Store diff --git a/src/OpenFga.Sdk/Model/Tuple.cs b/src/OpenFga.Sdk/Model/Tuple.cs index 3820842..baefe12 100644 --- a/src/OpenFga.Sdk/Model/Tuple.cs +++ b/src/OpenFga.Sdk/Model/Tuple.cs @@ -10,12 +10,6 @@ // 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 { /// /// Tuple diff --git a/src/OpenFga.Sdk/Model/TupleChange.cs b/src/OpenFga.Sdk/Model/TupleChange.cs index 892e985..8c62dc0 100644 --- a/src/OpenFga.Sdk/Model/TupleChange.cs +++ b/src/OpenFga.Sdk/Model/TupleChange.cs @@ -10,12 +10,6 @@ // 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 { /// /// TupleChange diff --git a/src/OpenFga.Sdk/Model/TupleKey.cs b/src/OpenFga.Sdk/Model/TupleKey.cs index 57ab767..aa55142 100644 --- a/src/OpenFga.Sdk/Model/TupleKey.cs +++ b/src/OpenFga.Sdk/Model/TupleKey.cs @@ -10,12 +10,6 @@ // 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 { /// /// TupleKey diff --git a/src/OpenFga.Sdk/Model/TupleKeyWithoutCondition.cs b/src/OpenFga.Sdk/Model/TupleKeyWithoutCondition.cs index 992954f..743b2e6 100644 --- a/src/OpenFga.Sdk/Model/TupleKeyWithoutCondition.cs +++ b/src/OpenFga.Sdk/Model/TupleKeyWithoutCondition.cs @@ -10,12 +10,6 @@ // 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 diff --git a/src/OpenFga.Sdk/Model/TupleOperation.cs b/src/OpenFga.Sdk/Model/TupleOperation.cs index b7dcbcf..ffd5007 100644 --- a/src/OpenFga.Sdk/Model/TupleOperation.cs +++ b/src/OpenFga.Sdk/Model/TupleOperation.cs @@ -10,10 +10,6 @@ // NOTE: This file was auto generated. DO NOT EDIT. // - -using System.Runtime.Serialization; -using System.Text.Json.Serialization; - namespace OpenFga.Sdk.Model { /// /// Defines TupleOperation diff --git a/src/OpenFga.Sdk/Model/TupleToUserset.cs b/src/OpenFga.Sdk/Model/TupleToUserset.cs index 7b6d52f..01cc9e9 100644 --- a/src/OpenFga.Sdk/Model/TupleToUserset.cs +++ b/src/OpenFga.Sdk/Model/TupleToUserset.cs @@ -10,12 +10,6 @@ // 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 { /// /// TupleToUserset diff --git a/src/OpenFga.Sdk/Model/TypeDefinition.cs b/src/OpenFga.Sdk/Model/TypeDefinition.cs index a4ba8f7..4d0a2a0 100644 --- a/src/OpenFga.Sdk/Model/TypeDefinition.cs +++ b/src/OpenFga.Sdk/Model/TypeDefinition.cs @@ -10,12 +10,6 @@ // 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 { /// /// TypeDefinition diff --git a/src/OpenFga.Sdk/Model/TypeName.cs b/src/OpenFga.Sdk/Model/TypeName.cs index b86937c..fc8a3a5 100644 --- a/src/OpenFga.Sdk/Model/TypeName.cs +++ b/src/OpenFga.Sdk/Model/TypeName.cs @@ -10,80 +10,84 @@ // 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 { +namespace OpenFga.Sdk.Model { /// - /// Enum UNSPECIFIED for value: TYPE_NAME_UNSPECIFIED + /// Defines TypeName /// - [EnumMember(Value = "TYPE_NAME_UNSPECIFIED")] - TypeName_UNSPECIFIED = 1, + [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")] TypeName_ANY = 2, + /// + /// 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")] TypeName_BOOL = 3, + /// + /// 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 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 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 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 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 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 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 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 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 + + } - /// - /// 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/TypedWildcard.cs b/src/OpenFga.Sdk/Model/TypedWildcard.cs index 4d2a1fe..a7d20c1 100644 --- a/src/OpenFga.Sdk/Model/TypedWildcard.cs +++ b/src/OpenFga.Sdk/Model/TypedWildcard.cs @@ -10,12 +10,6 @@ // 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 { /// /// Type bound public access. Normally represented using the `<type>:*` syntax `employee:*` represents every object of type `employee`, including those not currently present in the system See https://openfga.dev/docs/concepts#what-is-type-bound-public-access diff --git a/src/OpenFga.Sdk/Model/UnauthenticatedResponse.cs b/src/OpenFga.Sdk/Model/UnauthenticatedResponse.cs index b51943a..03bae05 100644 --- a/src/OpenFga.Sdk/Model/UnauthenticatedResponse.cs +++ b/src/OpenFga.Sdk/Model/UnauthenticatedResponse.cs @@ -10,12 +10,6 @@ // 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 { /// /// UnauthenticatedResponse diff --git a/src/OpenFga.Sdk/Model/UnprocessableContentErrorCode.cs b/src/OpenFga.Sdk/Model/UnprocessableContentErrorCode.cs index e9664a8..45f45d0 100644 --- a/src/OpenFga.Sdk/Model/UnprocessableContentErrorCode.cs +++ b/src/OpenFga.Sdk/Model/UnprocessableContentErrorCode.cs @@ -10,10 +10,6 @@ // NOTE: This file was auto generated. DO NOT EDIT. // - -using System.Runtime.Serialization; -using System.Text.Json.Serialization; - namespace OpenFga.Sdk.Model { /// /// Defines UnprocessableContentErrorCode diff --git a/src/OpenFga.Sdk/Model/UnprocessableContentMessageResponse.cs b/src/OpenFga.Sdk/Model/UnprocessableContentMessageResponse.cs index 386bbde..3c21c0e 100644 --- a/src/OpenFga.Sdk/Model/UnprocessableContentMessageResponse.cs +++ b/src/OpenFga.Sdk/Model/UnprocessableContentMessageResponse.cs @@ -10,12 +10,6 @@ // 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 { /// /// UnprocessableContentMessageResponse diff --git a/src/OpenFga.Sdk/Model/User.cs b/src/OpenFga.Sdk/Model/User.cs index 179e0f5..079beb1 100644 --- a/src/OpenFga.Sdk/Model/User.cs +++ b/src/OpenFga.Sdk/Model/User.cs @@ -10,12 +10,6 @@ // 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 { /// /// User. Represents any possible value for a user (subject or principal). Can be a: - Specific user object e.g.: 'user:will', 'folder:marketing', 'org:contoso', ...) - Specific userset (e.g. 'group:engineering#member') - Public-typed wildcard (e.g. 'user:*') See https://openfga.dev/docs/concepts#what-is-a-user diff --git a/src/OpenFga.Sdk/Model/UserTypeFilter.cs b/src/OpenFga.Sdk/Model/UserTypeFilter.cs index d9346fa..362b6b9 100644 --- a/src/OpenFga.Sdk/Model/UserTypeFilter.cs +++ b/src/OpenFga.Sdk/Model/UserTypeFilter.cs @@ -10,12 +10,6 @@ // 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 { /// /// UserTypeFilter diff --git a/src/OpenFga.Sdk/Model/Users.cs b/src/OpenFga.Sdk/Model/Users.cs index b283ad2..0a115d3 100644 --- a/src/OpenFga.Sdk/Model/Users.cs +++ b/src/OpenFga.Sdk/Model/Users.cs @@ -10,12 +10,6 @@ // 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 { /// /// Users diff --git a/src/OpenFga.Sdk/Model/Userset.cs b/src/OpenFga.Sdk/Model/Userset.cs index d1f4f4a..5b1189f 100644 --- a/src/OpenFga.Sdk/Model/Userset.cs +++ b/src/OpenFga.Sdk/Model/Userset.cs @@ -10,12 +10,6 @@ // 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 { /// /// Userset diff --git a/src/OpenFga.Sdk/Model/UsersetTree.cs b/src/OpenFga.Sdk/Model/UsersetTree.cs index 2e18959..1c87a41 100644 --- a/src/OpenFga.Sdk/Model/UsersetTree.cs +++ b/src/OpenFga.Sdk/Model/UsersetTree.cs @@ -10,12 +10,6 @@ // 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 { /// /// A UsersetTree contains the result of an Expansion. diff --git a/src/OpenFga.Sdk/Model/UsersetTreeDifference.cs b/src/OpenFga.Sdk/Model/UsersetTreeDifference.cs index b4153de..9fa3152 100644 --- a/src/OpenFga.Sdk/Model/UsersetTreeDifference.cs +++ b/src/OpenFga.Sdk/Model/UsersetTreeDifference.cs @@ -10,12 +10,6 @@ // 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 { /// /// UsersetTreeDifference diff --git a/src/OpenFga.Sdk/Model/UsersetTreeTupleToUserset.cs b/src/OpenFga.Sdk/Model/UsersetTreeTupleToUserset.cs index 94b722a..3986aa4 100644 --- a/src/OpenFga.Sdk/Model/UsersetTreeTupleToUserset.cs +++ b/src/OpenFga.Sdk/Model/UsersetTreeTupleToUserset.cs @@ -10,12 +10,6 @@ // 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 { /// /// UsersetTreeTupleToUserset diff --git a/src/OpenFga.Sdk/Model/UsersetUser.cs b/src/OpenFga.Sdk/Model/UsersetUser.cs index bfbe58d..6a897cd 100644 --- a/src/OpenFga.Sdk/Model/UsersetUser.cs +++ b/src/OpenFga.Sdk/Model/UsersetUser.cs @@ -10,12 +10,6 @@ // 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 { /// /// Userset. A set or group of users, represented in the `<type>:<id>#<relation>` format `group:fga#member` represents all members of group FGA, not to be confused by `group:fga` which represents the group itself as a specific object. See: https://openfga.dev/docs/modeling/building-blocks/usersets#what-is-a-userset diff --git a/src/OpenFga.Sdk/Model/Usersets.cs b/src/OpenFga.Sdk/Model/Usersets.cs index b4812ad..d3a86e0 100644 --- a/src/OpenFga.Sdk/Model/Usersets.cs +++ b/src/OpenFga.Sdk/Model/Usersets.cs @@ -10,12 +10,6 @@ // 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 { /// /// Usersets diff --git a/src/OpenFga.Sdk/Model/ValidationErrorMessageResponse.cs b/src/OpenFga.Sdk/Model/ValidationErrorMessageResponse.cs index 465f5e4..e68bc37 100644 --- a/src/OpenFga.Sdk/Model/ValidationErrorMessageResponse.cs +++ b/src/OpenFga.Sdk/Model/ValidationErrorMessageResponse.cs @@ -10,12 +10,6 @@ // 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 { /// /// ValidationErrorMessageResponse diff --git a/src/OpenFga.Sdk/Model/WriteAssertionsRequest.cs b/src/OpenFga.Sdk/Model/WriteAssertionsRequest.cs index fe52935..2457381 100644 --- a/src/OpenFga.Sdk/Model/WriteAssertionsRequest.cs +++ b/src/OpenFga.Sdk/Model/WriteAssertionsRequest.cs @@ -10,12 +10,6 @@ // 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 { /// /// WriteAssertionsRequest diff --git a/src/OpenFga.Sdk/Model/WriteAuthorizationModelRequest.cs b/src/OpenFga.Sdk/Model/WriteAuthorizationModelRequest.cs index 846e75c..6c4b8bb 100644 --- a/src/OpenFga.Sdk/Model/WriteAuthorizationModelRequest.cs +++ b/src/OpenFga.Sdk/Model/WriteAuthorizationModelRequest.cs @@ -10,12 +10,6 @@ // 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 { /// /// WriteAuthorizationModelRequest diff --git a/src/OpenFga.Sdk/Model/WriteAuthorizationModelResponse.cs b/src/OpenFga.Sdk/Model/WriteAuthorizationModelResponse.cs index 83c4635..c60f383 100644 --- a/src/OpenFga.Sdk/Model/WriteAuthorizationModelResponse.cs +++ b/src/OpenFga.Sdk/Model/WriteAuthorizationModelResponse.cs @@ -10,12 +10,6 @@ // 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 { /// /// WriteAuthorizationModelResponse diff --git a/src/OpenFga.Sdk/Model/WriteRequest.cs b/src/OpenFga.Sdk/Model/WriteRequest.cs index 0ed67b4..d7f74a3 100644 --- a/src/OpenFga.Sdk/Model/WriteRequest.cs +++ b/src/OpenFga.Sdk/Model/WriteRequest.cs @@ -10,12 +10,6 @@ // 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 { /// /// WriteRequest diff --git a/src/OpenFga.Sdk/Model/WriteRequestDeletes.cs b/src/OpenFga.Sdk/Model/WriteRequestDeletes.cs index e11c0d5..9353eb3 100644 --- a/src/OpenFga.Sdk/Model/WriteRequestDeletes.cs +++ b/src/OpenFga.Sdk/Model/WriteRequestDeletes.cs @@ -10,12 +10,6 @@ // 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 diff --git a/src/OpenFga.Sdk/Model/WriteRequestWrites.cs b/src/OpenFga.Sdk/Model/WriteRequestWrites.cs index ea74734..3560a62 100644 --- a/src/OpenFga.Sdk/Model/WriteRequestWrites.cs +++ b/src/OpenFga.Sdk/Model/WriteRequestWrites.cs @@ -10,12 +10,6 @@ // 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 { /// /// WriteRequestWrites diff --git a/src/OpenFga.Sdk/Net/HttpStatusCodeExtensions.cs b/src/OpenFga.Sdk/Net/HttpStatusCodeExtensions.cs new file mode 100644 index 0000000..17190c7 --- /dev/null +++ b/src/OpenFga.Sdk/Net/HttpStatusCodeExtensions.cs @@ -0,0 +1,29 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 1.x +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://openfga.dev/community +// License: [Apache-2.0](https://github.com/openfga/dotnet-sdk/blob/main/LICENSE) +// +// NOTE: This file was auto generated. DO NOT EDIT. +// + + +namespace System.Net { + /// + /// Extensions for HttpStatusCode + /// + public static class HttpStatusCodeExtensions { + /// + /// Unprocessable Entity status code (422) as defined in RFC 4918 + /// + public static HttpStatusCode UnprocessableEntity { get; } = (HttpStatusCode)422; + + /// + /// Too Many Requests status code (429) as defined in RFC 6585 + /// + public static HttpStatusCode TooManyRequests { get; } = (HttpStatusCode)429; + } +} \ No newline at end of file diff --git a/src/OpenFga.Sdk/OpenFga.Sdk.csproj b/src/OpenFga.Sdk/OpenFga.Sdk.csproj index 24e3a00..fb8d1f7 100644 --- a/src/OpenFga.Sdk/OpenFga.Sdk.csproj +++ b/src/OpenFga.Sdk/OpenFga.Sdk.csproj @@ -2,7 +2,7 @@ false - net6.0 + netstandard2.0 OpenFga.Sdk OpenFga.Sdk Library @@ -23,8 +23,11 @@ FGAIcon.png annotations enable - enable + latest true + + disable + NETSTANDARD2_0 @@ -33,4 +36,11 @@ + + + + + + + diff --git a/src/OpenFga.Sdk/Telemetry/Attributes.cs b/src/OpenFga.Sdk/Telemetry/Attributes.cs index c417b42..e512ab0 100644 --- a/src/OpenFga.Sdk/Telemetry/Attributes.cs +++ b/src/OpenFga.Sdk/Telemetry/Attributes.cs @@ -12,10 +12,9 @@ using OpenFga.Sdk.ApiClient; +using OpenFga.Sdk.Client; // For extensions using OpenFga.Sdk.Configuration; using System.Diagnostics; -using System.Net.Http.Headers; -using System.Text.Json; namespace OpenFga.Sdk.Telemetry; @@ -46,6 +45,41 @@ public static class TelemetryAttribute { /// public static readonly string RequestClientId = "fga-client.request.client_id"; + /// + /// The internal retry count for an API request. + /// + public static readonly string RequestRetryCount = "fga-client.request.retry-count"; + + /// + /// The HTTP host for an API request + /// + public static readonly string HttpHost = "http.host"; + + /// + /// The HTTP status for an API request + /// + public static readonly string HttpStatus = "http.status"; + + /// + /// The HTTP user agent for an API request + /// + public static readonly string HttpUserAgent = "http.user_agent"; + + /// + /// The HTTP scheme for an API request + /// + public static readonly string HttpScheme = "http.scheme"; + + /// + /// The HTTP method for an API request + /// + public static readonly string HttpMethod = "http.method"; + + /// + /// The HTTP URL for an API request + /// + public static readonly string HttpUrl = "http.url"; + // Attributes (tags) associated with the response // /// @@ -60,98 +94,89 @@ public static class TelemetryAttribute { /// public static readonly string FgaRequestUser = "fga-client.user"; - // OTEL Semantic Attributes (tags) // - /// - /// The HTTP method for the request. + /// The context/condition that is associated with the action of the request for check and list objects. /// - public static readonly string HttpMethod = "http.request.method"; + public static readonly string FgaRequestContext = "fga-client.context"; /// - /// The status code of the response. + /// The object that is associated with the action of the request for check and list relations. /// - public static readonly string HttpStatus = "http.response.status_code"; + public static readonly string FgaRequestObject = "fga-client.object"; /// - /// Host identifier of the origin the request was sent to. + /// The relation that is associated with the action of the request for check and list objects. /// - public static readonly string HttpHost = "http.host"; + public static readonly string FgaRequestRelation = "fga-client.relation"; /// - /// HTTP Scheme of the request (`http`/`https`). + /// The type that is associated with the action of the request for list objects. /// - public static readonly string HttpScheme = "url.scheme"; + public static readonly string FgaRequestType = "fga-client.type"; /// - /// Full URL of the request. + /// The internal retry count for an API request. /// - public static readonly string HttpUrl = "url.full"; + public static readonly string RetryCount = "fga-client.retry-count"; /// - /// User Agent used in the query. + /// The HTTP status returned for an API request /// - public static readonly string HttpUserAgent = "user_agent.original"; + public static readonly string ResponseStatus = "fga-client.response.status"; /// - /// The number of retries attempted (Only sent if the request was retried. Count of `1` means the request was retried - /// once in addition to the original request). + /// Indicates if an API request was successful /// - public static readonly string RequestRetryCount = "http.request.resend_count"; + public static readonly string ResponseSuccess = "fga-client.response.success"; /// - /// Return all supported attributes + /// Return all supported attribute names for the client /// public static HashSet GetAllAttributes() { - return new() { - RequestMethod, - RequestStoreId, - RequestModelId, - RequestClientId, - ResponseModelId, - FgaRequestUser, - HttpMethod, - HttpStatus, - HttpHost, - HttpScheme, - HttpUrl, - HttpUserAgent, - RequestRetryCount - }; + var attributes = new HashSet(); + attributes.Add(RequestMethod); + attributes.Add(RequestStoreId); + attributes.Add(RequestModelId); + attributes.Add(RequestClientId); + attributes.Add(RequestRetryCount); + attributes.Add(HttpHost); + attributes.Add(HttpStatus); + attributes.Add(HttpUserAgent); + attributes.Add(HttpScheme); + attributes.Add(HttpMethod); + attributes.Add(HttpUrl); + attributes.Add(ResponseModelId); + attributes.Add(FgaRequestUser); + attributes.Add(FgaRequestContext); + attributes.Add(FgaRequestObject); + attributes.Add(FgaRequestRelation); + attributes.Add(FgaRequestType); + attributes.Add(RetryCount); + attributes.Add(ResponseStatus); + attributes.Add(ResponseSuccess); + return attributes; } } /// -/// Class for building attributes for telemetry. +/// Helper class for building attribute tags for telemetry /// -public class Attributes { +public static class Attributes { /// - /// Gets the header value if valid. + /// Filter all attributes against the allowed attributes hash set /// - /// The HTTP response headers. - /// The name of the header. - /// The header value if valid, otherwise null. - private static string? GetHeaderValueIfValid(HttpResponseHeaders headers, string headerName) { - if (headers.Contains(headerName) && headers.GetValues(headerName).Any()) { - return headers.GetValues(headerName).First(); + /// The full attributes to be filtered + /// The hashset of allowed attribute names + /// A tag list containing only the allowed attributes + public static TagList FilterAttributes(TagList fullAttributes, HashSet? allowedAttributes) { + if (allowedAttributes == null || allowedAttributes.Count == 0) { + return new TagList(); } - return null; - } - - /// - /// Filters the attributes based on the enabled attributes. - /// - /// The list of attributes to filter. - /// The dictionary of enabled attributes. - /// A filtered list of attributes. - public static TagList FilterAttributes(TagList attributes, HashSet? enabledAttributes) { var filteredAttributes = new TagList(); - - if (enabledAttributes != null && enabledAttributes.Count != 0) { - foreach (var attribute in attributes) { - if (enabledAttributes.Contains(attribute.Key)) { - filteredAttributes.Add(attribute); - } + foreach (var attribute in fullAttributes) { + if (allowedAttributes.Contains(attribute.Key)) { + filteredAttributes.Add(attribute.Key, attribute.Value); } } @@ -159,163 +184,170 @@ public static TagList FilterAttributes(TagList attributes, HashSet? enab } /// - /// Builds an object of attributes that can be used to report alongside an OpenTelemetry metric event. + /// Builds the attribute tags for metrics for client credentials exchange requests /// - /// The type of the request builder. - /// The list of enabled attributes. - /// The credentials object. - /// The GRPC method name. - /// The HTTP response message. - /// The request builder. - /// The stopwatch measuring the request duration. - /// The number of retries attempted. - /// A TagList of attributes. - public static TagList BuildAttributesForResponse( - HashSet enabledAttributes, Credentials? credentials, - string apiName, HttpResponseMessage response, RequestBuilder requestBuilder, - Stopwatch requestDuration, int retryCount) { - var attributes = new TagList(); - - attributes = AddRequestAttributes(enabledAttributes, apiName, requestBuilder, attributes); - attributes = AddResponseAttributes(enabledAttributes, response, attributes); - attributes = AddCommonAttributes(enabledAttributes, response, requestBuilder, credentials, retryCount, attributes); - - return attributes; - } + /// The enabled attribute names (must be a subset of ) + /// The client credentials used make the API call + /// Measures the total request time + /// How many times the token request was retried + /// Attributes for telemetry + public static TagList BuildAttributesForClientCredentials(HashSet enabledAttributeNames, Credentials? credentials, + Stopwatch requestDuration, int retryCount = 0) { + if (enabledAttributeNames.Count == 0) { + return new TagList(); + } - private static TagList AddRequestAttributes( - HashSet enabledAttributes, string apiName, RequestBuilder requestBuilder, TagList attributes) { - // var attributes = new TagList(); - if (enabledAttributes.Contains(TelemetryAttribute.RequestMethod)) { - attributes.Add(new KeyValuePair(TelemetryAttribute.RequestMethod, apiName)); + var tagList = new TagList(); + if (enabledAttributeNames.Contains(TelemetryAttribute.RequestMethod)) { + tagList.Add(TelemetryAttribute.RequestMethod, "ClientCredentialsExchange"); } - if (enabledAttributes.Contains(TelemetryAttribute.RequestStoreId) && - requestBuilder.PathParameters.ContainsKey("store_id")) { - var storeId = requestBuilder.PathParameters.GetValueOrDefault("store_id"); - if (!string.IsNullOrEmpty(storeId)) { - attributes.Add(new KeyValuePair(TelemetryAttribute.RequestStoreId, storeId)); - } + if (enabledAttributeNames.Contains(TelemetryAttribute.RetryCount)) { + tagList.Add(TelemetryAttribute.RetryCount, retryCount); } - if (enabledAttributes.Contains(TelemetryAttribute.RequestModelId)) { - attributes = AddRequestModelIdAttributes(requestBuilder, apiName, attributes); + if (enabledAttributeNames.Contains(TelemetryAttribute.RequestClientId)) { + var clientId = credentials?.Config?.ClientId ?? null; + if (clientId != null) { + tagList.Add(TelemetryAttribute.RequestClientId, clientId); + } } - return attributes; + return tagList; } - private static TagList AddRequestModelIdAttributes( - RequestBuilder requestBuilder, string apiName, TagList attributes) { - string? modelId = null; - - if (requestBuilder.PathParameters.ContainsKey("authorization_model_id")) { - modelId = requestBuilder.PathParameters.GetValueOrDefault("authorization_model_id"); - } - else if (requestBuilder.PathTemplate == "/stores/{store_id}/authorization-models/{id}" && - requestBuilder.PathParameters.ContainsKey("id")) { - modelId = requestBuilder.PathParameters.GetValueOrDefault("id"); + /// + /// Builds the attribute tags for metrics for a response + /// + /// The enabled attribute names (must be a subset of ) + /// The client credentials used make the API call + /// The API method which is being called. + /// The response of the call which is being made + /// The request builder used to make the call + /// Measures the total request time + /// How many times the API request was retried + /// The type of the request, required for API calls + /// Attributes for telemetry + public static TagList BuildAttributesForResponse(HashSet enabledAttributeNames, Credentials? credentials, + string? apiName, HttpResponseMessage response, RequestBuilder requestBuilder, Stopwatch requestDuration, int retryCount = 0) { + if (enabledAttributeNames.Count == 0) { + return new TagList(); } - if (!string.IsNullOrEmpty(modelId)) { - attributes.Add(new KeyValuePair(TelemetryAttribute.RequestModelId, modelId)); - } + var tagList = new TagList(); - if (apiName is "Check" or "ListObjects" or "Write" or "Expand" or "ListUsers") { - AddRequestBodyAttributes(requestBuilder, apiName, attributes); + if (enabledAttributeNames.Contains(TelemetryAttribute.RequestMethod) && apiName != null) { + tagList.Add(TelemetryAttribute.RequestMethod, apiName); } - return attributes; - } - - private static TagList AddRequestBodyAttributes( - RequestBuilder requestBuilder, string apiName, TagList attributes) { - try { - if (requestBuilder.JsonBody != null) { - using (var document = JsonDocument.Parse(requestBuilder.JsonBody)) { - var root = document.RootElement; - - if (root.TryGetProperty("authorization_model_id", out var authModelId) && - !string.IsNullOrEmpty(authModelId.GetString())) { - attributes.Add(new KeyValuePair(TelemetryAttribute.RequestModelId, - authModelId.GetString())); - } - - if (apiName is "Check" or "ListObjects" && root.TryGetProperty("user", out var fgaUser) && - !string.IsNullOrEmpty(fgaUser.GetString())) { - attributes.Add(new KeyValuePair(TelemetryAttribute.FgaRequestUser, - fgaUser.GetString())); - } - } - } - } - catch { - // Handle parsing errors if necessary + if (enabledAttributeNames.Contains(TelemetryAttribute.RetryCount)) { + tagList.Add(TelemetryAttribute.RetryCount, retryCount); } - return attributes; - } + if (enabledAttributeNames.Contains(TelemetryAttribute.ResponseStatus)) { + tagList.Add(TelemetryAttribute.ResponseStatus, (int)response.StatusCode); + } - private static TagList AddResponseAttributes( - HashSet enabledAttributes, HttpResponseMessage response, TagList attributes) { - if (enabledAttributes.Contains(TelemetryAttribute.HttpStatus) && response.StatusCode != null) { - attributes.Add(new KeyValuePair(TelemetryAttribute.HttpStatus, (int)response.StatusCode)); + if (enabledAttributeNames.Contains(TelemetryAttribute.ResponseSuccess)) { + tagList.Add(TelemetryAttribute.ResponseSuccess, response.IsSuccessStatusCode); } - if (enabledAttributes.Contains(TelemetryAttribute.ResponseModelId)) { - var responseModelId = GetHeaderValueIfValid(response.Headers, "openfga-authorization-model-id") ?? - GetHeaderValueIfValid(response.Headers, "fga-authorization-model-id"); - if (!string.IsNullOrEmpty(responseModelId)) { - attributes.Add(new KeyValuePair(TelemetryAttribute.ResponseModelId, responseModelId)); + if (enabledAttributeNames.Contains(TelemetryAttribute.RequestClientId)) { + var clientId = credentials?.Config?.ClientId ?? null; + if (clientId != null) { + tagList.Add(TelemetryAttribute.RequestClientId, clientId); } } - return attributes; - } + if (enabledAttributeNames.Contains(TelemetryAttribute.RequestStoreId) && + requestBuilder.PathParameters.TryGetValue("store_id", out var storeId) && + !string.IsNullOrEmpty(storeId)) { + tagList.Add(TelemetryAttribute.RequestStoreId, storeId); + } - private static TagList AddCommonAttributes( - HashSet enabledAttributes, HttpResponseMessage response, RequestBuilder requestBuilder, - Credentials? credentials, int retryCount, TagList attributes) { - if (response.RequestMessage != null) { - if (enabledAttributes.Contains(TelemetryAttribute.HttpMethod) && response.RequestMessage.Method != null) { - attributes.Add(new KeyValuePair(TelemetryAttribute.HttpMethod, - response.RequestMessage.Method)); + if (enabledAttributeNames.Contains(TelemetryAttribute.RequestModelId) && enabledAttributeNames.Contains(TelemetryAttribute.ResponseModelId)) { + // Try to read the model ID from the path params + var modelIdParam = requestBuilder.PathParameters.GetValueOrDefault("authorization_model_id"); + if (!string.IsNullOrEmpty(modelIdParam)) { + tagList.Add(TelemetryAttribute.RequestModelId, modelIdParam); + tagList.Add(TelemetryAttribute.ResponseModelId, modelIdParam); } - - if (response.RequestMessage.RequestUri != null) { - if (enabledAttributes.Contains(TelemetryAttribute.HttpScheme)) { - attributes.Add(new KeyValuePair(TelemetryAttribute.HttpScheme, - response.RequestMessage.RequestUri.Scheme)); - } - - if (enabledAttributes.Contains(TelemetryAttribute.HttpHost)) { - attributes.Add(new KeyValuePair(TelemetryAttribute.HttpHost, - response.RequestMessage.RequestUri.Host)); + else { + // Try to read the model ID from the query params + var modelIdQuery = requestBuilder.QueryParameters.GetValueOrDefault("authorization_model_id"); + if (!string.IsNullOrEmpty(modelIdQuery)) { + tagList.Add(TelemetryAttribute.RequestModelId, modelIdQuery); + tagList.Add(TelemetryAttribute.ResponseModelId, modelIdQuery); } - - if (enabledAttributes.Contains(TelemetryAttribute.HttpUrl)) { - attributes.Add(new KeyValuePair(TelemetryAttribute.HttpUrl, - response.RequestMessage.RequestUri.AbsoluteUri)); + else if (requestBuilder.Body != null) { + // Try to read the model ID from the request body + var requestBodyJson = requestBuilder.JsonBody; + if (!string.IsNullOrEmpty(requestBodyJson) && requestBodyJson.Contains("authorization_model_id")) { + try { + var bodyDoc = JsonDocument.Parse(requestBodyJson); + if (bodyDoc.RootElement.TryGetProperty("authorization_model_id", out var modelIdJsonElement)) { + var modelIdValue = modelIdJsonElement.GetString(); + if (!string.IsNullOrEmpty(modelIdValue)) { + tagList.Add(TelemetryAttribute.RequestModelId, modelIdValue); + tagList.Add(TelemetryAttribute.ResponseModelId, modelIdValue); + } + } + } + catch { + // This is just for metrics, it's safe to ignore parsing failures. + } + } } } - - if (enabledAttributes.Contains(TelemetryAttribute.HttpUserAgent) && - response.RequestMessage.Headers.UserAgent != null && - !string.IsNullOrEmpty(response.RequestMessage.Headers.UserAgent.ToString())) { - attributes.Add(new KeyValuePair(TelemetryAttribute.HttpUserAgent, - response.RequestMessage.Headers.UserAgent.ToString())); - } } - if (enabledAttributes.Contains(TelemetryAttribute.RequestClientId) && credentials is { Method: CredentialsMethod.ClientCredentials, Config.ClientId: not null }) { - attributes.Add(new KeyValuePair(TelemetryAttribute.RequestClientId, - credentials.Config.ClientId)); - } + if (requestBuilder.Body != null) { + var bodyWithTupleKey = requestBuilder.JsonBody; + if (!string.IsNullOrEmpty(bodyWithTupleKey) && bodyWithTupleKey.Contains("tuple_key")) { + try { + var bodyDoc = JsonDocument.Parse(bodyWithTupleKey); + if (bodyDoc.RootElement.TryGetProperty("tuple_key", out var tupleKeyElement)) { + if (enabledAttributeNames.Contains(TelemetryAttribute.FgaRequestUser) && tupleKeyElement.TryGetProperty("user", out var userElement)) { + var userValue = userElement.GetString(); + if (!string.IsNullOrEmpty(userValue)) { + tagList.Add(TelemetryAttribute.FgaRequestUser, userValue); + } + } + + if (enabledAttributeNames.Contains(TelemetryAttribute.FgaRequestRelation) && tupleKeyElement.TryGetProperty("relation", out var relationElement)) { + var relationValue = relationElement.GetString(); + if (!string.IsNullOrEmpty(relationValue)) { + tagList.Add(TelemetryAttribute.FgaRequestRelation, relationValue); + } + } + + if (enabledAttributeNames.Contains(TelemetryAttribute.FgaRequestObject) && tupleKeyElement.TryGetProperty("object", out var objectElement)) { + var objectValue = objectElement.GetString(); + if (!string.IsNullOrEmpty(objectValue)) { + tagList.Add(TelemetryAttribute.FgaRequestObject, objectValue); + } + } + } - if (enabledAttributes.Contains(TelemetryAttribute.RequestRetryCount) && retryCount > 0) { - attributes.Add(new KeyValuePair(TelemetryAttribute.RequestRetryCount, retryCount)); + if (bodyDoc.RootElement.TryGetProperty("context", out var contextElement) && + enabledAttributeNames.Contains(TelemetryAttribute.FgaRequestContext) && + !contextElement.ValueKind.Equals(JsonValueKind.Null)) { + tagList.Add(TelemetryAttribute.FgaRequestContext, true); + } + + if (bodyDoc.RootElement.TryGetProperty("type", out var typeElement)) { + var typeValue = typeElement.GetString(); + if (!string.IsNullOrEmpty(typeValue) && enabledAttributeNames.Contains(TelemetryAttribute.FgaRequestType)) { + tagList.Add(TelemetryAttribute.FgaRequestType, typeValue); + } + } + } + catch { + // This is just for metrics, it's safe to ignore parsing failures. + } + } } - return attributes; + return tagList; } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Telemetry/Counters.cs b/src/OpenFga.Sdk/Telemetry/Counters.cs index 86de2e6..6c5e1da 100644 --- a/src/OpenFga.Sdk/Telemetry/Counters.cs +++ b/src/OpenFga.Sdk/Telemetry/Counters.cs @@ -10,10 +10,6 @@ // NOTE: This file was auto generated. DO NOT EDIT. // - -using System.Diagnostics; -using System.Diagnostics.Metrics; - namespace OpenFga.Sdk.Telemetry; /// diff --git a/src/OpenFga.Sdk/Telemetry/Histograms.cs b/src/OpenFga.Sdk/Telemetry/Histograms.cs index ab02547..459bda1 100644 --- a/src/OpenFga.Sdk/Telemetry/Histograms.cs +++ b/src/OpenFga.Sdk/Telemetry/Histograms.cs @@ -12,7 +12,6 @@ using System.Diagnostics; -using System.Diagnostics.Metrics; namespace OpenFga.Sdk.Telemetry; diff --git a/src/OpenFga.Sdk/Telemetry/Meters.cs b/src/OpenFga.Sdk/Telemetry/Meters.cs index ff9748e..35c9477 100644 --- a/src/OpenFga.Sdk/Telemetry/Meters.cs +++ b/src/OpenFga.Sdk/Telemetry/Meters.cs @@ -10,7 +10,6 @@ // NOTE: This file was auto generated. DO NOT EDIT. // - namespace OpenFga.Sdk.Telemetry; /// @@ -46,11 +45,11 @@ public static class TelemetryMeter { /// Return all supported meter names /// public static HashSet GetAllMeters() { - return new() { - RequestDuration, - QueryDuration, - TokenExchangeCount, - RequestCount - }; + var meters = new HashSet(); + meters.Add(RequestDuration); + meters.Add(QueryDuration); + meters.Add(TokenExchangeCount); + meters.Add(RequestCount); + return meters; } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Telemetry/Metrics.cs b/src/OpenFga.Sdk/Telemetry/Metrics.cs index e2a0afd..226db73 100644 --- a/src/OpenFga.Sdk/Telemetry/Metrics.cs +++ b/src/OpenFga.Sdk/Telemetry/Metrics.cs @@ -14,7 +14,6 @@ using OpenFga.Sdk.ApiClient; using OpenFga.Sdk.Configuration; using System.Diagnostics; -using System.Diagnostics.Metrics; namespace OpenFga.Sdk.Telemetry; diff --git a/src/OpenFga.Sdk/Telemetry/Standard20TelemetryTypes.cs b/src/OpenFga.Sdk/Telemetry/Standard20TelemetryTypes.cs new file mode 100644 index 0000000..4308a35 --- /dev/null +++ b/src/OpenFga.Sdk/Telemetry/Standard20TelemetryTypes.cs @@ -0,0 +1,99 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 1.x +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://openfga.dev/community +// 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.Telemetry { + /// + /// TagList implementation for telemetry attributes + /// + public class TagList : Dictionary { + // Helper methods to replace typical Add operations + + public void Add(string key) { + base.Add(key, true); + } + + public void AddRange(Dictionary keyValues) { + foreach (var item in keyValues) { + base.Add(item.Key, item.Value); + } + } + + public new void Add(string key, object value) { + base.Add(key, value); + } + } + + /// + /// Meter implementation for telemetry + /// + public class Meter { + public string Name { get; } + public string Version { get; } + + public Meter(string name) { + Name = name; + Version = string.Empty; + } + + public Meter(string name, string version) { + Name = name; + Version = version; + } + + /// + /// Creates a counter for the meter + /// + public Counter CreateCounter(string name, string description = null, string unit = null) { + return new Counter(name); + } + + /// + /// Creates a histogram for the meter + /// + public Histogram CreateHistogram(string name, string description = null, string unit = null) { + return new Histogram(name); + } + } + + /// + /// Counter implementation for telemetry + /// + /// Type of the counter + public class Counter { + public string Name { get; } + + public Counter(string name) { + Name = name; + } + + public void Add(T value, TagList tags = null) { + // No-op implementation + } + } + + /// + /// Histogram implementation for telemetry + /// + /// Type of the histogram + public class Histogram { + public string Name { get; } + + public Histogram(string name) { + Name = name; + } + + public void Record(T value, TagList tags = null) { + // No-op implementation + } + } +} \ No newline at end of file From 5fbd1b52a48eb5f3bc196e58f545c2d6e21c292e Mon Sep 17 00:00:00 2001 From: Ryan Quinn Date: Thu, 8 May 2025 11:31:45 -0500 Subject: [PATCH 2/4] codeql fixes and updates from sdk-generator --- src/OpenFga.Sdk/Client/Client.cs | 105 +++++++++++++++ .../Model/AbortedMessageResponse.cs | 78 +++++++++-- src/OpenFga.Sdk/Model/Any.cs | 61 ++++++++- src/OpenFga.Sdk/Model/Assertion.cs | 96 ++++++++++---- src/OpenFga.Sdk/Model/AssertionTupleKey.cs | 87 +++++++++--- src/OpenFga.Sdk/Model/AuthorizationModel.cs | 98 ++++++++++---- src/OpenFga.Sdk/Model/BatchCheckItem.cs | 96 ++++++++++---- src/OpenFga.Sdk/Model/BatchCheckRequest.cs | 87 +++++++++--- src/OpenFga.Sdk/Model/BatchCheckResponse.cs | 70 ++++++++-- .../Model/BatchCheckSingleResult.cs | 77 +++++++++-- src/OpenFga.Sdk/Model/CheckError.cs | 85 +++++++++--- src/OpenFga.Sdk/Model/CheckRequest.cs | 112 +++++++++++----- src/OpenFga.Sdk/Model/CheckRequestTupleKey.cs | 87 +++++++++--- src/OpenFga.Sdk/Model/CheckResponse.cs | 77 +++++++++-- src/OpenFga.Sdk/Model/Computed.cs | 69 ++++++++-- src/OpenFga.Sdk/Model/Condition.cs | 97 ++++++++++---- src/OpenFga.Sdk/Model/ConditionMetadata.cs | 78 +++++++++-- .../Model/ConditionParamTypeRef.cs | 78 +++++++++-- src/OpenFga.Sdk/Model/ContextualTupleKeys.cs | 70 ++++++++-- src/OpenFga.Sdk/Model/CreateStoreRequest.cs | 69 ++++++++-- src/OpenFga.Sdk/Model/CreateStoreResponse.cs | 96 ++++++++++---- src/OpenFga.Sdk/Model/Difference.cs | 78 +++++++++-- src/OpenFga.Sdk/Model/ExpandRequest.cs | 95 ++++++++++---- .../Model/ExpandRequestTupleKey.cs | 78 +++++++++-- src/OpenFga.Sdk/Model/ExpandResponse.cs | 69 ++++++++-- src/OpenFga.Sdk/Model/FgaObject.cs | 78 +++++++++-- src/OpenFga.Sdk/Model/ForbiddenResponse.cs | 77 +++++++++-- src/OpenFga.Sdk/Model/GetStoreResponse.cs | 105 +++++++++++---- .../Model/InternalErrorMessageResponse.cs | 77 +++++++++-- src/OpenFga.Sdk/Model/Leaf.cs | 87 +++++++++--- src/OpenFga.Sdk/Model/ListObjectsRequest.cs | 122 +++++++++++------ src/OpenFga.Sdk/Model/ListObjectsResponse.cs | 70 ++++++++-- src/OpenFga.Sdk/Model/ListStoresResponse.cs | 79 +++++++++-- src/OpenFga.Sdk/Model/ListUsersRequest.cs | 124 ++++++++++++------ src/OpenFga.Sdk/Model/ListUsersResponse.cs | 70 ++++++++-- src/OpenFga.Sdk/Model/Metadata.cs | 88 ++++++++++--- src/OpenFga.Sdk/Model/Node.cs | 105 +++++++++++---- src/OpenFga.Sdk/Model/Nodes.cs | 70 ++++++++-- src/OpenFga.Sdk/Model/ObjectRelation.cs | 78 +++++++++-- .../Model/PathUnknownErrorMessageResponse.cs | 77 +++++++++-- .../Model/ReadAssertionsResponse.cs | 79 +++++++++-- .../Model/ReadAuthorizationModelResponse.cs | 69 ++++++++-- .../Model/ReadAuthorizationModelsResponse.cs | 79 +++++++++-- src/OpenFga.Sdk/Model/ReadChangesResponse.cs | 79 +++++++++-- src/OpenFga.Sdk/Model/ReadRequest.cs | 94 ++++++++++--- src/OpenFga.Sdk/Model/ReadRequestTupleKey.cs | 87 +++++++++--- src/OpenFga.Sdk/Model/ReadResponse.cs | 79 +++++++++-- src/OpenFga.Sdk/Model/RelationMetadata.cs | 88 ++++++++++--- src/OpenFga.Sdk/Model/RelationReference.cs | 96 ++++++++++---- .../Model/RelationshipCondition.cs | 78 +++++++++-- src/OpenFga.Sdk/Model/SourceInfo.cs | 69 ++++++++-- src/OpenFga.Sdk/Model/Status.cs | 87 +++++++++--- src/OpenFga.Sdk/Model/Store.cs | 105 +++++++++++---- src/OpenFga.Sdk/Model/Tuple.cs | 78 +++++++++-- src/OpenFga.Sdk/Model/TupleChange.cs | 86 +++++++++--- src/OpenFga.Sdk/Model/TupleKey.cs | 96 ++++++++++---- .../Model/TupleKeyWithoutCondition.cs | 87 +++++++++--- src/OpenFga.Sdk/Model/TupleToUserset.cs | 78 +++++++++-- src/OpenFga.Sdk/Model/TypeDefinition.cs | 88 ++++++++++--- src/OpenFga.Sdk/Model/TypedWildcard.cs | 69 ++++++++-- .../Model/UnauthenticatedResponse.cs | 77 +++++++++-- .../UnprocessableContentMessageResponse.cs | 77 +++++++++-- src/OpenFga.Sdk/Model/User.cs | 87 +++++++++--- src/OpenFga.Sdk/Model/UserTypeFilter.cs | 78 +++++++++-- src/OpenFga.Sdk/Model/Users.cs | 70 ++++++++-- src/OpenFga.Sdk/Model/Userset.cs | 114 +++++++++++----- src/OpenFga.Sdk/Model/UsersetTree.cs | 69 ++++++++-- .../Model/UsersetTreeDifference.cs | 78 +++++++++-- .../Model/UsersetTreeTupleToUserset.cs | 79 +++++++++-- src/OpenFga.Sdk/Model/UsersetUser.cs | 87 +++++++++--- src/OpenFga.Sdk/Model/Usersets.cs | 70 ++++++++-- .../Model/ValidationErrorMessageResponse.cs | 77 +++++++++-- .../Model/WriteAssertionsRequest.cs | 70 ++++++++-- .../Model/WriteAuthorizationModelRequest.cs | 89 ++++++++++--- .../Model/WriteAuthorizationModelResponse.cs | 69 ++++++++-- src/OpenFga.Sdk/Model/WriteRequest.cs | 87 +++++++++--- src/OpenFga.Sdk/Model/WriteRequestDeletes.cs | 70 ++++++++-- src/OpenFga.Sdk/Model/WriteRequestWrites.cs | 70 ++++++++-- src/OpenFga.Sdk/Telemetry/Attributes.cs | 14 +- 79 files changed, 5281 insertions(+), 1222 deletions(-) diff --git a/src/OpenFga.Sdk/Client/Client.cs b/src/OpenFga.Sdk/Client/Client.cs index 5ae6da5..cc676d5 100644 --- a/src/OpenFga.Sdk/Client/Client.cs +++ b/src/OpenFga.Sdk/Client/Client.cs @@ -242,6 +242,51 @@ await writeChunks.ForEachAsync(async (request) => { }); } } + catch (FgaApiAuthenticationError e) { + foreach (var tupleKey in writes) { + writeResponses.Add(new ClientWriteSingleResponse { + TupleKey = tupleKey.ToTupleKey(), + Status = ClientWriteStatus.FAILURE, + Error = e, + }); + } + } + catch (FgaApiInternalError e) { + foreach (var tupleKey in writes) { + writeResponses.Add(new ClientWriteSingleResponse { + TupleKey = tupleKey.ToTupleKey(), + Status = ClientWriteStatus.FAILURE, + Error = e, + }); + } + } + catch (FgaApiValidationError e) { + foreach (var tupleKey in writes) { + writeResponses.Add(new ClientWriteSingleResponse { + TupleKey = tupleKey.ToTupleKey(), + Status = ClientWriteStatus.FAILURE, + Error = e, + }); + } + } + catch (FgaApiNotFoundError e) { + foreach (var tupleKey in writes) { + writeResponses.Add(new ClientWriteSingleResponse { + TupleKey = tupleKey.ToTupleKey(), + Status = ClientWriteStatus.FAILURE, + Error = e, + }); + } + } + catch (FgaApiRateLimitExceededError e) { + foreach (var tupleKey in writes) { + writeResponses.Add(new ClientWriteSingleResponse { + TupleKey = tupleKey.ToTupleKey(), + Status = ClientWriteStatus.FAILURE, + Error = e, + }); + } + } catch (Exception e) { foreach (var tupleKey in writes) { writeResponses.Add(new ClientWriteSingleResponse { @@ -265,6 +310,51 @@ await deleteChunks.ForEachAsync(async (request) => { }); } } + catch (FgaApiAuthenticationError e) { + foreach (var tupleKey in deletes) { + deleteResponses.Add(new ClientWriteSingleResponse { + TupleKey = tupleKey.ToTupleKey(), + Status = ClientWriteStatus.FAILURE, + Error = e, + }); + } + } + catch (FgaApiInternalError e) { + foreach (var tupleKey in deletes) { + deleteResponses.Add(new ClientWriteSingleResponse { + TupleKey = tupleKey.ToTupleKey(), + Status = ClientWriteStatus.FAILURE, + Error = e, + }); + } + } + catch (FgaApiValidationError e) { + foreach (var tupleKey in deletes) { + deleteResponses.Add(new ClientWriteSingleResponse { + TupleKey = tupleKey.ToTupleKey(), + Status = ClientWriteStatus.FAILURE, + Error = e, + }); + } + } + catch (FgaApiNotFoundError e) { + foreach (var tupleKey in deletes) { + deleteResponses.Add(new ClientWriteSingleResponse { + TupleKey = tupleKey.ToTupleKey(), + Status = ClientWriteStatus.FAILURE, + Error = e, + }); + } + } + catch (FgaApiRateLimitExceededError e) { + foreach (var tupleKey in deletes) { + deleteResponses.Add(new ClientWriteSingleResponse { + TupleKey = tupleKey.ToTupleKey(), + Status = ClientWriteStatus.FAILURE, + Error = e, + }); + } + } catch (Exception e) { foreach (var tupleKey in deletes) { deleteResponses.Add(new ClientWriteSingleResponse { @@ -334,6 +424,21 @@ await body.ForEachAsync(async (request) => { Error = null }); } + catch (FgaApiAuthenticationError e) { + responses.Add(new BatchCheckSingleResponse { Allowed = false, Request = request, Error = e }); + } + catch (FgaApiInternalError e) { + responses.Add(new BatchCheckSingleResponse { Allowed = false, Request = request, Error = e }); + } + catch (FgaApiValidationError e) { + responses.Add(new BatchCheckSingleResponse { Allowed = false, Request = request, Error = e }); + } + catch (FgaApiNotFoundError e) { + responses.Add(new BatchCheckSingleResponse { Allowed = false, Request = request, Error = e }); + } + catch (FgaApiRateLimitExceededError e) { + responses.Add(new BatchCheckSingleResponse { Allowed = false, Request = request, Error = e }); + } catch (Exception e) { responses.Add(new BatchCheckSingleResponse { Allowed = false, Request = request, Error = e }); } diff --git a/src/OpenFga.Sdk/Model/AbortedMessageResponse.cs b/src/OpenFga.Sdk/Model/AbortedMessageResponse.cs index 775ec79..e528fed 100644 --- a/src/OpenFga.Sdk/Model/AbortedMessageResponse.cs +++ b/src/OpenFga.Sdk/Model/AbortedMessageResponse.cs @@ -80,7 +80,17 @@ public static AbortedMessageResponse FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as AbortedMessageResponse); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((AbortedMessageResponse)input); } /// @@ -92,18 +102,60 @@ 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()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(AbortedMessageResponse input) { + + if (!IsPropertyEqual(this.Code, input.Code)) { + return false; + } + + if (!IsPropertyEqual(this.Message, input.Message)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(AbortedMessageResponse input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/Any.cs b/src/OpenFga.Sdk/Model/Any.cs index 0ab3d3c..fea241d 100644 --- a/src/OpenFga.Sdk/Model/Any.cs +++ b/src/OpenFga.Sdk/Model/Any.cs @@ -61,7 +61,17 @@ public static Any FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as Any); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((Any)input); } /// @@ -73,12 +83,49 @@ public bool Equals(Any input) { if (input == null) { return false; } - return base.Equals(input) && - ( - this.Type == input.Type || - (this.Type != null && - this.Type.Equals(input.Type)) - ); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(Any input) { + + if (!base.Equals(input)) { + return false; + } + + if (!IsPropertyEqual(this.Type, input.Type)) { + return false; + } + + + + return true; + } + + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/Assertion.cs b/src/OpenFga.Sdk/Model/Assertion.cs index d318949..4eb1c88 100644 --- a/src/OpenFga.Sdk/Model/Assertion.cs +++ b/src/OpenFga.Sdk/Model/Assertion.cs @@ -105,7 +105,17 @@ public static Assertion FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as Assertion); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((Assertion)input); } /// @@ -117,28 +127,68 @@ public bool Equals(Assertion input) { if (input == null) { return false; } - return - ( - this.TupleKey == input.TupleKey || - (this.TupleKey != null && - this.TupleKey.Equals(input.TupleKey)) - ) && - ( - this.Expectation == input.Expectation || - this.Expectation.Equals(input.Expectation) - ) && - ( - this.ContextualTuples == input.ContextualTuples || - this.ContextualTuples != null && - input.ContextualTuples != null && - this.ContextualTuples.SequenceEqual(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()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(Assertion input) { + + if (!IsPropertyEqual(this.TupleKey, input.TupleKey)) { + return false; + } + + if (!IsPropertyEqual(this.Expectation, input.Expectation)) { + return false; + } + + if (!IsCollectionPropertyEqual(this.ContextualTuples, input.ContextualTuples)) { + return false; + } + + if (!IsPropertyEqual(this.Context, input.Context)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(Assertion input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/AssertionTupleKey.cs b/src/OpenFga.Sdk/Model/AssertionTupleKey.cs index 3526acf..8513663 100644 --- a/src/OpenFga.Sdk/Model/AssertionTupleKey.cs +++ b/src/OpenFga.Sdk/Model/AssertionTupleKey.cs @@ -102,7 +102,17 @@ public static AssertionTupleKey FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as AssertionTupleKey); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((AssertionTupleKey)input); } /// @@ -114,23 +124,64 @@ 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()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(AssertionTupleKey input) { + + if (!IsPropertyEqual(this.Object, input.Object)) { + return false; + } + + if (!IsPropertyEqual(this.Relation, input.Relation)) { + return false; + } + + if (!IsPropertyEqual(this.User, input.User)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(AssertionTupleKey input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/AuthorizationModel.cs b/src/OpenFga.Sdk/Model/AuthorizationModel.cs index 002259e..8655180 100644 --- a/src/OpenFga.Sdk/Model/AuthorizationModel.cs +++ b/src/OpenFga.Sdk/Model/AuthorizationModel.cs @@ -112,7 +112,17 @@ public static AuthorizationModel FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as AuthorizationModel); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((AuthorizationModel)input); } /// @@ -124,30 +134,68 @@ public bool Equals(AuthorizationModel input) { if (input == null) { return false; } - return - ( - this.Id == input.Id || - (this.Id != null && - this.Id.Equals(input.Id)) - ) && - ( - this.SchemaVersion == input.SchemaVersion || - (this.SchemaVersion != null && - this.SchemaVersion.Equals(input.SchemaVersion)) - ) && - ( - this.TypeDefinitions == input.TypeDefinitions || - 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()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(AuthorizationModel input) { + + if (!IsPropertyEqual(this.Id, input.Id)) { + return false; + } + + if (!IsPropertyEqual(this.SchemaVersion, input.SchemaVersion)) { + return false; + } + + if (!IsCollectionPropertyEqual(this.TypeDefinitions, input.TypeDefinitions)) { + return false; + } + + if (!IsCollectionPropertyEqual(this.Conditions, input.Conditions)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(AuthorizationModel input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/BatchCheckItem.cs b/src/OpenFga.Sdk/Model/BatchCheckItem.cs index d8239e7..76bdc44 100644 --- a/src/OpenFga.Sdk/Model/BatchCheckItem.cs +++ b/src/OpenFga.Sdk/Model/BatchCheckItem.cs @@ -109,7 +109,17 @@ public static BatchCheckItem FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as BatchCheckItem); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((BatchCheckItem)input); } /// @@ -121,28 +131,68 @@ public bool Equals(BatchCheckItem input) { if (input == null) { return false; } - return - ( - this.TupleKey == input.TupleKey || - (this.TupleKey != null && - this.TupleKey.Equals(input.TupleKey)) - ) && - ( - 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.CorrelationId == input.CorrelationId || - (this.CorrelationId != null && - this.CorrelationId.Equals(input.CorrelationId)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(BatchCheckItem input) { + + if (!IsPropertyEqual(this.TupleKey, input.TupleKey)) { + return false; + } + + if (!IsPropertyEqual(this.ContextualTuples, input.ContextualTuples)) { + return false; + } + + if (!IsPropertyEqual(this.Context, input.Context)) { + return false; + } + + if (!IsPropertyEqual(this.CorrelationId, input.CorrelationId)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(BatchCheckItem input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/BatchCheckRequest.cs b/src/OpenFga.Sdk/Model/BatchCheckRequest.cs index e3508fe..8bf563f 100644 --- a/src/OpenFga.Sdk/Model/BatchCheckRequest.cs +++ b/src/OpenFga.Sdk/Model/BatchCheckRequest.cs @@ -93,7 +93,17 @@ public static BatchCheckRequest FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as BatchCheckRequest); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((BatchCheckRequest)input); } /// @@ -105,23 +115,64 @@ public bool Equals(BatchCheckRequest input) { if (input == null) { return false; } - return - ( - this.Checks == input.Checks || - this.Checks != null && - input.Checks != null && - this.Checks.SequenceEqual(input.Checks) - ) && - ( - this.AuthorizationModelId == input.AuthorizationModelId || - (this.AuthorizationModelId != null && - this.AuthorizationModelId.Equals(input.AuthorizationModelId)) - ) && - ( - this.Consistency == input.Consistency || - this.Consistency.Equals(input.Consistency) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(BatchCheckRequest input) { + + if (!IsCollectionPropertyEqual(this.Checks, input.Checks)) { + return false; + } + + if (!IsPropertyEqual(this.AuthorizationModelId, input.AuthorizationModelId)) { + return false; + } + + if (!IsPropertyEqual(this.Consistency, input.Consistency)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(BatchCheckRequest input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/BatchCheckResponse.cs b/src/OpenFga.Sdk/Model/BatchCheckResponse.cs index cc4799e..8d471aa 100644 --- a/src/OpenFga.Sdk/Model/BatchCheckResponse.cs +++ b/src/OpenFga.Sdk/Model/BatchCheckResponse.cs @@ -71,7 +71,17 @@ public static BatchCheckResponse FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as BatchCheckResponse); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((BatchCheckResponse)input); } /// @@ -83,14 +93,56 @@ public bool Equals(BatchCheckResponse input) { if (input == null) { return false; } - return - ( - this.Result == input.Result || - this.Result != null && - input.Result != null && - this.Result.SequenceEqual(input.Result) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(BatchCheckResponse input) { + + if (!IsCollectionPropertyEqual(this.Result, input.Result)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(BatchCheckResponse input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/BatchCheckSingleResult.cs b/src/OpenFga.Sdk/Model/BatchCheckSingleResult.cs index 495de35..40e3402 100644 --- a/src/OpenFga.Sdk/Model/BatchCheckSingleResult.cs +++ b/src/OpenFga.Sdk/Model/BatchCheckSingleResult.cs @@ -80,7 +80,17 @@ public static BatchCheckSingleResult FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as BatchCheckSingleResult); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((BatchCheckSingleResult)input); } /// @@ -92,17 +102,60 @@ public bool Equals(BatchCheckSingleResult input) { if (input == null) { return false; } - return - ( - this.Allowed == input.Allowed || - this.Allowed.Equals(input.Allowed) - ) && - ( - this.Error == input.Error || - (this.Error != null && - this.Error.Equals(input.Error)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(BatchCheckSingleResult input) { + + if (!IsPropertyEqual(this.Allowed, input.Allowed)) { + return false; + } + + if (!IsPropertyEqual(this.Error, input.Error)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(BatchCheckSingleResult input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/CheckError.cs b/src/OpenFga.Sdk/Model/CheckError.cs index ac32838..1843ac9 100644 --- a/src/OpenFga.Sdk/Model/CheckError.cs +++ b/src/OpenFga.Sdk/Model/CheckError.cs @@ -88,7 +88,17 @@ public static CheckError FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as CheckError); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((CheckError)input); } /// @@ -100,21 +110,64 @@ public bool Equals(CheckError input) { if (input == null) { return false; } - return - ( - this.InputError == input.InputError || - this.InputError.Equals(input.InputError) - ) && - ( - this.InternalError == input.InternalError || - this.InternalError.Equals(input.InternalError) - ) && - ( - this.Message == input.Message || - (this.Message != null && - this.Message.Equals(input.Message)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(CheckError input) { + + if (!IsPropertyEqual(this.InputError, input.InputError)) { + return false; + } + + if (!IsPropertyEqual(this.InternalError, input.InternalError)) { + return false; + } + + if (!IsPropertyEqual(this.Message, input.Message)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(CheckError input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/CheckRequest.cs b/src/OpenFga.Sdk/Model/CheckRequest.cs index e21cff8..5f68477 100644 --- a/src/OpenFga.Sdk/Model/CheckRequest.cs +++ b/src/OpenFga.Sdk/Model/CheckRequest.cs @@ -130,7 +130,17 @@ public static CheckRequest FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as CheckRequest); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((CheckRequest)input); } /// @@ -142,36 +152,76 @@ public bool Equals(CheckRequest input) { if (input == null) { return false; } - return - ( - this.TupleKey == input.TupleKey || - (this.TupleKey != null && - this.TupleKey.Equals(input.TupleKey)) - ) && - ( - this.ContextualTuples == input.ContextualTuples || - (this.ContextualTuples != null && - this.ContextualTuples.Equals(input.ContextualTuples)) - ) && - ( - this.AuthorizationModelId == input.AuthorizationModelId || - (this.AuthorizationModelId != null && - this.AuthorizationModelId.Equals(input.AuthorizationModelId)) - ) && - ( - this.Trace == input.Trace || - this.Trace.Equals(input.Trace) - ) && - ( - this.Context == input.Context || - (this.Context != null && - this.Context.Equals(input.Context)) - ) && - ( - this.Consistency == input.Consistency || - this.Consistency.Equals(input.Consistency) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(CheckRequest input) { + + if (!IsPropertyEqual(this.TupleKey, input.TupleKey)) { + return false; + } + + if (!IsPropertyEqual(this.ContextualTuples, input.ContextualTuples)) { + return false; + } + + if (!IsPropertyEqual(this.AuthorizationModelId, input.AuthorizationModelId)) { + return false; + } + + if (!IsPropertyEqual(this.Trace, input.Trace)) { + return false; + } + + if (!IsPropertyEqual(this.Context, input.Context)) { + return false; + } + + if (!IsPropertyEqual(this.Consistency, input.Consistency)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(CheckRequest input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/CheckRequestTupleKey.cs b/src/OpenFga.Sdk/Model/CheckRequestTupleKey.cs index f69b8ae..72fe423 100644 --- a/src/OpenFga.Sdk/Model/CheckRequestTupleKey.cs +++ b/src/OpenFga.Sdk/Model/CheckRequestTupleKey.cs @@ -102,7 +102,17 @@ public static CheckRequestTupleKey FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as CheckRequestTupleKey); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((CheckRequestTupleKey)input); } /// @@ -114,23 +124,64 @@ 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()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(CheckRequestTupleKey input) { + + if (!IsPropertyEqual(this.User, input.User)) { + return false; + } + + if (!IsPropertyEqual(this.Relation, input.Relation)) { + return false; + } + + if (!IsPropertyEqual(this.Object, input.Object)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(CheckRequestTupleKey input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/CheckResponse.cs b/src/OpenFga.Sdk/Model/CheckResponse.cs index 87f1dee..85a2ccf 100644 --- a/src/OpenFga.Sdk/Model/CheckResponse.cs +++ b/src/OpenFga.Sdk/Model/CheckResponse.cs @@ -81,7 +81,17 @@ public static CheckResponse FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as CheckResponse); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((CheckResponse)input); } /// @@ -93,17 +103,60 @@ public bool Equals(CheckResponse input) { if (input == null) { return false; } - return - ( - this.Allowed == input.Allowed || - this.Allowed.Equals(input.Allowed) - ) && - ( - this.Resolution == input.Resolution || - (this.Resolution != null && - this.Resolution.Equals(input.Resolution)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(CheckResponse input) { + + if (!IsPropertyEqual(this.Allowed, input.Allowed)) { + return false; + } + + if (!IsPropertyEqual(this.Resolution, input.Resolution)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(CheckResponse input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/Computed.cs b/src/OpenFga.Sdk/Model/Computed.cs index e8d1eb3..b172889 100644 --- a/src/OpenFga.Sdk/Model/Computed.cs +++ b/src/OpenFga.Sdk/Model/Computed.cs @@ -74,7 +74,17 @@ public static Computed FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as Computed); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((Computed)input); } /// @@ -86,13 +96,56 @@ public bool Equals(Computed input) { if (input == null) { return false; } - return - ( - this.Userset == input.Userset || - (this.Userset != null && - this.Userset.Equals(input.Userset)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(Computed input) { + + if (!IsPropertyEqual(this.Userset, input.Userset)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(Computed input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/Condition.cs b/src/OpenFga.Sdk/Model/Condition.cs index 77aa505..e8f44e7 100644 --- a/src/OpenFga.Sdk/Model/Condition.cs +++ b/src/OpenFga.Sdk/Model/Condition.cs @@ -110,7 +110,17 @@ public static Condition FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as Condition); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((Condition)input); } /// @@ -122,29 +132,68 @@ 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.Metadata == input.Metadata || - (this.Metadata != null && - this.Metadata.Equals(input.Metadata)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(Condition input) { + + if (!IsPropertyEqual(this.Name, input.Name)) { + return false; + } + + if (!IsPropertyEqual(this.Expression, input.Expression)) { + return false; + } + + if (!IsCollectionPropertyEqual(this.Parameters, input.Parameters)) { + return false; + } + + if (!IsPropertyEqual(this.Metadata, input.Metadata)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(Condition input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/ConditionMetadata.cs b/src/OpenFga.Sdk/Model/ConditionMetadata.cs index 0c888ab..254336b 100644 --- a/src/OpenFga.Sdk/Model/ConditionMetadata.cs +++ b/src/OpenFga.Sdk/Model/ConditionMetadata.cs @@ -80,7 +80,17 @@ public static ConditionMetadata FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as ConditionMetadata); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((ConditionMetadata)input); } /// @@ -92,18 +102,60 @@ public bool Equals(ConditionMetadata input) { if (input == null) { return false; } - return - ( - this.Module == input.Module || - (this.Module != null && - this.Module.Equals(input.Module)) - ) && - ( - this.SourceInfo == input.SourceInfo || - (this.SourceInfo != null && - this.SourceInfo.Equals(input.SourceInfo)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(ConditionMetadata input) { + + if (!IsPropertyEqual(this.Module, input.Module)) { + return false; + } + + if (!IsPropertyEqual(this.SourceInfo, input.SourceInfo)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(ConditionMetadata input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/ConditionParamTypeRef.cs b/src/OpenFga.Sdk/Model/ConditionParamTypeRef.cs index 1b0a48d..201b1c6 100644 --- a/src/OpenFga.Sdk/Model/ConditionParamTypeRef.cs +++ b/src/OpenFga.Sdk/Model/ConditionParamTypeRef.cs @@ -79,7 +79,17 @@ public static ConditionParamTypeRef FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as ConditionParamTypeRef); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((ConditionParamTypeRef)input); } /// @@ -91,18 +101,60 @@ 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()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(ConditionParamTypeRef input) { + + if (!IsPropertyEqual(this.TypeName, input.TypeName)) { + return false; + } + + if (!IsCollectionPropertyEqual(this.GenericTypes, input.GenericTypes)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(ConditionParamTypeRef input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/ContextualTupleKeys.cs b/src/OpenFga.Sdk/Model/ContextualTupleKeys.cs index c912c04..b3d6355 100644 --- a/src/OpenFga.Sdk/Model/ContextualTupleKeys.cs +++ b/src/OpenFga.Sdk/Model/ContextualTupleKeys.cs @@ -74,7 +74,17 @@ public static ContextualTupleKeys FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as ContextualTupleKeys); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((ContextualTupleKeys)input); } /// @@ -86,14 +96,56 @@ public bool Equals(ContextualTupleKeys 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()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(ContextualTupleKeys input) { + + if (!IsCollectionPropertyEqual(this.TupleKeys, input.TupleKeys)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(ContextualTupleKeys input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/CreateStoreRequest.cs b/src/OpenFga.Sdk/Model/CreateStoreRequest.cs index 58c9cef..6fa079b 100644 --- a/src/OpenFga.Sdk/Model/CreateStoreRequest.cs +++ b/src/OpenFga.Sdk/Model/CreateStoreRequest.cs @@ -74,7 +74,17 @@ public static CreateStoreRequest FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as CreateStoreRequest); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((CreateStoreRequest)input); } /// @@ -86,13 +96,56 @@ public bool Equals(CreateStoreRequest input) { if (input == null) { return false; } - return - ( - this.Name == input.Name || - (this.Name != null && - this.Name.Equals(input.Name)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(CreateStoreRequest input) { + + if (!IsPropertyEqual(this.Name, input.Name)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(CreateStoreRequest input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/CreateStoreResponse.cs b/src/OpenFga.Sdk/Model/CreateStoreResponse.cs index b962a59..0ae6699 100644 --- a/src/OpenFga.Sdk/Model/CreateStoreResponse.cs +++ b/src/OpenFga.Sdk/Model/CreateStoreResponse.cs @@ -108,7 +108,17 @@ public static CreateStoreResponse FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as CreateStoreResponse); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((CreateStoreResponse)input); } /// @@ -120,28 +130,68 @@ public bool Equals(CreateStoreResponse input) { if (input == null) { return false; } - return - ( - this.Id == input.Id || - (this.Id != null && - this.Id.Equals(input.Id)) - ) && - ( - this.Name == input.Name || - (this.Name != null && - this.Name.Equals(input.Name)) - ) && - ( - this.CreatedAt == input.CreatedAt || - (this.CreatedAt != null && - this.CreatedAt.Equals(input.CreatedAt)) - ) && - ( - this.UpdatedAt == input.UpdatedAt || - (this.UpdatedAt != null && - this.UpdatedAt.Equals(input.UpdatedAt)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(CreateStoreResponse input) { + + if (!IsPropertyEqual(this.Id, input.Id)) { + return false; + } + + if (!IsPropertyEqual(this.Name, input.Name)) { + return false; + } + + if (!IsPropertyEqual(this.CreatedAt, input.CreatedAt)) { + return false; + } + + if (!IsPropertyEqual(this.UpdatedAt, input.UpdatedAt)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(CreateStoreResponse input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/Difference.cs b/src/OpenFga.Sdk/Model/Difference.cs index 1c35d3f..741d1f0 100644 --- a/src/OpenFga.Sdk/Model/Difference.cs +++ b/src/OpenFga.Sdk/Model/Difference.cs @@ -88,7 +88,17 @@ public static Difference FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as Difference); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((Difference)input); } /// @@ -100,18 +110,60 @@ public bool Equals(Difference input) { if (input == null) { return false; } - return - ( - this.Base == input.Base || - (this.Base != null && - this.Base.Equals(input.Base)) - ) && - ( - this.Subtract == input.Subtract || - (this.Subtract != null && - this.Subtract.Equals(input.Subtract)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(Difference input) { + + if (!IsPropertyEqual(this.Base, input.Base)) { + return false; + } + + if (!IsPropertyEqual(this.Subtract, input.Subtract)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(Difference input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/ExpandRequest.cs b/src/OpenFga.Sdk/Model/ExpandRequest.cs index 50c2fb6..8b2a5dd 100644 --- a/src/OpenFga.Sdk/Model/ExpandRequest.cs +++ b/src/OpenFga.Sdk/Model/ExpandRequest.cs @@ -103,7 +103,17 @@ public static ExpandRequest FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as ExpandRequest); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((ExpandRequest)input); } /// @@ -115,27 +125,68 @@ public bool Equals(ExpandRequest input) { if (input == null) { return false; } - return - ( - this.TupleKey == input.TupleKey || - (this.TupleKey != null && - this.TupleKey.Equals(input.TupleKey)) - ) && - ( - this.AuthorizationModelId == input.AuthorizationModelId || - (this.AuthorizationModelId != null && - this.AuthorizationModelId.Equals(input.AuthorizationModelId)) - ) && - ( - this.Consistency == input.Consistency || - this.Consistency.Equals(input.Consistency) - ) && - ( - this.ContextualTuples == input.ContextualTuples || - (this.ContextualTuples != null && - this.ContextualTuples.Equals(input.ContextualTuples)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(ExpandRequest input) { + + if (!IsPropertyEqual(this.TupleKey, input.TupleKey)) { + return false; + } + + if (!IsPropertyEqual(this.AuthorizationModelId, input.AuthorizationModelId)) { + return false; + } + + if (!IsPropertyEqual(this.Consistency, input.Consistency)) { + return false; + } + + if (!IsPropertyEqual(this.ContextualTuples, input.ContextualTuples)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(ExpandRequest input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/ExpandRequestTupleKey.cs b/src/OpenFga.Sdk/Model/ExpandRequestTupleKey.cs index 98e529b..7f1abb8 100644 --- a/src/OpenFga.Sdk/Model/ExpandRequestTupleKey.cs +++ b/src/OpenFga.Sdk/Model/ExpandRequestTupleKey.cs @@ -88,7 +88,17 @@ public static ExpandRequestTupleKey FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as ExpandRequestTupleKey); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((ExpandRequestTupleKey)input); } /// @@ -100,18 +110,60 @@ 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()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(ExpandRequestTupleKey input) { + + if (!IsPropertyEqual(this.Relation, input.Relation)) { + return false; + } + + if (!IsPropertyEqual(this.Object, input.Object)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(ExpandRequestTupleKey input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/ExpandResponse.cs b/src/OpenFga.Sdk/Model/ExpandResponse.cs index d77f2ea..2c8189c 100644 --- a/src/OpenFga.Sdk/Model/ExpandResponse.cs +++ b/src/OpenFga.Sdk/Model/ExpandResponse.cs @@ -70,7 +70,17 @@ public static ExpandResponse FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as ExpandResponse); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((ExpandResponse)input); } /// @@ -82,13 +92,56 @@ public bool Equals(ExpandResponse input) { if (input == null) { return false; } - return - ( - this.Tree == input.Tree || - (this.Tree != null && - this.Tree.Equals(input.Tree)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(ExpandResponse input) { + + if (!IsPropertyEqual(this.Tree, input.Tree)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(ExpandResponse input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/FgaObject.cs b/src/OpenFga.Sdk/Model/FgaObject.cs index 56aa2da..e37f446 100644 --- a/src/OpenFga.Sdk/Model/FgaObject.cs +++ b/src/OpenFga.Sdk/Model/FgaObject.cs @@ -88,7 +88,17 @@ public static FgaObject FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as FgaObject); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((FgaObject)input); } /// @@ -100,18 +110,60 @@ public bool Equals(FgaObject input) { if (input == null) { return false; } - return - ( - this.Type == input.Type || - (this.Type != null && - this.Type.Equals(input.Type)) - ) && - ( - this.Id == input.Id || - (this.Id != null && - this.Id.Equals(input.Id)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(FgaObject input) { + + if (!IsPropertyEqual(this.Type, input.Type)) { + return false; + } + + if (!IsPropertyEqual(this.Id, input.Id)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(FgaObject input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/ForbiddenResponse.cs b/src/OpenFga.Sdk/Model/ForbiddenResponse.cs index 1e5951e..d66b3a6 100644 --- a/src/OpenFga.Sdk/Model/ForbiddenResponse.cs +++ b/src/OpenFga.Sdk/Model/ForbiddenResponse.cs @@ -79,7 +79,17 @@ public static ForbiddenResponse FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as ForbiddenResponse); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((ForbiddenResponse)input); } /// @@ -91,17 +101,60 @@ public bool Equals(ForbiddenResponse input) { if (input == null) { return false; } - return - ( - this.Code == input.Code || - 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()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(ForbiddenResponse input) { + + if (!IsPropertyEqual(this.Code, input.Code)) { + return false; + } + + if (!IsPropertyEqual(this.Message, input.Message)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(ForbiddenResponse input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/GetStoreResponse.cs b/src/OpenFga.Sdk/Model/GetStoreResponse.cs index 34af149..5e6bee1 100644 --- a/src/OpenFga.Sdk/Model/GetStoreResponse.cs +++ b/src/OpenFga.Sdk/Model/GetStoreResponse.cs @@ -118,7 +118,17 @@ public static GetStoreResponse FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as GetStoreResponse); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((GetStoreResponse)input); } /// @@ -130,33 +140,72 @@ public bool Equals(GetStoreResponse input) { if (input == null) { return false; } - return - ( - this.Id == input.Id || - (this.Id != null && - this.Id.Equals(input.Id)) - ) && - ( - this.Name == input.Name || - (this.Name != null && - this.Name.Equals(input.Name)) - ) && - ( - this.CreatedAt == input.CreatedAt || - (this.CreatedAt != null && - this.CreatedAt.Equals(input.CreatedAt)) - ) && - ( - 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()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(GetStoreResponse input) { + + if (!IsPropertyEqual(this.Id, input.Id)) { + return false; + } + + if (!IsPropertyEqual(this.Name, input.Name)) { + return false; + } + + if (!IsPropertyEqual(this.CreatedAt, input.CreatedAt)) { + return false; + } + + if (!IsPropertyEqual(this.UpdatedAt, input.UpdatedAt)) { + return false; + } + + if (!IsPropertyEqual(this.DeletedAt, input.DeletedAt)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(GetStoreResponse input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/InternalErrorMessageResponse.cs b/src/OpenFga.Sdk/Model/InternalErrorMessageResponse.cs index d385be5..88f3001 100644 --- a/src/OpenFga.Sdk/Model/InternalErrorMessageResponse.cs +++ b/src/OpenFga.Sdk/Model/InternalErrorMessageResponse.cs @@ -79,7 +79,17 @@ public static InternalErrorMessageResponse FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as InternalErrorMessageResponse); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((InternalErrorMessageResponse)input); } /// @@ -91,17 +101,60 @@ public bool Equals(InternalErrorMessageResponse input) { if (input == null) { return false; } - return - ( - this.Code == input.Code || - 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()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(InternalErrorMessageResponse input) { + + if (!IsPropertyEqual(this.Code, input.Code)) { + return false; + } + + if (!IsPropertyEqual(this.Message, input.Message)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(InternalErrorMessageResponse input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/Leaf.cs b/src/OpenFga.Sdk/Model/Leaf.cs index cb84c45..dc9f373 100644 --- a/src/OpenFga.Sdk/Model/Leaf.cs +++ b/src/OpenFga.Sdk/Model/Leaf.cs @@ -90,7 +90,17 @@ public static Leaf FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as Leaf); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((Leaf)input); } /// @@ -102,23 +112,64 @@ public bool Equals(Leaf input) { if (input == null) { return false; } - return - ( - this.Users == input.Users || - (this.Users != null && - this.Users.Equals(input.Users)) - ) && - ( - this.Computed == input.Computed || - (this.Computed != null && - this.Computed.Equals(input.Computed)) - ) && - ( - this.TupleToUserset == input.TupleToUserset || - (this.TupleToUserset != null && - this.TupleToUserset.Equals(input.TupleToUserset)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(Leaf input) { + + if (!IsPropertyEqual(this.Users, input.Users)) { + return false; + } + + if (!IsPropertyEqual(this.Computed, input.Computed)) { + return false; + } + + if (!IsPropertyEqual(this.TupleToUserset, input.TupleToUserset)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(Leaf input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/ListObjectsRequest.cs b/src/OpenFga.Sdk/Model/ListObjectsRequest.cs index a873bcb..37648ec 100644 --- a/src/OpenFga.Sdk/Model/ListObjectsRequest.cs +++ b/src/OpenFga.Sdk/Model/ListObjectsRequest.cs @@ -142,7 +142,17 @@ public static ListObjectsRequest FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as ListObjectsRequest); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((ListObjectsRequest)input); } /// @@ -154,42 +164,80 @@ public bool Equals(ListObjectsRequest input) { if (input == null) { return false; } - return - ( - this.AuthorizationModelId == input.AuthorizationModelId || - (this.AuthorizationModelId != null && - this.AuthorizationModelId.Equals(input.AuthorizationModelId)) - ) && - ( - this.Type == input.Type || - (this.Type != null && - this.Type.Equals(input.Type)) - ) && - ( - 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.ContextualTuples == input.ContextualTuples || - (this.ContextualTuples != null && - this.ContextualTuples.Equals(input.ContextualTuples)) - ) && - ( - this.Context == input.Context || - (this.Context != null && - this.Context.Equals(input.Context)) - ) && - ( - this.Consistency == input.Consistency || - this.Consistency.Equals(input.Consistency) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(ListObjectsRequest input) { + + if (!IsPropertyEqual(this.AuthorizationModelId, input.AuthorizationModelId)) { + return false; + } + + if (!IsPropertyEqual(this.Type, input.Type)) { + return false; + } + + if (!IsPropertyEqual(this.Relation, input.Relation)) { + return false; + } + + if (!IsPropertyEqual(this.User, input.User)) { + return false; + } + + if (!IsPropertyEqual(this.ContextualTuples, input.ContextualTuples)) { + return false; + } + + if (!IsPropertyEqual(this.Context, input.Context)) { + return false; + } + + if (!IsPropertyEqual(this.Consistency, input.Consistency)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(ListObjectsRequest input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/ListObjectsResponse.cs b/src/OpenFga.Sdk/Model/ListObjectsResponse.cs index f2ab927..7d26313 100644 --- a/src/OpenFga.Sdk/Model/ListObjectsResponse.cs +++ b/src/OpenFga.Sdk/Model/ListObjectsResponse.cs @@ -74,7 +74,17 @@ public static ListObjectsResponse FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as ListObjectsResponse); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((ListObjectsResponse)input); } /// @@ -86,14 +96,56 @@ public bool Equals(ListObjectsResponse input) { if (input == null) { return false; } - return - ( - this.Objects == input.Objects || - this.Objects != null && - input.Objects != null && - this.Objects.SequenceEqual(input.Objects) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(ListObjectsResponse input) { + + if (!IsCollectionPropertyEqual(this.Objects, input.Objects)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(ListObjectsResponse input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/ListStoresResponse.cs b/src/OpenFga.Sdk/Model/ListStoresResponse.cs index 74d46b3..4493783 100644 --- a/src/OpenFga.Sdk/Model/ListStoresResponse.cs +++ b/src/OpenFga.Sdk/Model/ListStoresResponse.cs @@ -89,7 +89,17 @@ public static ListStoresResponse FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as ListStoresResponse); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((ListStoresResponse)input); } /// @@ -101,19 +111,60 @@ public bool Equals(ListStoresResponse input) { if (input == null) { return false; } - return - ( - this.Stores == input.Stores || - this.Stores != null && - input.Stores != null && - this.Stores.SequenceEqual(input.Stores) - ) && - ( - this.ContinuationToken == input.ContinuationToken || - (this.ContinuationToken != null && - this.ContinuationToken.Equals(input.ContinuationToken)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(ListStoresResponse input) { + + if (!IsCollectionPropertyEqual(this.Stores, input.Stores)) { + return false; + } + + if (!IsPropertyEqual(this.ContinuationToken, input.ContinuationToken)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(ListStoresResponse input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/ListUsersRequest.cs b/src/OpenFga.Sdk/Model/ListUsersRequest.cs index 5c144b3..32f5d00 100644 --- a/src/OpenFga.Sdk/Model/ListUsersRequest.cs +++ b/src/OpenFga.Sdk/Model/ListUsersRequest.cs @@ -143,7 +143,17 @@ public static ListUsersRequest FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as ListUsersRequest); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((ListUsersRequest)input); } /// @@ -155,44 +165,80 @@ public bool Equals(ListUsersRequest input) { if (input == null) { return false; } - return - ( - this.AuthorizationModelId == input.AuthorizationModelId || - (this.AuthorizationModelId != null && - this.AuthorizationModelId.Equals(input.AuthorizationModelId)) - ) && - ( - 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.UserFilters == input.UserFilters || - this.UserFilters != null && - input.UserFilters != null && - this.UserFilters.SequenceEqual(input.UserFilters) - ) && - ( - this.ContextualTuples == input.ContextualTuples || - this.ContextualTuples != null && - input.ContextualTuples != null && - this.ContextualTuples.SequenceEqual(input.ContextualTuples) - ) && - ( - this.Context == input.Context || - (this.Context != null && - this.Context.Equals(input.Context)) - ) && - ( - this.Consistency == input.Consistency || - this.Consistency.Equals(input.Consistency) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(ListUsersRequest input) { + + if (!IsPropertyEqual(this.AuthorizationModelId, input.AuthorizationModelId)) { + return false; + } + + if (!IsPropertyEqual(this.Object, input.Object)) { + return false; + } + + if (!IsPropertyEqual(this.Relation, input.Relation)) { + return false; + } + + if (!IsCollectionPropertyEqual(this.UserFilters, input.UserFilters)) { + return false; + } + + if (!IsCollectionPropertyEqual(this.ContextualTuples, input.ContextualTuples)) { + return false; + } + + if (!IsPropertyEqual(this.Context, input.Context)) { + return false; + } + + if (!IsPropertyEqual(this.Consistency, input.Consistency)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(ListUsersRequest input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/ListUsersResponse.cs b/src/OpenFga.Sdk/Model/ListUsersResponse.cs index ec0cf40..681f574 100644 --- a/src/OpenFga.Sdk/Model/ListUsersResponse.cs +++ b/src/OpenFga.Sdk/Model/ListUsersResponse.cs @@ -74,7 +74,17 @@ public static ListUsersResponse FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as ListUsersResponse); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((ListUsersResponse)input); } /// @@ -86,14 +96,56 @@ public bool Equals(ListUsersResponse input) { if (input == null) { return false; } - return - ( - this.Users == input.Users || - this.Users != null && - input.Users != null && - this.Users.SequenceEqual(input.Users) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(ListUsersResponse input) { + + if (!IsCollectionPropertyEqual(this.Users, input.Users)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(ListUsersResponse input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/Metadata.cs b/src/OpenFga.Sdk/Model/Metadata.cs index bb704e2..5832b1f 100644 --- a/src/OpenFga.Sdk/Model/Metadata.cs +++ b/src/OpenFga.Sdk/Model/Metadata.cs @@ -90,7 +90,17 @@ public static Metadata FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as Metadata); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((Metadata)input); } /// @@ -102,24 +112,64 @@ public bool Equals(Metadata input) { if (input == null) { return false; } - return - ( - this.Relations == input.Relations || - this.Relations != null && - input.Relations != null && - this.Relations.SequenceEqual(input.Relations) - ) && - ( - this.Module == input.Module || - (this.Module != null && - this.Module.Equals(input.Module)) - ) && - ( - this.SourceInfo == input.SourceInfo || - (this.SourceInfo != null && - this.SourceInfo.Equals(input.SourceInfo)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(Metadata input) { + + if (!IsCollectionPropertyEqual(this.Relations, input.Relations)) { + return false; + } + + if (!IsPropertyEqual(this.Module, input.Module)) { + return false; + } + + if (!IsPropertyEqual(this.SourceInfo, input.SourceInfo)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(Metadata input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/Node.cs b/src/OpenFga.Sdk/Model/Node.cs index be296f9..670e3f0 100644 --- a/src/OpenFga.Sdk/Model/Node.cs +++ b/src/OpenFga.Sdk/Model/Node.cs @@ -114,7 +114,17 @@ public static Node FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as Node); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((Node)input); } /// @@ -126,33 +136,72 @@ public bool Equals(Node input) { if (input == null) { return false; } - return - ( - this.Name == input.Name || - (this.Name != null && - this.Name.Equals(input.Name)) - ) && - ( - this.Leaf == input.Leaf || - (this.Leaf != null && - this.Leaf.Equals(input.Leaf)) - ) && - ( - this.Difference == input.Difference || - (this.Difference != null && - this.Difference.Equals(input.Difference)) - ) && - ( - this.Union == input.Union || - (this.Union != null && - this.Union.Equals(input.Union)) - ) && - ( - this.Intersection == input.Intersection || - (this.Intersection != null && - this.Intersection.Equals(input.Intersection)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(Node input) { + + if (!IsPropertyEqual(this.Name, input.Name)) { + return false; + } + + if (!IsPropertyEqual(this.Leaf, input.Leaf)) { + return false; + } + + if (!IsPropertyEqual(this.Difference, input.Difference)) { + return false; + } + + if (!IsPropertyEqual(this.Union, input.Union)) { + return false; + } + + if (!IsPropertyEqual(this.Intersection, input.Intersection)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(Node input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/Nodes.cs b/src/OpenFga.Sdk/Model/Nodes.cs index 9b798d1..bedfdf6 100644 --- a/src/OpenFga.Sdk/Model/Nodes.cs +++ b/src/OpenFga.Sdk/Model/Nodes.cs @@ -74,7 +74,17 @@ public static Nodes FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as Nodes); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((Nodes)input); } /// @@ -86,14 +96,56 @@ public bool Equals(Nodes input) { if (input == null) { return false; } - return - ( - this._Nodes == input._Nodes || - this._Nodes != null && - input._Nodes != null && - this._Nodes.SequenceEqual(input._Nodes) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(Nodes input) { + + if (!IsCollectionPropertyEqual(this._Nodes, input._Nodes)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(Nodes input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/ObjectRelation.cs b/src/OpenFga.Sdk/Model/ObjectRelation.cs index 49e10a4..25a840c 100644 --- a/src/OpenFga.Sdk/Model/ObjectRelation.cs +++ b/src/OpenFga.Sdk/Model/ObjectRelation.cs @@ -80,7 +80,17 @@ public static ObjectRelation FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as ObjectRelation); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((ObjectRelation)input); } /// @@ -92,18 +102,60 @@ public bool Equals(ObjectRelation 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.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(ObjectRelation input) { + + if (!IsPropertyEqual(this.Object, input.Object)) { + return false; + } + + if (!IsPropertyEqual(this.Relation, input.Relation)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(ObjectRelation input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/PathUnknownErrorMessageResponse.cs b/src/OpenFga.Sdk/Model/PathUnknownErrorMessageResponse.cs index 4b5aae0..934f310 100644 --- a/src/OpenFga.Sdk/Model/PathUnknownErrorMessageResponse.cs +++ b/src/OpenFga.Sdk/Model/PathUnknownErrorMessageResponse.cs @@ -79,7 +79,17 @@ public static PathUnknownErrorMessageResponse FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as PathUnknownErrorMessageResponse); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((PathUnknownErrorMessageResponse)input); } /// @@ -91,17 +101,60 @@ public bool Equals(PathUnknownErrorMessageResponse input) { if (input == null) { return false; } - return - ( - this.Code == input.Code || - 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()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(PathUnknownErrorMessageResponse input) { + + if (!IsPropertyEqual(this.Code, input.Code)) { + return false; + } + + if (!IsPropertyEqual(this.Message, input.Message)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(PathUnknownErrorMessageResponse input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/ReadAssertionsResponse.cs b/src/OpenFga.Sdk/Model/ReadAssertionsResponse.cs index 9da68c5..132bf58 100644 --- a/src/OpenFga.Sdk/Model/ReadAssertionsResponse.cs +++ b/src/OpenFga.Sdk/Model/ReadAssertionsResponse.cs @@ -84,7 +84,17 @@ public static ReadAssertionsResponse FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as ReadAssertionsResponse); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((ReadAssertionsResponse)input); } /// @@ -96,19 +106,60 @@ public bool Equals(ReadAssertionsResponse input) { if (input == null) { return false; } - return - ( - this.AuthorizationModelId == input.AuthorizationModelId || - (this.AuthorizationModelId != null && - this.AuthorizationModelId.Equals(input.AuthorizationModelId)) - ) && - ( - this.Assertions == input.Assertions || - this.Assertions != null && - input.Assertions != null && - this.Assertions.SequenceEqual(input.Assertions) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(ReadAssertionsResponse input) { + + if (!IsPropertyEqual(this.AuthorizationModelId, input.AuthorizationModelId)) { + return false; + } + + if (!IsCollectionPropertyEqual(this.Assertions, input.Assertions)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(ReadAssertionsResponse input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/ReadAuthorizationModelResponse.cs b/src/OpenFga.Sdk/Model/ReadAuthorizationModelResponse.cs index 2b637a9..c8d0e60 100644 --- a/src/OpenFga.Sdk/Model/ReadAuthorizationModelResponse.cs +++ b/src/OpenFga.Sdk/Model/ReadAuthorizationModelResponse.cs @@ -70,7 +70,17 @@ public static ReadAuthorizationModelResponse FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as ReadAuthorizationModelResponse); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((ReadAuthorizationModelResponse)input); } /// @@ -82,13 +92,56 @@ public bool Equals(ReadAuthorizationModelResponse input) { if (input == null) { return false; } - return - ( - this.AuthorizationModel == input.AuthorizationModel || - (this.AuthorizationModel != null && - this.AuthorizationModel.Equals(input.AuthorizationModel)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(ReadAuthorizationModelResponse input) { + + if (!IsPropertyEqual(this.AuthorizationModel, input.AuthorizationModel)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(ReadAuthorizationModelResponse input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/ReadAuthorizationModelsResponse.cs b/src/OpenFga.Sdk/Model/ReadAuthorizationModelsResponse.cs index 2ac4991..f1d3c0f 100644 --- a/src/OpenFga.Sdk/Model/ReadAuthorizationModelsResponse.cs +++ b/src/OpenFga.Sdk/Model/ReadAuthorizationModelsResponse.cs @@ -85,7 +85,17 @@ public static ReadAuthorizationModelsResponse FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as ReadAuthorizationModelsResponse); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((ReadAuthorizationModelsResponse)input); } /// @@ -97,19 +107,60 @@ public bool Equals(ReadAuthorizationModelsResponse input) { if (input == null) { return false; } - return - ( - this.AuthorizationModels == input.AuthorizationModels || - this.AuthorizationModels != null && - input.AuthorizationModels != null && - this.AuthorizationModels.SequenceEqual(input.AuthorizationModels) - ) && - ( - this.ContinuationToken == input.ContinuationToken || - (this.ContinuationToken != null && - this.ContinuationToken.Equals(input.ContinuationToken)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(ReadAuthorizationModelsResponse input) { + + if (!IsCollectionPropertyEqual(this.AuthorizationModels, input.AuthorizationModels)) { + return false; + } + + if (!IsPropertyEqual(this.ContinuationToken, input.ContinuationToken)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(ReadAuthorizationModelsResponse input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/ReadChangesResponse.cs b/src/OpenFga.Sdk/Model/ReadChangesResponse.cs index db0fe79..72ed9c3 100644 --- a/src/OpenFga.Sdk/Model/ReadChangesResponse.cs +++ b/src/OpenFga.Sdk/Model/ReadChangesResponse.cs @@ -85,7 +85,17 @@ public static ReadChangesResponse FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as ReadChangesResponse); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((ReadChangesResponse)input); } /// @@ -97,19 +107,60 @@ public bool Equals(ReadChangesResponse input) { if (input == null) { return false; } - return - ( - this.Changes == input.Changes || - this.Changes != null && - input.Changes != null && - this.Changes.SequenceEqual(input.Changes) - ) && - ( - this.ContinuationToken == input.ContinuationToken || - (this.ContinuationToken != null && - this.ContinuationToken.Equals(input.ContinuationToken)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(ReadChangesResponse input) { + + if (!IsCollectionPropertyEqual(this.Changes, input.Changes)) { + return false; + } + + if (!IsPropertyEqual(this.ContinuationToken, input.ContinuationToken)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(ReadChangesResponse input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/ReadRequest.cs b/src/OpenFga.Sdk/Model/ReadRequest.cs index 39dbb2d..6d226b8 100644 --- a/src/OpenFga.Sdk/Model/ReadRequest.cs +++ b/src/OpenFga.Sdk/Model/ReadRequest.cs @@ -99,7 +99,17 @@ public static ReadRequest FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as ReadRequest); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((ReadRequest)input); } /// @@ -111,26 +121,68 @@ public bool Equals(ReadRequest input) { if (input == null) { return false; } - return - ( - this.TupleKey == input.TupleKey || - (this.TupleKey != null && - this.TupleKey.Equals(input.TupleKey)) - ) && - ( - this.PageSize == input.PageSize || - this.PageSize.Equals(input.PageSize) - ) && - ( - this.ContinuationToken == input.ContinuationToken || - (this.ContinuationToken != null && - this.ContinuationToken.Equals(input.ContinuationToken)) - ) && - ( - this.Consistency == input.Consistency || - this.Consistency.Equals(input.Consistency) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(ReadRequest input) { + + if (!IsPropertyEqual(this.TupleKey, input.TupleKey)) { + return false; + } + + if (!IsPropertyEqual(this.PageSize, input.PageSize)) { + return false; + } + + if (!IsPropertyEqual(this.ContinuationToken, input.ContinuationToken)) { + return false; + } + + if (!IsPropertyEqual(this.Consistency, input.Consistency)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(ReadRequest input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/ReadRequestTupleKey.cs b/src/OpenFga.Sdk/Model/ReadRequestTupleKey.cs index 5f4c3b9..1391bd4 100644 --- a/src/OpenFga.Sdk/Model/ReadRequestTupleKey.cs +++ b/src/OpenFga.Sdk/Model/ReadRequestTupleKey.cs @@ -90,7 +90,17 @@ public static ReadRequestTupleKey FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as ReadRequestTupleKey); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((ReadRequestTupleKey)input); } /// @@ -102,23 +112,64 @@ 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()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(ReadRequestTupleKey input) { + + if (!IsPropertyEqual(this.User, input.User)) { + return false; + } + + if (!IsPropertyEqual(this.Relation, input.Relation)) { + return false; + } + + if (!IsPropertyEqual(this.Object, input.Object)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(ReadRequestTupleKey input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/ReadResponse.cs b/src/OpenFga.Sdk/Model/ReadResponse.cs index 434a39d..75c53cf 100644 --- a/src/OpenFga.Sdk/Model/ReadResponse.cs +++ b/src/OpenFga.Sdk/Model/ReadResponse.cs @@ -89,7 +89,17 @@ public static ReadResponse FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as ReadResponse); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((ReadResponse)input); } /// @@ -101,19 +111,60 @@ public bool Equals(ReadResponse input) { if (input == null) { return false; } - return - ( - this.Tuples == input.Tuples || - this.Tuples != null && - input.Tuples != null && - this.Tuples.SequenceEqual(input.Tuples) - ) && - ( - this.ContinuationToken == input.ContinuationToken || - (this.ContinuationToken != null && - this.ContinuationToken.Equals(input.ContinuationToken)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(ReadResponse input) { + + if (!IsCollectionPropertyEqual(this.Tuples, input.Tuples)) { + return false; + } + + if (!IsPropertyEqual(this.ContinuationToken, input.ContinuationToken)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(ReadResponse input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/RelationMetadata.cs b/src/OpenFga.Sdk/Model/RelationMetadata.cs index 84adaf0..a4233c1 100644 --- a/src/OpenFga.Sdk/Model/RelationMetadata.cs +++ b/src/OpenFga.Sdk/Model/RelationMetadata.cs @@ -90,7 +90,17 @@ public static RelationMetadata FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as RelationMetadata); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((RelationMetadata)input); } /// @@ -102,24 +112,64 @@ public bool Equals(RelationMetadata input) { if (input == null) { return false; } - return - ( - this.DirectlyRelatedUserTypes == input.DirectlyRelatedUserTypes || - this.DirectlyRelatedUserTypes != null && - input.DirectlyRelatedUserTypes != null && - this.DirectlyRelatedUserTypes.SequenceEqual(input.DirectlyRelatedUserTypes) - ) && - ( - this.Module == input.Module || - (this.Module != null && - this.Module.Equals(input.Module)) - ) && - ( - this.SourceInfo == input.SourceInfo || - (this.SourceInfo != null && - this.SourceInfo.Equals(input.SourceInfo)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(RelationMetadata input) { + + if (!IsCollectionPropertyEqual(this.DirectlyRelatedUserTypes, input.DirectlyRelatedUserTypes)) { + return false; + } + + if (!IsPropertyEqual(this.Module, input.Module)) { + return false; + } + + if (!IsPropertyEqual(this.SourceInfo, input.SourceInfo)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(RelationMetadata input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/RelationReference.cs b/src/OpenFga.Sdk/Model/RelationReference.cs index 09ff8db..2f8b013 100644 --- a/src/OpenFga.Sdk/Model/RelationReference.cs +++ b/src/OpenFga.Sdk/Model/RelationReference.cs @@ -105,7 +105,17 @@ public static RelationReference FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as RelationReference); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((RelationReference)input); } /// @@ -117,28 +127,68 @@ public bool Equals(RelationReference input) { if (input == null) { return false; } - return - ( - this.Type == input.Type || - (this.Type != null && - this.Type.Equals(input.Type)) - ) && - ( - this.Relation == input.Relation || - (this.Relation != null && - this.Relation.Equals(input.Relation)) - ) && - ( - 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()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(RelationReference input) { + + if (!IsPropertyEqual(this.Type, input.Type)) { + return false; + } + + if (!IsPropertyEqual(this.Relation, input.Relation)) { + return false; + } + + if (!IsPropertyEqual(this.Wildcard, input.Wildcard)) { + return false; + } + + if (!IsPropertyEqual(this.Condition, input.Condition)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(RelationReference input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/RelationshipCondition.cs b/src/OpenFga.Sdk/Model/RelationshipCondition.cs index c51b275..4555d38 100644 --- a/src/OpenFga.Sdk/Model/RelationshipCondition.cs +++ b/src/OpenFga.Sdk/Model/RelationshipCondition.cs @@ -86,7 +86,17 @@ public static RelationshipCondition FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as RelationshipCondition); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((RelationshipCondition)input); } /// @@ -98,18 +108,60 @@ 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()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(RelationshipCondition input) { + + if (!IsPropertyEqual(this.Name, input.Name)) { + return false; + } + + if (!IsPropertyEqual(this.Context, input.Context)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(RelationshipCondition input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/SourceInfo.cs b/src/OpenFga.Sdk/Model/SourceInfo.cs index 31f1133..7681d77 100644 --- a/src/OpenFga.Sdk/Model/SourceInfo.cs +++ b/src/OpenFga.Sdk/Model/SourceInfo.cs @@ -70,7 +70,17 @@ public static SourceInfo FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as SourceInfo); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((SourceInfo)input); } /// @@ -82,13 +92,56 @@ public bool Equals(SourceInfo input) { if (input == null) { return false; } - return - ( - this.File == input.File || - (this.File != null && - this.File.Equals(input.File)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(SourceInfo input) { + + if (!IsPropertyEqual(this.File, input.File)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(SourceInfo input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/Status.cs b/src/OpenFga.Sdk/Model/Status.cs index 2ee9896..f31b80f 100644 --- a/src/OpenFga.Sdk/Model/Status.cs +++ b/src/OpenFga.Sdk/Model/Status.cs @@ -90,7 +90,17 @@ public static Status FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as Status); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((Status)input); } /// @@ -102,23 +112,64 @@ public bool Equals(Status input) { if (input == null) { return false; } - return - ( - this.Code == input.Code || - this.Code.Equals(input.Code) - ) && - ( - this.Message == input.Message || - (this.Message != null && - this.Message.Equals(input.Message)) - ) && - ( - this.Details == input.Details || - this.Details != null && - input.Details != null && - this.Details.SequenceEqual(input.Details) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(Status input) { + + if (!IsPropertyEqual(this.Code, input.Code)) { + return false; + } + + if (!IsPropertyEqual(this.Message, input.Message)) { + return false; + } + + if (!IsCollectionPropertyEqual(this.Details, input.Details)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(Status input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/Store.cs b/src/OpenFga.Sdk/Model/Store.cs index 7b7e4fa..f1d9a13 100644 --- a/src/OpenFga.Sdk/Model/Store.cs +++ b/src/OpenFga.Sdk/Model/Store.cs @@ -118,7 +118,17 @@ public static Store FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as Store); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((Store)input); } /// @@ -130,33 +140,72 @@ public bool Equals(Store input) { if (input == null) { return false; } - return - ( - this.Id == input.Id || - (this.Id != null && - this.Id.Equals(input.Id)) - ) && - ( - this.Name == input.Name || - (this.Name != null && - this.Name.Equals(input.Name)) - ) && - ( - this.CreatedAt == input.CreatedAt || - (this.CreatedAt != null && - this.CreatedAt.Equals(input.CreatedAt)) - ) && - ( - 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()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(Store input) { + + if (!IsPropertyEqual(this.Id, input.Id)) { + return false; + } + + if (!IsPropertyEqual(this.Name, input.Name)) { + return false; + } + + if (!IsPropertyEqual(this.CreatedAt, input.CreatedAt)) { + return false; + } + + if (!IsPropertyEqual(this.UpdatedAt, input.UpdatedAt)) { + return false; + } + + if (!IsPropertyEqual(this.DeletedAt, input.DeletedAt)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(Store input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/Tuple.cs b/src/OpenFga.Sdk/Model/Tuple.cs index baefe12..bb4e6ae 100644 --- a/src/OpenFga.Sdk/Model/Tuple.cs +++ b/src/OpenFga.Sdk/Model/Tuple.cs @@ -84,7 +84,17 @@ public static Tuple FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as Tuple); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((Tuple)input); } /// @@ -96,18 +106,60 @@ public bool Equals(Tuple input) { if (input == null) { return false; } - return - ( - this.Key == input.Key || - (this.Key != null && - this.Key.Equals(input.Key)) - ) && - ( - this.Timestamp == input.Timestamp || - (this.Timestamp != null && - this.Timestamp.Equals(input.Timestamp)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(Tuple input) { + + if (!IsPropertyEqual(this.Key, input.Key)) { + return false; + } + + if (!IsPropertyEqual(this.Timestamp, input.Timestamp)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(Tuple input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/TupleChange.cs b/src/OpenFga.Sdk/Model/TupleChange.cs index 8c62dc0..7c93c92 100644 --- a/src/OpenFga.Sdk/Model/TupleChange.cs +++ b/src/OpenFga.Sdk/Model/TupleChange.cs @@ -93,7 +93,17 @@ public static TupleChange FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as TupleChange); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((TupleChange)input); } /// @@ -105,22 +115,64 @@ public bool Equals(TupleChange input) { if (input == null) { return false; } - return - ( - this.TupleKey == input.TupleKey || - (this.TupleKey != null && - this.TupleKey.Equals(input.TupleKey)) - ) && - ( - this.Operation == input.Operation || - this.Operation.Equals(input.Operation) - ) && - ( - this.Timestamp == input.Timestamp || - (this.Timestamp != null && - this.Timestamp.Equals(input.Timestamp)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(TupleChange input) { + + if (!IsPropertyEqual(this.TupleKey, input.TupleKey)) { + return false; + } + + if (!IsPropertyEqual(this.Operation, input.Operation)) { + return false; + } + + if (!IsPropertyEqual(this.Timestamp, input.Timestamp)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(TupleChange input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/TupleKey.cs b/src/OpenFga.Sdk/Model/TupleKey.cs index aa55142..da56ffb 100644 --- a/src/OpenFga.Sdk/Model/TupleKey.cs +++ b/src/OpenFga.Sdk/Model/TupleKey.cs @@ -112,7 +112,17 @@ public static TupleKey FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as TupleKey); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((TupleKey)input); } /// @@ -124,28 +134,68 @@ public bool Equals(TupleKey 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.Condition == input.Condition || - (this.Condition != null && - this.Condition.Equals(input.Condition)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(TupleKey input) { + + if (!IsPropertyEqual(this.User, input.User)) { + return false; + } + + if (!IsPropertyEqual(this.Relation, input.Relation)) { + return false; + } + + if (!IsPropertyEqual(this.Object, input.Object)) { + return false; + } + + if (!IsPropertyEqual(this.Condition, input.Condition)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(TupleKey input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/TupleKeyWithoutCondition.cs b/src/OpenFga.Sdk/Model/TupleKeyWithoutCondition.cs index 743b2e6..7176610 100644 --- a/src/OpenFga.Sdk/Model/TupleKeyWithoutCondition.cs +++ b/src/OpenFga.Sdk/Model/TupleKeyWithoutCondition.cs @@ -102,7 +102,17 @@ public static TupleKeyWithoutCondition FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as TupleKeyWithoutCondition); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((TupleKeyWithoutCondition)input); } /// @@ -114,23 +124,64 @@ 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()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(TupleKeyWithoutCondition input) { + + if (!IsPropertyEqual(this.User, input.User)) { + return false; + } + + if (!IsPropertyEqual(this.Relation, input.Relation)) { + return false; + } + + if (!IsPropertyEqual(this.Object, input.Object)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(TupleKeyWithoutCondition input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/TupleToUserset.cs b/src/OpenFga.Sdk/Model/TupleToUserset.cs index 01cc9e9..dbd6779 100644 --- a/src/OpenFga.Sdk/Model/TupleToUserset.cs +++ b/src/OpenFga.Sdk/Model/TupleToUserset.cs @@ -88,7 +88,17 @@ public static TupleToUserset FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as TupleToUserset); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((TupleToUserset)input); } /// @@ -100,18 +110,60 @@ public bool Equals(TupleToUserset input) { if (input == null) { return false; } - return - ( - this.Tupleset == input.Tupleset || - (this.Tupleset != null && - this.Tupleset.Equals(input.Tupleset)) - ) && - ( - this.ComputedUserset == input.ComputedUserset || - (this.ComputedUserset != null && - this.ComputedUserset.Equals(input.ComputedUserset)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(TupleToUserset input) { + + if (!IsPropertyEqual(this.Tupleset, input.Tupleset)) { + return false; + } + + if (!IsPropertyEqual(this.ComputedUserset, input.ComputedUserset)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(TupleToUserset input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/TypeDefinition.cs b/src/OpenFga.Sdk/Model/TypeDefinition.cs index 4d0a2a0..e2eb4c0 100644 --- a/src/OpenFga.Sdk/Model/TypeDefinition.cs +++ b/src/OpenFga.Sdk/Model/TypeDefinition.cs @@ -94,7 +94,17 @@ public static TypeDefinition FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as TypeDefinition); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((TypeDefinition)input); } /// @@ -106,24 +116,64 @@ public bool Equals(TypeDefinition input) { if (input == null) { return false; } - return - ( - this.Type == input.Type || - (this.Type != null && - this.Type.Equals(input.Type)) - ) && - ( - this.Relations == input.Relations || - this.Relations != null && - input.Relations != null && - this.Relations.SequenceEqual(input.Relations) - ) && - ( - this.Metadata == input.Metadata || - (this.Metadata != null && - this.Metadata.Equals(input.Metadata)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(TypeDefinition input) { + + if (!IsPropertyEqual(this.Type, input.Type)) { + return false; + } + + if (!IsCollectionPropertyEqual(this.Relations, input.Relations)) { + return false; + } + + if (!IsPropertyEqual(this.Metadata, input.Metadata)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(TypeDefinition input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/TypedWildcard.cs b/src/OpenFga.Sdk/Model/TypedWildcard.cs index a7d20c1..1643788 100644 --- a/src/OpenFga.Sdk/Model/TypedWildcard.cs +++ b/src/OpenFga.Sdk/Model/TypedWildcard.cs @@ -74,7 +74,17 @@ public static TypedWildcard FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as TypedWildcard); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((TypedWildcard)input); } /// @@ -86,13 +96,56 @@ public bool Equals(TypedWildcard input) { if (input == null) { return false; } - return - ( - this.Type == input.Type || - (this.Type != null && - this.Type.Equals(input.Type)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(TypedWildcard input) { + + if (!IsPropertyEqual(this.Type, input.Type)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(TypedWildcard input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/UnauthenticatedResponse.cs b/src/OpenFga.Sdk/Model/UnauthenticatedResponse.cs index 03bae05..0175589 100644 --- a/src/OpenFga.Sdk/Model/UnauthenticatedResponse.cs +++ b/src/OpenFga.Sdk/Model/UnauthenticatedResponse.cs @@ -79,7 +79,17 @@ public static UnauthenticatedResponse FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as UnauthenticatedResponse); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((UnauthenticatedResponse)input); } /// @@ -91,17 +101,60 @@ public bool Equals(UnauthenticatedResponse input) { if (input == null) { return false; } - return - ( - this.Code == input.Code || - 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()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(UnauthenticatedResponse input) { + + if (!IsPropertyEqual(this.Code, input.Code)) { + return false; + } + + if (!IsPropertyEqual(this.Message, input.Message)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(UnauthenticatedResponse input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/UnprocessableContentMessageResponse.cs b/src/OpenFga.Sdk/Model/UnprocessableContentMessageResponse.cs index 3c21c0e..60118d4 100644 --- a/src/OpenFga.Sdk/Model/UnprocessableContentMessageResponse.cs +++ b/src/OpenFga.Sdk/Model/UnprocessableContentMessageResponse.cs @@ -79,7 +79,17 @@ public static UnprocessableContentMessageResponse FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as UnprocessableContentMessageResponse); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((UnprocessableContentMessageResponse)input); } /// @@ -91,17 +101,60 @@ public bool Equals(UnprocessableContentMessageResponse input) { if (input == null) { return false; } - return - ( - this.Code == input.Code || - 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()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(UnprocessableContentMessageResponse input) { + + if (!IsPropertyEqual(this.Code, input.Code)) { + return false; + } + + if (!IsPropertyEqual(this.Message, input.Message)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(UnprocessableContentMessageResponse input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/User.cs b/src/OpenFga.Sdk/Model/User.cs index 079beb1..c8470c8 100644 --- a/src/OpenFga.Sdk/Model/User.cs +++ b/src/OpenFga.Sdk/Model/User.cs @@ -90,7 +90,17 @@ public static User FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as User); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((User)input); } /// @@ -102,23 +112,64 @@ public bool Equals(User input) { if (input == null) { return false; } - return - ( - this.Object == input.Object || - (this.Object != null && - this.Object.Equals(input.Object)) - ) && - ( - this.Userset == input.Userset || - (this.Userset != null && - this.Userset.Equals(input.Userset)) - ) && - ( - this.Wildcard == input.Wildcard || - (this.Wildcard != null && - this.Wildcard.Equals(input.Wildcard)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(User input) { + + if (!IsPropertyEqual(this.Object, input.Object)) { + return false; + } + + if (!IsPropertyEqual(this.Userset, input.Userset)) { + return false; + } + + if (!IsPropertyEqual(this.Wildcard, input.Wildcard)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(User input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/UserTypeFilter.cs b/src/OpenFga.Sdk/Model/UserTypeFilter.cs index 362b6b9..03c8d7a 100644 --- a/src/OpenFga.Sdk/Model/UserTypeFilter.cs +++ b/src/OpenFga.Sdk/Model/UserTypeFilter.cs @@ -84,7 +84,17 @@ public static UserTypeFilter FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as UserTypeFilter); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((UserTypeFilter)input); } /// @@ -96,18 +106,60 @@ public bool Equals(UserTypeFilter input) { if (input == null) { return false; } - return - ( - this.Type == input.Type || - (this.Type != null && - this.Type.Equals(input.Type)) - ) && - ( - this.Relation == input.Relation || - (this.Relation != null && - this.Relation.Equals(input.Relation)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(UserTypeFilter input) { + + if (!IsPropertyEqual(this.Type, input.Type)) { + return false; + } + + if (!IsPropertyEqual(this.Relation, input.Relation)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(UserTypeFilter input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/Users.cs b/src/OpenFga.Sdk/Model/Users.cs index 0a115d3..f6fff1f 100644 --- a/src/OpenFga.Sdk/Model/Users.cs +++ b/src/OpenFga.Sdk/Model/Users.cs @@ -74,7 +74,17 @@ public static Users FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as Users); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((Users)input); } /// @@ -86,14 +96,56 @@ public bool Equals(Users input) { if (input == null) { return false; } - return - ( - this._Users == input._Users || - this._Users != null && - input._Users != null && - this._Users.SequenceEqual(input._Users) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(Users input) { + + if (!IsCollectionPropertyEqual(this._Users, input._Users)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(Users input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/Userset.cs b/src/OpenFga.Sdk/Model/Userset.cs index 5b1189f..a5d8336 100644 --- a/src/OpenFga.Sdk/Model/Userset.cs +++ b/src/OpenFga.Sdk/Model/Userset.cs @@ -121,7 +121,17 @@ public static Userset FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as Userset); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((Userset)input); } /// @@ -133,38 +143,76 @@ public bool Equals(Userset input) { if (input == null) { return false; } - return - ( - this.This == input.This || - (this.This != null && - this.This.Equals(input.This)) - ) && - ( - this.ComputedUserset == input.ComputedUserset || - (this.ComputedUserset != null && - this.ComputedUserset.Equals(input.ComputedUserset)) - ) && - ( - this.TupleToUserset == input.TupleToUserset || - (this.TupleToUserset != null && - this.TupleToUserset.Equals(input.TupleToUserset)) - ) && - ( - this.Union == input.Union || - (this.Union != null && - this.Union.Equals(input.Union)) - ) && - ( - this.Intersection == input.Intersection || - (this.Intersection != null && - this.Intersection.Equals(input.Intersection)) - ) && - ( - this.Difference == input.Difference || - (this.Difference != null && - this.Difference.Equals(input.Difference)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(Userset input) { + + if (!IsPropertyEqual(this.This, input.This)) { + return false; + } + + if (!IsPropertyEqual(this.ComputedUserset, input.ComputedUserset)) { + return false; + } + + if (!IsPropertyEqual(this.TupleToUserset, input.TupleToUserset)) { + return false; + } + + if (!IsPropertyEqual(this.Union, input.Union)) { + return false; + } + + if (!IsPropertyEqual(this.Intersection, input.Intersection)) { + return false; + } + + if (!IsPropertyEqual(this.Difference, input.Difference)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(Userset input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/UsersetTree.cs b/src/OpenFga.Sdk/Model/UsersetTree.cs index 1c87a41..c2b3ec2 100644 --- a/src/OpenFga.Sdk/Model/UsersetTree.cs +++ b/src/OpenFga.Sdk/Model/UsersetTree.cs @@ -70,7 +70,17 @@ public static UsersetTree FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as UsersetTree); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((UsersetTree)input); } /// @@ -82,13 +92,56 @@ public bool Equals(UsersetTree input) { if (input == null) { return false; } - return - ( - this.Root == input.Root || - (this.Root != null && - this.Root.Equals(input.Root)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(UsersetTree input) { + + if (!IsPropertyEqual(this.Root, input.Root)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(UsersetTree input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/UsersetTreeDifference.cs b/src/OpenFga.Sdk/Model/UsersetTreeDifference.cs index 9fa3152..ee960ea 100644 --- a/src/OpenFga.Sdk/Model/UsersetTreeDifference.cs +++ b/src/OpenFga.Sdk/Model/UsersetTreeDifference.cs @@ -88,7 +88,17 @@ public static UsersetTreeDifference FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as UsersetTreeDifference); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((UsersetTreeDifference)input); } /// @@ -100,18 +110,60 @@ public bool Equals(UsersetTreeDifference input) { if (input == null) { return false; } - return - ( - this.Base == input.Base || - (this.Base != null && - this.Base.Equals(input.Base)) - ) && - ( - this.Subtract == input.Subtract || - (this.Subtract != null && - this.Subtract.Equals(input.Subtract)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(UsersetTreeDifference input) { + + if (!IsPropertyEqual(this.Base, input.Base)) { + return false; + } + + if (!IsPropertyEqual(this.Subtract, input.Subtract)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(UsersetTreeDifference input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/UsersetTreeTupleToUserset.cs b/src/OpenFga.Sdk/Model/UsersetTreeTupleToUserset.cs index 3986aa4..c4ada28 100644 --- a/src/OpenFga.Sdk/Model/UsersetTreeTupleToUserset.cs +++ b/src/OpenFga.Sdk/Model/UsersetTreeTupleToUserset.cs @@ -88,7 +88,17 @@ public static UsersetTreeTupleToUserset FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as UsersetTreeTupleToUserset); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((UsersetTreeTupleToUserset)input); } /// @@ -100,19 +110,60 @@ public bool Equals(UsersetTreeTupleToUserset input) { if (input == null) { return false; } - return - ( - this.Tupleset == input.Tupleset || - (this.Tupleset != null && - this.Tupleset.Equals(input.Tupleset)) - ) && - ( - this.Computed == input.Computed || - this.Computed != null && - input.Computed != null && - this.Computed.SequenceEqual(input.Computed) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(UsersetTreeTupleToUserset input) { + + if (!IsPropertyEqual(this.Tupleset, input.Tupleset)) { + return false; + } + + if (!IsCollectionPropertyEqual(this.Computed, input.Computed)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(UsersetTreeTupleToUserset input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/UsersetUser.cs b/src/OpenFga.Sdk/Model/UsersetUser.cs index 6a897cd..4657f54 100644 --- a/src/OpenFga.Sdk/Model/UsersetUser.cs +++ b/src/OpenFga.Sdk/Model/UsersetUser.cs @@ -102,7 +102,17 @@ public static UsersetUser FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as UsersetUser); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((UsersetUser)input); } /// @@ -114,23 +124,64 @@ public bool Equals(UsersetUser input) { if (input == null) { return false; } - return - ( - this.Type == input.Type || - (this.Type != null && - this.Type.Equals(input.Type)) - ) && - ( - this.Id == input.Id || - (this.Id != null && - this.Id.Equals(input.Id)) - ) && - ( - this.Relation == input.Relation || - (this.Relation != null && - this.Relation.Equals(input.Relation)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(UsersetUser input) { + + if (!IsPropertyEqual(this.Type, input.Type)) { + return false; + } + + if (!IsPropertyEqual(this.Id, input.Id)) { + return false; + } + + if (!IsPropertyEqual(this.Relation, input.Relation)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(UsersetUser input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/Usersets.cs b/src/OpenFga.Sdk/Model/Usersets.cs index d3a86e0..60b3766 100644 --- a/src/OpenFga.Sdk/Model/Usersets.cs +++ b/src/OpenFga.Sdk/Model/Usersets.cs @@ -74,7 +74,17 @@ public static Usersets FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as Usersets); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((Usersets)input); } /// @@ -86,14 +96,56 @@ public bool Equals(Usersets input) { if (input == null) { return false; } - return - ( - this.Child == input.Child || - this.Child != null && - input.Child != null && - this.Child.SequenceEqual(input.Child) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(Usersets input) { + + if (!IsCollectionPropertyEqual(this.Child, input.Child)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(Usersets input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/ValidationErrorMessageResponse.cs b/src/OpenFga.Sdk/Model/ValidationErrorMessageResponse.cs index e68bc37..c34d209 100644 --- a/src/OpenFga.Sdk/Model/ValidationErrorMessageResponse.cs +++ b/src/OpenFga.Sdk/Model/ValidationErrorMessageResponse.cs @@ -79,7 +79,17 @@ public static ValidationErrorMessageResponse FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as ValidationErrorMessageResponse); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((ValidationErrorMessageResponse)input); } /// @@ -91,17 +101,60 @@ public bool Equals(ValidationErrorMessageResponse input) { if (input == null) { return false; } - return - ( - this.Code == input.Code || - 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()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(ValidationErrorMessageResponse input) { + + if (!IsPropertyEqual(this.Code, input.Code)) { + return false; + } + + if (!IsPropertyEqual(this.Message, input.Message)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(ValidationErrorMessageResponse input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/WriteAssertionsRequest.cs b/src/OpenFga.Sdk/Model/WriteAssertionsRequest.cs index 2457381..4a7a4a6 100644 --- a/src/OpenFga.Sdk/Model/WriteAssertionsRequest.cs +++ b/src/OpenFga.Sdk/Model/WriteAssertionsRequest.cs @@ -74,7 +74,17 @@ public static WriteAssertionsRequest FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as WriteAssertionsRequest); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((WriteAssertionsRequest)input); } /// @@ -86,14 +96,56 @@ public bool Equals(WriteAssertionsRequest input) { if (input == null) { return false; } - return - ( - this.Assertions == input.Assertions || - this.Assertions != null && - input.Assertions != null && - this.Assertions.SequenceEqual(input.Assertions) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(WriteAssertionsRequest input) { + + if (!IsCollectionPropertyEqual(this.Assertions, input.Assertions)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(WriteAssertionsRequest input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/WriteAuthorizationModelRequest.cs b/src/OpenFga.Sdk/Model/WriteAuthorizationModelRequest.cs index 6c4b8bb..5fe11e1 100644 --- a/src/OpenFga.Sdk/Model/WriteAuthorizationModelRequest.cs +++ b/src/OpenFga.Sdk/Model/WriteAuthorizationModelRequest.cs @@ -98,7 +98,17 @@ public static WriteAuthorizationModelRequest FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as WriteAuthorizationModelRequest); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((WriteAuthorizationModelRequest)input); } /// @@ -110,25 +120,64 @@ public bool Equals(WriteAuthorizationModelRequest input) { if (input == null) { return false; } - return - ( - this.TypeDefinitions == input.TypeDefinitions || - this.TypeDefinitions != null && - input.TypeDefinitions != null && - this.TypeDefinitions.SequenceEqual(input.TypeDefinitions) - ) && - ( - 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()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(WriteAuthorizationModelRequest input) { + + if (!IsCollectionPropertyEqual(this.TypeDefinitions, input.TypeDefinitions)) { + return false; + } + + if (!IsPropertyEqual(this.SchemaVersion, input.SchemaVersion)) { + return false; + } + + if (!IsCollectionPropertyEqual(this.Conditions, input.Conditions)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(WriteAuthorizationModelRequest input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/WriteAuthorizationModelResponse.cs b/src/OpenFga.Sdk/Model/WriteAuthorizationModelResponse.cs index c60f383..9b894e0 100644 --- a/src/OpenFga.Sdk/Model/WriteAuthorizationModelResponse.cs +++ b/src/OpenFga.Sdk/Model/WriteAuthorizationModelResponse.cs @@ -74,7 +74,17 @@ public static WriteAuthorizationModelResponse FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as WriteAuthorizationModelResponse); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((WriteAuthorizationModelResponse)input); } /// @@ -86,13 +96,56 @@ public bool Equals(WriteAuthorizationModelResponse input) { if (input == null) { return false; } - return - ( - this.AuthorizationModelId == input.AuthorizationModelId || - (this.AuthorizationModelId != null && - this.AuthorizationModelId.Equals(input.AuthorizationModelId)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(WriteAuthorizationModelResponse input) { + + if (!IsPropertyEqual(this.AuthorizationModelId, input.AuthorizationModelId)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(WriteAuthorizationModelResponse input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/WriteRequest.cs b/src/OpenFga.Sdk/Model/WriteRequest.cs index d7f74a3..e3364fc 100644 --- a/src/OpenFga.Sdk/Model/WriteRequest.cs +++ b/src/OpenFga.Sdk/Model/WriteRequest.cs @@ -90,7 +90,17 @@ public static WriteRequest FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as WriteRequest); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((WriteRequest)input); } /// @@ -102,23 +112,64 @@ public bool Equals(WriteRequest input) { if (input == null) { return false; } - return - ( - this.Writes == input.Writes || - (this.Writes != null && - this.Writes.Equals(input.Writes)) - ) && - ( - this.Deletes == input.Deletes || - (this.Deletes != null && - this.Deletes.Equals(input.Deletes)) - ) && - ( - this.AuthorizationModelId == input.AuthorizationModelId || - (this.AuthorizationModelId != null && - this.AuthorizationModelId.Equals(input.AuthorizationModelId)) - ) - && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(WriteRequest input) { + + if (!IsPropertyEqual(this.Writes, input.Writes)) { + return false; + } + + if (!IsPropertyEqual(this.Deletes, input.Deletes)) { + return false; + } + + if (!IsPropertyEqual(this.AuthorizationModelId, input.AuthorizationModelId)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(WriteRequest input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/WriteRequestDeletes.cs b/src/OpenFga.Sdk/Model/WriteRequestDeletes.cs index 9353eb3..c0a3399 100644 --- a/src/OpenFga.Sdk/Model/WriteRequestDeletes.cs +++ b/src/OpenFga.Sdk/Model/WriteRequestDeletes.cs @@ -74,7 +74,17 @@ public static WriteRequestDeletes FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as WriteRequestDeletes); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((WriteRequestDeletes)input); } /// @@ -86,14 +96,56 @@ 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()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(WriteRequestDeletes input) { + + if (!IsCollectionPropertyEqual(this.TupleKeys, input.TupleKeys)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(WriteRequestDeletes input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Model/WriteRequestWrites.cs b/src/OpenFga.Sdk/Model/WriteRequestWrites.cs index 3560a62..53c57a2 100644 --- a/src/OpenFga.Sdk/Model/WriteRequestWrites.cs +++ b/src/OpenFga.Sdk/Model/WriteRequestWrites.cs @@ -74,7 +74,17 @@ public static WriteRequestWrites FromJson(string jsonString) { /// Object to be compared /// Boolean public override bool Equals(object input) { - return this.Equals(input as WriteRequestWrites); + // Proper type checking in the Equals method - don't use 'as' operator + if (input == null) + return false; + + if (ReferenceEquals(this, input)) + return true; + + if (this.GetType() != input.GetType()) + return false; + + return Equals((WriteRequestWrites)input); } /// @@ -86,14 +96,56 @@ 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.AdditionalProperties.Count == input.AdditionalProperties.Count && !this.AdditionalProperties.Except(input.AdditionalProperties).Any()); + + return ArePropertiesEqual(input); + } + + // Helper methods for property equality + private bool ArePropertiesEqual(WriteRequestWrites input) { + + if (!IsCollectionPropertyEqual(this.TupleKeys, input.TupleKeys)) { + return false; + } + + + // Check if additional properties are equal + if (!AreAdditionalPropertiesEqual(input)) { + return false; + } + + return true; + } + + private bool AreAdditionalPropertiesEqual(WriteRequestWrites input) { + if (this.AdditionalProperties.Count != input.AdditionalProperties.Count) { + return false; + } + + return !this.AdditionalProperties.Except(input.AdditionalProperties).Any(); + } + + private bool IsPropertyEqual(T thisValue, T otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.Equals(otherValue); + } + + private bool IsCollectionPropertyEqual(IEnumerable thisValue, IEnumerable otherValue) { + if (thisValue == null && otherValue == null) { + return true; + } + + if (thisValue == null || otherValue == null) { + return false; + } + + return thisValue.SequenceEqual(otherValue); } /// diff --git a/src/OpenFga.Sdk/Telemetry/Attributes.cs b/src/OpenFga.Sdk/Telemetry/Attributes.cs index e512ab0..c495c7a 100644 --- a/src/OpenFga.Sdk/Telemetry/Attributes.cs +++ b/src/OpenFga.Sdk/Telemetry/Attributes.cs @@ -293,8 +293,11 @@ public static TagList BuildAttributesForResponse(HashSet enabledAttri } } } - catch { - // This is just for metrics, it's safe to ignore parsing failures. + catch (JsonException) { + // Safe to ignore parsing failures for telemetry + } + catch (InvalidOperationException) { + // Safe to ignore for telemetry } } } @@ -342,8 +345,11 @@ public static TagList BuildAttributesForResponse(HashSet enabledAttri } } } - catch { - // This is just for metrics, it's safe to ignore parsing failures. + catch (JsonException) { + // Safe to ignore parsing failures for telemetry + } + catch (InvalidOperationException) { + // Safe to ignore for telemetry } } } From 7b55fa82feb4463649051e20b430afe472d17818 Mon Sep 17 00:00:00 2001 From: Ryan Quinn Date: Thu, 8 May 2025 11:44:11 -0500 Subject: [PATCH 3/4] Update ClientBatchCheckResponse.cs --- .../Client/Model/ClientBatchCheckResponse.cs | 106 +++++++++++++++++- 1 file changed, 100 insertions(+), 6 deletions(-) diff --git a/src/OpenFga.Sdk/Client/Model/ClientBatchCheckResponse.cs b/src/OpenFga.Sdk/Client/Model/ClientBatchCheckResponse.cs index b13d0e9..4531d5a 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientBatchCheckResponse.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientBatchCheckResponse.cs @@ -49,10 +49,55 @@ public BatchCheckSingleResponse() { } [JsonPropertyName("error")] public Exception? Error { get; set; } - public bool Equals(BatchCheckSingleResponse? other) => throw new NotImplementedException(); + /// + /// Returns true if objects are equal + /// + /// Object to be compared + /// Boolean + public override bool Equals(object? obj) { + if (obj is not BatchCheckSingleResponse other) + return false; + + return Equals(other); + } + + /// + /// Returns true if BatchCheckSingleResponse instances are equal + /// + /// Instance of BatchCheckSingleResponse to be compared + /// Boolean + public bool Equals(BatchCheckSingleResponse? other) { + if (other == null) + return false; + + return Allowed == other.Allowed && + (Request?.Equals(other.Request) ?? other.Request == null) && + ((Error == null && other.Error == null) || + (Error != null && other.Error != null && Error.Message == other.Error.Message)); + } - public IEnumerable Validate(ValidationContext validationContext) => - throw new NotImplementedException(); + /// + /// Gets the hash code + /// + /// Hash code + public override int GetHashCode() { + unchecked { + int hashCode = 41; + hashCode = (hashCode * 59) + Allowed.GetHashCode(); + + if (Request != null) + hashCode = (hashCode * 59) + Request.GetHashCode(); + + if (Error != null) + hashCode = (hashCode * 59) + Error.GetHashCode(); + + return hashCode; + } + } + + public IEnumerable Validate(ValidationContext validationContext) { + yield break; + } } /// @@ -78,10 +123,59 @@ public ClientBatchCheckClientResponse(List responses) [JsonPropertyName("responses")] public List Responses { get; set; } - public bool Equals(ClientBatchCheckClientResponse? other) => throw new NotImplementedException(); + /// + /// Returns true if objects are equal + /// + /// Object to be compared + /// Boolean + public override bool Equals(object? obj) { + if (obj is not ClientBatchCheckClientResponse other) + return false; + + return Equals(other); + } - public IEnumerable Validate(ValidationContext validationContext) => - throw new NotImplementedException(); + /// + /// Returns true if ClientBatchCheckClientResponse instances are equal + /// + /// Instance of ClientBatchCheckClientResponse to be compared + /// Boolean + public bool Equals(ClientBatchCheckClientResponse? other) { + if (other == null) + return false; + + if (Responses.Count != other.Responses.Count) + return false; + + for (int i = 0; i < Responses.Count; i++) { + if (!Responses[i].Equals(other.Responses[i])) + return false; + } + + return true; + } + + /// + /// Gets the hash code + /// + /// Hash code + public override int GetHashCode() { + unchecked { + int hashCode = 41; + + if (Responses != null) { + foreach (var response in Responses) { + hashCode = (hashCode * 59) + response.GetHashCode(); + } + } + + return hashCode; + } + } + + public IEnumerable Validate(ValidationContext validationContext) { + yield break; + } /// /// Appends a response to the list of responses From d0a255cd2d3d4d66e8a20836165bb412a2a92094 Mon Sep 17 00:00:00 2001 From: Ryan Quinn Date: Mon, 19 May 2025 14:02:17 -0500 Subject: [PATCH 4/4] update from sdk-generator --- CHANGELOG.md | 12 + example/Example1/Example1.cs | 148 +- example/Example1/Example1.csproj | 2 +- src/OpenFga.Sdk.Test/Api/OpenFgaApiTests.cs | 2 +- .../Client/OpenFgaClientTests.cs | 2510 +++++++++-------- .../Client/ClientBatchCheckResponseTest.cs | 48 + src/OpenFga.Sdk.Test/OpenFga.Sdk.Test.csproj | 20 +- src/OpenFga.Sdk/Api/OpenFgaApi.cs | 3 +- src/OpenFga.Sdk/Client/Client.cs | 13 +- .../Client/Model/ClientBatchCheckResponse.cs | 4 + .../Client/Model/ClientExpandRequest.cs | 18 + .../Client/Model/ClientListStoresRequest.cs | 67 + src/OpenFga.Sdk/OpenFga.Sdk.csproj | 6 +- 13 files changed, 1589 insertions(+), 1264 deletions(-) create mode 100644 src/OpenFga.Sdk.Test/Models/Client/ClientBatchCheckResponseTest.cs create mode 100644 src/OpenFga.Sdk/Client/Model/ClientListStoresRequest.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e01224..95c8f11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,18 @@ ## [Unreleased](https://github.com/openfga/dotnet-sdk/compare/v0.5.1...HEAD) - feat: add support for `start_time` parameter in `ReadChanges` endpoint +- feat: update API definitions +- feat: support assertions context and contextual tuples +- feat: support contextual tuples in `Expand` +- feat!: support passing in name to filter in `ListStores` +- fix: remove dependency on OpenTelemetry.Api (#100) - thanks @m4tchl0ck +- fix: limit default retries to `3` from `15` (https://github.com/openfga/sdk-generator/pull/420) - thanks @ovindu-a +- fix: `ListRelations` should not swallow errors +- chore(docs): replace readable names with uuid to discourage storing PII in OpenFGA (https://github.com/openfga/sdk-generator/pull/433) - thanks @sccalabr + +[!WARNING] +BREAKING CHANGES: +- The `ListStores` method now accepts a body parameter with an optional `Name` to filter the stores. This is a breaking change as it changes the method contract to allow passing in a body with the name. ## v0.5.1 diff --git a/example/Example1/Example1.cs b/example/Example1/Example1.cs index 3324677..657e90b 100644 --- a/example/Example1/Example1.cs +++ b/example/Example1/Example1.cs @@ -9,6 +9,9 @@ namespace Example1; public class Example1 { public static async Task Main() { + var shouldSkipListingStores = false; + var shouldSkipStoreMethods = false; + try { var credentials = new Credentials(); if (Environment.GetEnvironmentVariable("FGA_CLIENT_ID") != null) { @@ -29,28 +32,44 @@ public static async Task Main() { }; var fgaClient = new OpenFgaClient(configuration); - // ListStores - Console.WriteLine("Listing Stores"); - var stores1 = await fgaClient.ListStores(); - Console.WriteLine("Stores Count: " + stores1.Stores?.Count()); + GetStoreResponse? currentStore = null; + if (shouldSkipStoreMethods) { + Console.WriteLine("Skipping initial store creation"); + } + else { + if (shouldSkipListingStores) { + Console.WriteLine("Skipping Listing Stores"); + } + else { + // 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); + // CreateStore + Console.WriteLine("Creating Test Store"); + var store = await fgaClient.CreateStore(new ClientCreateStoreRequest {Name = "Test Store"}); + Console.WriteLine("Created Test Store ID: " + store.Id); - // Set the store id - fgaClient.StoreId = 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()); + if (shouldSkipListingStores) { + Console.WriteLine("Skipping Listing Stores"); + } + else { + // 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); + // GetStore + Console.WriteLine("Getting Current Store"); + currentStore = await fgaClient.GetStore(); + Console.WriteLine("Current Store Name: " + currentStore.Name); + } // ReadAuthorizationModels Console.WriteLine("Reading Authorization Models"); @@ -142,16 +161,23 @@ public static async Task Main() { Console.WriteLine("Authorization Model ID " + authorizationModel.AuthorizationModelId); // ReadAuthorizationModels - after Write + Thread.Sleep(10_000); 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); + if (latestAauthorizationModel == null) { + throw new Exception("Cannot find module that was written"); + } + else { + var latestModelId = latestAauthorizationModel.AuthorizationModel?.Id; + Console.WriteLine("Latest Authorization Model ID " + latestModelId); - // Set the model ID - fgaClient.AuthorizationModelId = latestAauthorizationModel.AuthorizationModel.Id; + // Set the model ID + fgaClient.AuthorizationModelId = latestModelId; + } // Write Console.WriteLine("Writing Tuples"); @@ -160,7 +186,7 @@ await fgaClient.Write(new ClientWriteRequest { new() { User = "user:anne", Relation = "writer", - Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", + Object = "document:roadmap", Condition = new RelationshipCondition() { Name = "ViewCountLessThan200", Context = new { Name = "Roadmap", Type = "document" } @@ -188,7 +214,7 @@ await fgaClient.Write(new ClientWriteRequest { var failingCheckResponse = await fgaClient.Check(new ClientCheckRequest { User = "user:anne", Relation = "viewer", - Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" + Object = "document:roadmap" }); Console.WriteLine("Allowed: " + failingCheckResponse.Allowed); } @@ -201,11 +227,70 @@ await fgaClient.Write(new ClientWriteRequest { var checkResponse = await fgaClient.Check(new ClientCheckRequest { User = "user:anne", Relation = "viewer", - Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", + Object = "document:roadmap", Context = new { ViewCount = 100 } }); Console.WriteLine("Allowed: " + checkResponse.Allowed); + // Batch checking for access with context + Console.WriteLine("Batch checking for access with context"); + var batchCheckResponse = await fgaClient.BatchCheck(new List() { + new () { + User = "user:anne", + Relation = "viewer", + Object = "document:roadmap", + Context = new { ViewCount = 100 } + } + }); + Console.WriteLine("Responses[0].Allowed: " + batchCheckResponse.Responses[0].Allowed); + + // Listing relations with context + Console.WriteLine("Listing relations with context"); + var listRelationsResponse = await fgaClient.ListRelations(new ClientListRelationsRequest() { + User = "user:anne", + Relations = new List() {"viewer", "writer"}, + Object = "document:roadmap", + Context = new { ViewCount = 100 } + }); + // var allowedRelations = new List(); + // listRelationsResponse.Relations?.ForEach(r => { + // allowedRelations.Add(r); + // }); + Console.WriteLine("Relations: " + string.Join(" | ", listRelationsResponse.Relations!)); + + // Listing objects with context + Console.WriteLine("Listing objects with context"); + var listObjectsResponse = await fgaClient.ListObjects(new ClientListObjectsRequest() { + User = "user:anne", + Relation = "viewer", + Type = "document", + Context = new { ViewCount = 100 } + }); + // var allowedObjects = new List(); + // listObjectsResponse.Objects?.ForEach(o => { + // allowedObjects.Add(o); + // }); + Console.WriteLine("Objects: " + string.Join(" | ", listObjectsResponse.Objects!)); + + // Listing users with context + Console.WriteLine("Listing users with context"); + var listUsersResponse = await fgaClient.ListUsers(new ClientListUsersRequest() { + UserFilters = new List() { + new () { Type = "user" }, + }, + Relation = "viewer", + Object = new FgaObject() { + Type = "document", + Id = "roadmap" + }, + Context = new { ViewCount = 100 } + }); + var allowedUsers = new List(); + listUsersResponse.Users?.ForEach(u => { + allowedUsers.Add(u.ToJson()); + }); + Console.WriteLine("Users: " + string.Join(" | ", allowedUsers)); + // WriteAssertions await fgaClient.WriteAssertions(new List() { new ClientAssertion() { @@ -217,7 +302,7 @@ await fgaClient.WriteAssertions(new List() { new ClientAssertion() { User = "user:anne", Relation = "viewer", - Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", + Object = "document:roadmap", Expectation = false, } }); @@ -228,10 +313,15 @@ await fgaClient.WriteAssertions(new List() { 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); + if (shouldSkipStoreMethods || currentStore == null) { + Console.WriteLine("Skipping store deletion"); + } + else { + // DeleteStore + Console.WriteLine("Deleting Test Store"); + await fgaClient.DeleteStore(); + Console.WriteLine("Deleted Store: " + currentStore.Name); + } } catch (ApiException e) { Console.WriteLine("Error: " + e); diff --git a/example/Example1/Example1.csproj b/example/Example1/Example1.csproj index 3bbed4d..54d4033 100644 --- a/example/Example1/Example1.csproj +++ b/example/Example1/Example1.csproj @@ -10,7 +10,7 @@ - all + all diff --git a/src/OpenFga.Sdk.Test/Api/OpenFgaApiTests.cs b/src/OpenFga.Sdk.Test/Api/OpenFgaApiTests.cs index 5e8876c..7f14cde 100644 --- a/src/OpenFga.Sdk.Test/Api/OpenFgaApiTests.cs +++ b/src/OpenFga.Sdk.Test/Api/OpenFgaApiTests.cs @@ -76,7 +76,7 @@ public void StoreIdNotRequired() { /// Test that a storeId is required when calling methods that need it /// [Fact] - public async Task StoreIdRequiredWhenNeeded() { + public async void StoreIdRequiredWhenNeeded() { var config = new Configuration.Configuration() { ApiHost = _host }; var openFgaApi = new OpenFgaApi(config); diff --git a/src/OpenFga.Sdk.Test/Client/OpenFgaClientTests.cs b/src/OpenFga.Sdk.Test/Client/OpenFgaClientTests.cs index a6da9b2..925eae1 100644 --- a/src/OpenFga.Sdk.Test/Client/OpenFgaClientTests.cs +++ b/src/OpenFga.Sdk.Test/Client/OpenFgaClientTests.cs @@ -29,357 +29,362 @@ using System.Threading.Tasks; using Xunit; -namespace OpenFga.Sdk.Test.Client; +namespace OpenFga.Sdk.Test.Client { -public class OpenFgaClientTests { - private readonly string _storeId; - private readonly string _apiUrl = "https://api.fga.example"; - private readonly ClientConfiguration _config; + public class OpenFgaClientTests { + private readonly string _storeId; + private readonly string _apiUrl = "https://api.fga.example"; + private readonly ClientConfiguration _config; - public OpenFgaClientTests() { - _storeId = "01H0H015178Y2V4CX10C2KGHF4"; - _config = new ClientConfiguration() { StoreId = _storeId, ApiUrl = _apiUrl }; - } + public OpenFgaClientTests() { + _storeId = "01H0H015178Y2V4CX10C2KGHF4"; + _config = new ClientConfiguration() { StoreId = _storeId, ApiUrl = _apiUrl }; + } - private HttpResponseMessage GetCheckResponse(CheckResponse content, bool shouldRetry = false) { - var response = new HttpResponseMessage() { - StatusCode = shouldRetry ? HttpStatusCode.TooManyRequests : HttpStatusCode.OK, - Content = Utils.CreateJsonStringContent(content), - Headers = { } - }; + private HttpResponseMessage GetCheckResponse(CheckResponse content, bool shouldRetry = false) { + var response = new HttpResponseMessage() { + StatusCode = shouldRetry ? HttpStatusCode.TooManyRequests : HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(content), + Headers = { } + }; - if (shouldRetry) { - response.Headers.Add(RateLimitParser.RateLimitHeader.LimitRemaining, "0"); - response.Headers.Add(RateLimitParser.RateLimitHeader.LimitResetIn, "100"); - response.Headers.Add(RateLimitParser.RateLimitHeader.LimitTotalInPeriod, "2"); - } + if (shouldRetry) { + response.Headers.Add(RateLimitParser.RateLimitHeader.LimitRemaining, "0"); + response.Headers.Add(RateLimitParser.RateLimitHeader.LimitResetIn, "100"); + response.Headers.Add(RateLimitParser.RateLimitHeader.LimitTotalInPeriod, "2"); + } - return response; - } + return response; + } - [Fact] - public void Dispose() { - // Cleanup when everything is done. - } + [Fact] + 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.EnsureValid(); - var exception = Assert.Throws(ActionInvalidId); - Assert.Equal("StoreId is not in a valid ulid format", exception.Message); - } + /// + /// Test StoreId validation + /// + [Fact] + public async Task ConfigurationInValidStoreIdTest() { + var config = new ClientConfiguration() { + ApiUrl = _apiUrl, + StoreId = "invalid-format" + }; + void ActionInvalidId() => config.EnsureValid(); + 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 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); + /// + /// Test Auth Model ID validation + /// + [Fact] + public async Task ConfigurationInValidAuthModelIdInOptionsTest() { + var config = new ClientConfiguration() { + ApiUrl = _apiUrl, + StoreId = _config.StoreId, + }; + var fgaClient = 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); - } + async Task ActionMissingStoreId() => await fgaClient.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 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); - } + /// + /// 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 - /// - [Fact] - public async Task ListStoresTest() { - var mockHandler = new Mock(MockBehavior.Strict); - var expectedResponse = new ListStoresResponse() { - Stores = new List() { + /********** + * Stores * + **********/ + + /// + /// Test ListStores + /// + [Fact] + public async Task ListStoresTest() { + var mockHandler = new Mock(MockBehavior.Strict); + var expectedResponse = new ListStoresResponse() { + Stores = new List() { new Store() {Id = "45678", Name = "TestStore", CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now} } - }; - mockHandler.Protected() - .Setup>( + }; + mockHandler.Protected() + .Setup>( + "SendAsync", + ItExpr.Is(req => + req.RequestUri == new Uri($"{_config.BasePath}/stores?page_size=10&") && + req.Method == HttpMethod.Get), + ItExpr.IsAny() + ) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(expectedResponse), + }); + + var httpClient = new HttpClient(mockHandler.Object); + var fgaClient = new OpenFgaClient(_config, httpClient); + + var response = await fgaClient.ListStores( + new ClientListStoresOptions() { + PageSize = 10, + ContinuationToken = null + } + ); + + mockHandler.Protected().Verify( "SendAsync", + Times.Exactly(1), ItExpr.Is(req => - req.RequestUri == - new Uri($"{_config.BasePath}/stores") && + req.RequestUri == new Uri($"{_config.BasePath}/stores?page_size=10&") && req.Method == HttpMethod.Get), ItExpr.IsAny() - ) - .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = Utils.CreateJsonStringContent(expectedResponse), - }); + ); + Assert.IsType(response); + Assert.Single(response.Stores); + Assert.Equal(response, expectedResponse); + } - var httpClient = new HttpClient(mockHandler.Object); - var fgaClient = new OpenFgaClient(_config, httpClient); - - var response = await fgaClient.ListStores(new ClientListStoresOptions() { }); - mockHandler.Protected().Verify( - "SendAsync", - Times.Exactly(1), - ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores") && - req.Method == HttpMethod.Get), - ItExpr.IsAny() - ); - Assert.IsType(response); - Assert.Single(response.Stores); - Assert.Equal(response, expectedResponse); - } + /// + /// Test ListStores with Null DateTime + /// + [Fact] + public async Task ListStoresTestNullDeletedAt() { + var mockHandler = new Mock(MockBehavior.Strict); + var content = + "{ \"stores\": [{\"id\": \"xyz123\", \"name\": \"abcdefg\", \"created_at\": \"2022-10-07T14:00:40.205Z\", \"updated_at\": \"2022-10-07T14:00:40.205Z\", \"deleted_at\": null}], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\"}"; + mockHandler.Protected() + .Setup>( + "SendAsync", + ItExpr.Is(req => + req.RequestUri == + new Uri($"{_config.BasePath}/stores") && + req.Method == HttpMethod.Get), + ItExpr.IsAny() + ) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = new StringContent(content, Encoding.UTF8, "application/json") + }); - /// - /// Test ListStores with Null DateTime - /// - [Fact] - public async Task ListStoresTestNullDeletedAt() { - var mockHandler = new Mock(MockBehavior.Strict); - var content = - "{ \"stores\": [{\"id\": \"xyz123\", \"name\": \"abcdefg\", \"created_at\": \"2022-10-07T14:00:40.205Z\", \"updated_at\": \"2022-10-07T14:00:40.205Z\", \"deleted_at\": null}], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\"}"; - mockHandler.Protected() - .Setup>( + var httpClient = new HttpClient(mockHandler.Object); + var fgaClient = new OpenFgaClient(_config, httpClient); + + var response = await fgaClient.ListStores(); + mockHandler.Protected().Verify( "SendAsync", + Times.Exactly(1), ItExpr.Is(req => - req.RequestUri == - new Uri($"{_config.BasePath}/stores") && + req.RequestUri == new Uri($"{_config.BasePath}/stores") && req.Method == HttpMethod.Get), ItExpr.IsAny() - ) - .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = new StringContent(content, Encoding.UTF8, "application/json") - }); + ); + Assert.IsType(response); + Assert.Single(response.Stores); + Assert.Equal("xyz123", response.Stores[0].Id); + Assert.Equal("abcdefg", response.Stores[0].Name); + Assert.Null(response.Stores[0].DeletedAt); + } - var httpClient = new HttpClient(mockHandler.Object); - var fgaClient = new OpenFgaClient(_config, httpClient); - - var response = await fgaClient.ListStores(); - mockHandler.Protected().Verify( - "SendAsync", - Times.Exactly(1), - ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores") && - req.Method == HttpMethod.Get), - ItExpr.IsAny() - ); - Assert.IsType(response); - Assert.Single(response.Stores); - Assert.Equal("xyz123", response.Stores[0].Id); - Assert.Equal("abcdefg", response.Stores[0].Name); - Assert.Null(response.Stores[0].DeletedAt); - } + /// + /// Test ListStores for empty array + /// + [Fact] + public async Task ListStoresEmptyTest() { + var mockHandler = new Mock(MockBehavior.Strict); + var expectedResponse = new ListStoresResponse() { Stores = new List() { } }; + mockHandler.Protected() + .Setup>( + "SendAsync", + ItExpr.Is(req => + req.RequestUri == + new Uri($"{_config.BasePath}/stores") && + req.Method == HttpMethod.Get), + ItExpr.IsAny() + ) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(expectedResponse), + }); + + var httpClient = new HttpClient(mockHandler.Object); + var fgaClient = new OpenFgaClient(_config, httpClient); - /// - /// Test ListStores for empty array - /// - [Fact] - public async Task ListStoresEmptyTest() { - var mockHandler = new Mock(MockBehavior.Strict); - var expectedResponse = new ListStoresResponse() { Stores = new List() { } }; - mockHandler.Protected() - .Setup>( + var response = await fgaClient.ListStores(); + mockHandler.Protected().Verify( "SendAsync", + Times.Exactly(1), ItExpr.Is(req => - req.RequestUri == - new Uri($"{_config.BasePath}/stores") && + req.RequestUri == new Uri($"{_config.BasePath}/stores") && req.Method == HttpMethod.Get), ItExpr.IsAny() - ) - .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = Utils.CreateJsonStringContent(expectedResponse), - }); + ); + Assert.IsType(response); + Assert.Empty(response.Stores); + Assert.Equal(response, expectedResponse); + } - var httpClient = new HttpClient(mockHandler.Object); - var fgaClient = new OpenFgaClient(_config, httpClient); - - var response = await fgaClient.ListStores(); - mockHandler.Protected().Verify( - "SendAsync", - Times.Exactly(1), - ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores") && - req.Method == HttpMethod.Get), - ItExpr.IsAny() - ); - Assert.IsType(response); - Assert.Empty(response.Stores); - Assert.Equal(response, expectedResponse); - } + /// + /// Test CreateStore + /// + [Fact] + public async Task CreateStoreTest() { + var mockHandler = new Mock(MockBehavior.Strict); + var expectedResponse = new CreateStoreResponse() { Id = "45678", Name = "TestStore", CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now }; + mockHandler.Protected() + .Setup>( + "SendAsync", + ItExpr.Is(req => + req.RequestUri == + new Uri($"{_config.BasePath}/stores") && + req.Method == HttpMethod.Post), + ItExpr.IsAny() + ) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(expectedResponse), + }); + + var httpClient = new HttpClient(mockHandler.Object); + var fgaClient = new OpenFgaClient(_config, httpClient); - /// - /// Test CreateStore - /// - [Fact] - public async Task CreateStoreTest() { - var mockHandler = new Mock(MockBehavior.Strict); - var expectedResponse = new CreateStoreResponse() { Id = "45678", Name = "TestStore", CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now }; - mockHandler.Protected() - .Setup>( + var response = await fgaClient.CreateStore(new ClientCreateStoreRequest() { Name = "FGA Test Store" }); + mockHandler.Protected().Verify( "SendAsync", + Times.Exactly(1), ItExpr.Is(req => - req.RequestUri == - new Uri($"{_config.BasePath}/stores") && + req.RequestUri == new Uri($"{_config.BasePath}/stores") && req.Method == HttpMethod.Post), ItExpr.IsAny() - ) - .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = Utils.CreateJsonStringContent(expectedResponse), - }); + ); + Assert.IsType(response); + Assert.Equal(response, expectedResponse); + } - var httpClient = new HttpClient(mockHandler.Object); - var fgaClient = new OpenFgaClient(_config, httpClient); - - var response = await fgaClient.CreateStore(new ClientCreateStoreRequest() { Name = "FGA Test Store" }); - mockHandler.Protected().Verify( - "SendAsync", - Times.Exactly(1), - ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores") && - req.Method == HttpMethod.Post), - ItExpr.IsAny() - ); - Assert.IsType(response); - Assert.Equal(response, expectedResponse); - } + /// + /// Test GetStore + /// + [Fact] + public async Task GetStoreTest() { + var mockHandler = new Mock(MockBehavior.Strict); + var expectedResponse = new GetStoreResponse() { Id = "45678", Name = "TestStore", CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now }; + mockHandler.Protected() + .Setup>( + "SendAsync", + ItExpr.Is(req => + req.RequestUri == + new Uri($"{_config.BasePath}/stores/{_config.StoreId}") && + req.Method == HttpMethod.Get), + ItExpr.IsAny() + ) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(expectedResponse), + }); + + var httpClient = new HttpClient(mockHandler.Object); + var fgaClient = new OpenFgaClient(_config, httpClient); - /// - /// Test GetStore - /// - [Fact] - public async Task GetStoreTest() { - var mockHandler = new Mock(MockBehavior.Strict); - var expectedResponse = new GetStoreResponse() { Id = "45678", Name = "TestStore", CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now }; - mockHandler.Protected() - .Setup>( + var response = await fgaClient.GetStore(); + mockHandler.Protected().Verify( "SendAsync", + Times.Exactly(1), ItExpr.Is(req => - req.RequestUri == - new Uri($"{_config.BasePath}/stores/{_config.StoreId}") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{fgaClient.StoreId}") && req.Method == HttpMethod.Get), ItExpr.IsAny() - ) - .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = Utils.CreateJsonStringContent(expectedResponse), - }); - - var httpClient = new HttpClient(mockHandler.Object); - var fgaClient = new OpenFgaClient(_config, httpClient); - - var response = await fgaClient.GetStore(); - mockHandler.Protected().Verify( - "SendAsync", - Times.Exactly(1), - ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{fgaClient.StoreId}") && - req.Method == HttpMethod.Get), - ItExpr.IsAny() - ); - Assert.IsType(response); - Assert.Equal(response, expectedResponse); - } + ); + Assert.IsType(response); + Assert.Equal(response, expectedResponse); + } - /// - /// Test DeleteStore - /// - [Fact] - public async Task DeleteStoreTest() { - var mockHandler = new Mock(MockBehavior.Strict); - mockHandler.Protected() - .Setup>( + /// + /// Test DeleteStore + /// + [Fact] + public async Task DeleteStoreTest() { + var mockHandler = new Mock(MockBehavior.Strict); + mockHandler.Protected() + .Setup>( + "SendAsync", + ItExpr.Is(req => + req.RequestUri == + new Uri($"{_config.BasePath}/stores/{_config.StoreId}") && + req.Method == HttpMethod.Delete), + ItExpr.IsAny() + ) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.NoContent + }); + + var httpClient = new HttpClient(mockHandler.Object); + var fgaClient = new OpenFgaClient(_config, httpClient); + + await fgaClient.DeleteStore(); + mockHandler.Protected().Verify( "SendAsync", + Times.Exactly(1), ItExpr.Is(req => - req.RequestUri == - new Uri($"{_config.BasePath}/stores/{_config.StoreId}") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{fgaClient.StoreId}") && req.Method == HttpMethod.Delete), ItExpr.IsAny() - ) - .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.NoContent - }); - - var httpClient = new HttpClient(mockHandler.Object); - var fgaClient = new OpenFgaClient(_config, httpClient); - - await fgaClient.DeleteStore(); - mockHandler.Protected().Verify( - "SendAsync", - Times.Exactly(1), - ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{fgaClient.StoreId}") && - req.Method == HttpMethod.Delete), - ItExpr.IsAny() - ); - } + ); + } - /************************ - * Authorization Models * - ************************/ - - /// - /// Test WriteAuthorizationModel - /// - [Fact] - public async Task WriteAuthorizationModelTest() { - const string authorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1"; - var body = new ClientWriteAuthorizationModelRequest { - SchemaVersion = "1.1", - TypeDefinitions = new List { + /************************ + * Authorization Models * + ************************/ + + /// + /// Test WriteAuthorizationModel + /// + [Fact] + public async Task WriteAuthorizationModelTest() { + const string authorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1"; + var body = new ClientWriteAuthorizationModelRequest { + SchemaVersion = "1.1", + TypeDefinitions = new List { new() { Type = "user", Relations = new Dictionary() }, @@ -430,192 +435,192 @@ public async Task WriteAuthorizationModelTest() { } } } - }; - var mockHandler = new Mock(MockBehavior.Strict); + }; + var mockHandler = new Mock(MockBehavior.Strict); + + mockHandler.Protected() + .Setup>( + "SendAsync", + ItExpr.Is(req => + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/authorization-models") && + req.Method == HttpMethod.Post), + ItExpr.IsAny() + ) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent( + new WriteAuthorizationModelResponse() { AuthorizationModelId = authorizationModelId }), + }); + + var httpClient = new HttpClient(mockHandler.Object); + var fgaClient = new OpenFgaClient(_config, httpClient); - mockHandler.Protected() - .Setup>( + var response = await fgaClient.WriteAuthorizationModel(body); + + mockHandler.Protected().Verify( "SendAsync", + Times.Exactly(1), ItExpr.Is(req => req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/authorization-models") && req.Method == HttpMethod.Post), ItExpr.IsAny() - ) - .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = Utils.CreateJsonStringContent( - new WriteAuthorizationModelResponse() { AuthorizationModelId = authorizationModelId }), - }); - - var httpClient = new HttpClient(mockHandler.Object); - var fgaClient = new OpenFgaClient(_config, httpClient); + ); - var response = await fgaClient.WriteAuthorizationModel(body); + Assert.IsType(response); + } - mockHandler.Protected().Verify( - "SendAsync", - Times.Exactly(1), - ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/authorization-models") && - req.Method == HttpMethod.Post), - ItExpr.IsAny() - ); + /// + /// Test ReadAuthorizationModel + /// + [Fact] + public async Task ReadAuthorizationModelTest() { + const string authorizationModelId = "01FMJA27YCE3QAT8RDS9VZFN0T"; + + var mockHandler = new Mock(MockBehavior.Strict); + mockHandler.Protected() + .Setup>( + "SendAsync", + ItExpr.Is(req => + req.RequestUri == + new Uri( + $"{_config.BasePath}/stores/{_config.StoreId}/authorization-models/{authorizationModelId}") && + req.Method == HttpMethod.Get), + ItExpr.IsAny() + ) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(new ReadAuthorizationModelResponse() { + AuthorizationModel = new AuthorizationModel(id: authorizationModelId, + typeDefinitions: new List(), schemaVersion: "1.1") + }), + }); - Assert.IsType(response); - } + var httpClient = new HttpClient(mockHandler.Object); + var fgaClient = new OpenFgaClient(_config, httpClient); - /// - /// Test ReadAuthorizationModel - /// - [Fact] - public async Task ReadAuthorizationModelTest() { - const string authorizationModelId = "01FMJA27YCE3QAT8RDS9VZFN0T"; + var response = await fgaClient.ReadAuthorizationModel(new ClientReadAuthorizationModelOptions { + AuthorizationModelId = authorizationModelId, + }); - var mockHandler = new Mock(MockBehavior.Strict); - mockHandler.Protected() - .Setup>( + 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/{_config.StoreId}/authorization-models/{authorizationModelId}") && req.Method == HttpMethod.Get), ItExpr.IsAny() - ) - .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = Utils.CreateJsonStringContent(new ReadAuthorizationModelResponse() { - AuthorizationModel = new AuthorizationModel(id: authorizationModelId, - typeDefinitions: new List(), schemaVersion: "1.1") - }), - }); + ); - var httpClient = new HttpClient(mockHandler.Object); - var fgaClient = new OpenFgaClient(_config, httpClient); - - var response = await fgaClient.ReadAuthorizationModel(new ClientReadAuthorizationModelOptions { - AuthorizationModelId = authorizationModelId, - }); - - mockHandler.Protected().Verify( - "SendAsync", - Times.Exactly(1), - ItExpr.Is(req => - req.RequestUri == - new Uri($"{_config.BasePath}/stores/{_config.StoreId}/authorization-models/{authorizationModelId}") && - req.Method == HttpMethod.Get), - ItExpr.IsAny() - ); - - Assert.IsType(response); - Assert.Equal(authorizationModelId, response.AuthorizationModel.Id); - } - /// - /// Test ReadAuthorizationModel - /// - [Fact] - public async Task ReadAuthorizationModelModelIdInConfigTest() { - const string authorizationModelId = "01FMJA27YCE3QAT8RDS9VZFN0T"; - - var mockHandler = new Mock(MockBehavior.Strict); - mockHandler.Protected() - .Setup>( + Assert.IsType(response); + Assert.Equal(authorizationModelId, response.AuthorizationModel.Id); + } + /// + /// Test ReadAuthorizationModel + /// + [Fact] + public async Task ReadAuthorizationModelModelIdInConfigTest() { + const string authorizationModelId = "01FMJA27YCE3QAT8RDS9VZFN0T"; + + var mockHandler = new Mock(MockBehavior.Strict); + mockHandler.Protected() + .Setup>( + "SendAsync", + ItExpr.Is(req => + req.RequestUri == + new Uri( + $"{_config.BasePath}/stores/{_config.StoreId}/authorization-models/{authorizationModelId}") && + req.Method == HttpMethod.Get), + ItExpr.IsAny() + ) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(new ReadAuthorizationModelResponse() { + AuthorizationModel = new AuthorizationModel(id: authorizationModelId, + typeDefinitions: new List(), schemaVersion: "1.1") + }), + }); + + var httpClient = new HttpClient(mockHandler.Object); + var fgaClient = new OpenFgaClient(new ClientConfiguration(_config) { + StoreId = _storeId, + AuthorizationModelId = authorizationModelId, + }, httpClient); + + var response = await fgaClient.ReadAuthorizationModel(); + + 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/{_config.StoreId}/authorization-models/{authorizationModelId}") && req.Method == HttpMethod.Get), ItExpr.IsAny() - ) - .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = Utils.CreateJsonStringContent(new ReadAuthorizationModelResponse() { - AuthorizationModel = new AuthorizationModel(id: authorizationModelId, - typeDefinitions: new List(), schemaVersion: "1.1") - }), - }); + ); - var httpClient = new HttpClient(mockHandler.Object); - var fgaClient = new OpenFgaClient(new ClientConfiguration(_config) { - StoreId = _storeId, - AuthorizationModelId = authorizationModelId, - }, httpClient); - - var response = await fgaClient.ReadAuthorizationModel(); - - mockHandler.Protected().Verify( - "SendAsync", - Times.Exactly(1), - ItExpr.Is(req => - req.RequestUri == - new Uri($"{_config.BasePath}/stores/{_config.StoreId}/authorization-models/{authorizationModelId}") && - req.Method == HttpMethod.Get), - ItExpr.IsAny() - ); - - Assert.IsType(response); - Assert.Equal(authorizationModelId, response.AuthorizationModel.Id); - } + Assert.IsType(response); + Assert.Equal(authorizationModelId, response.AuthorizationModel.Id); + } - /// - /// Test ReadAuthorizationModel - /// - [Fact] - public async Task ReadLatestAuthorizationModelTest() { - const string authorizationModelId = "01FMJA27YCE3QAT8RDS9VZFN0T"; + /// + /// Test ReadAuthorizationModel + /// + [Fact] + public async Task ReadLatestAuthorizationModelTest() { + const string authorizationModelId = "01FMJA27YCE3QAT8RDS9VZFN0T"; + + var mockHandler = new Mock(MockBehavior.Strict); + mockHandler.Protected() + .Setup>( + "SendAsync", + ItExpr.Is(req => + req.RequestUri == + new Uri( + $"{_config.BasePath}/stores/{_config.StoreId}/authorization-models?page_size=1&") && + req.Method == HttpMethod.Get), + ItExpr.IsAny() + ) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(new ReadAuthorizationModelsResponse() { + AuthorizationModels = new List() {new (id: authorizationModelId, + typeDefinitions: new List(), schemaVersion: "1.1")} + }), + }); - var mockHandler = new Mock(MockBehavior.Strict); - mockHandler.Protected() - .Setup>( + var httpClient = new HttpClient(mockHandler.Object); + var fgaClient = new OpenFgaClient(_config, httpClient); + + var response = await fgaClient.ReadLatestAuthorizationModel(); + + mockHandler.Protected().Verify( "SendAsync", + Times.Exactly(1), ItExpr.Is(req => req.RequestUri == - new Uri( - $"{_config.BasePath}/stores/{_config.StoreId}/authorization-models?page_size=1&") && + new Uri($"{_config.BasePath}/stores/{_config.StoreId}/authorization-models?page_size=1&") && req.Method == HttpMethod.Get), ItExpr.IsAny() - ) - .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = Utils.CreateJsonStringContent(new ReadAuthorizationModelsResponse() { - AuthorizationModels = new List() {new (id: authorizationModelId, - typeDefinitions: new List(), schemaVersion: "1.1")} - }), - }); - - var httpClient = new HttpClient(mockHandler.Object); - var fgaClient = new OpenFgaClient(_config, httpClient); - - var response = await fgaClient.ReadLatestAuthorizationModel(); + ); - mockHandler.Protected().Verify( - "SendAsync", - Times.Exactly(1), - ItExpr.Is(req => - req.RequestUri == - new Uri($"{_config.BasePath}/stores/{_config.StoreId}/authorization-models?page_size=1&") && - req.Method == HttpMethod.Get), - ItExpr.IsAny() - ); - - Assert.IsType(response); - Assert.Equal(authorizationModelId, response.AuthorizationModel.Id); - } + Assert.IsType(response); + Assert.Equal(authorizationModelId, response.AuthorizationModel.Id); + } - /*********************** - * Relationship Tuples * - ***********************/ + /*********************** + * Relationship Tuples * + ***********************/ - /// - /// Test ReadChanges - /// - [Fact] - public async Task ReadChangesTest() { - var mockHandler = new Mock(MockBehavior.Strict); - var expectedResponse = new ReadChangesResponse() { - Changes = new List() { + /// + /// Test ReadChanges + /// + [Fact] + public async Task ReadChangesTest() { + var mockHandler = new Mock(MockBehavior.Strict); + var expectedResponse = new ReadChangesResponse() { + Changes = new List() { new(new TupleKey { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", @@ -623,59 +628,59 @@ public async Task ReadChangesTest() { }, TupleOperation.WRITE, DateTime.Now), }, - ContinuationToken = - "eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==" - }; - mockHandler.Protected() - .Setup>( + ContinuationToken = + "eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==" + }; + mockHandler.Protected() + .Setup>( + "SendAsync", + ItExpr.Is(req => + req.RequestUri.ToString() + .StartsWith($"{_config.BasePath}/stores/{_config.StoreId}/changes") && + req.Method == HttpMethod.Get), + ItExpr.IsAny() + ) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(expectedResponse), + }); + + var httpClient = new HttpClient(mockHandler.Object); + var fgaClient = new OpenFgaClient(_config, httpClient); + + var type = "repo"; + var pageSize = 25; + var startTime = DateTime.Parse("2022-01-01T00:00:00Z"); + var continuationToken = + "eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ=="; + var response = await fgaClient.ReadChanges(new ClientReadChangesRequest { Type = type, StartTime = startTime }, new ClientReadChangesOptions { + PageSize = pageSize, + ContinuationToken = continuationToken, + }); + + mockHandler.Protected().Verify( "SendAsync", + Times.Exactly(1), ItExpr.Is(req => req.RequestUri.ToString() .StartsWith($"{_config.BasePath}/stores/{_config.StoreId}/changes") && req.Method == HttpMethod.Get), ItExpr.IsAny() - ) - .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = Utils.CreateJsonStringContent(expectedResponse), - }); + ); - var httpClient = new HttpClient(mockHandler.Object); - var fgaClient = new OpenFgaClient(_config, httpClient); - - var type = "repo"; - var pageSize = 25; - var startTime = DateTime.Parse("2022-01-01T00:00:00Z"); - var continuationToken = - "eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ=="; - var response = await fgaClient.ReadChanges(new ClientReadChangesRequest { Type = type, StartTime = startTime }, new ClientReadChangesOptions { - PageSize = pageSize, - ContinuationToken = continuationToken, - }); - - mockHandler.Protected().Verify( - "SendAsync", - Times.Exactly(1), - ItExpr.Is(req => - req.RequestUri.ToString() - .StartsWith($"{_config.BasePath}/stores/{_config.StoreId}/changes") && - req.Method == HttpMethod.Get), - ItExpr.IsAny() - ); - - Assert.IsType(response); - Assert.Single(response.Changes); - Assert.Equal(response, expectedResponse); - } + Assert.IsType(response); + Assert.Single(response.Changes); + Assert.Equal(response, expectedResponse); + } - /// - /// Test Read - /// - [Fact] - public async Task ReadTest() { - var mockHandler = new Mock(MockBehavior.Strict); - var expectedResponse = new ReadResponse() { - Tuples = new List() { + /// + /// Test Read + /// + [Fact] + public async Task ReadTest() { + var mockHandler = new Mock(MockBehavior.Strict); + var expectedResponse = new ReadResponse() { + Tuples = new List() { new(new TupleKey { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", @@ -683,55 +688,55 @@ public async Task ReadTest() { }, DateTime.Now) } - }; - mockHandler.Protected() - .Setup>( + }; + mockHandler.Protected() + .Setup>( + "SendAsync", + ItExpr.Is(req => + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/read") && + req.Method == HttpMethod.Post && + req.Content.ReadAsStringAsync().Result.Contains("tuple")), + ItExpr.IsAny() + ) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(expectedResponse), + }); + + var httpClient = new HttpClient(mockHandler.Object); + var fgaClient = new OpenFgaClient(_config, httpClient); + + var body = new ClientReadRequest() { + User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation = "viewer", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", + }; + var options = new ClientReadOptions { }; + var response = await fgaClient.Read(body, options); + + mockHandler.Protected().Verify( "SendAsync", + Times.Exactly(1), ItExpr.Is(req => req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/read") && req.Method == HttpMethod.Post && req.Content.ReadAsStringAsync().Result.Contains("tuple")), ItExpr.IsAny() - ) - .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = Utils.CreateJsonStringContent(expectedResponse), - }); - - var httpClient = new HttpClient(mockHandler.Object); - var fgaClient = new OpenFgaClient(_config, httpClient); + ); - var body = new ClientReadRequest() { - User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", - Relation = "viewer", - Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", - }; - var options = new ClientReadOptions { }; - var response = await fgaClient.Read(body, options); - - mockHandler.Protected().Verify( - "SendAsync", - Times.Exactly(1), - ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/read") && - req.Method == HttpMethod.Post && - req.Content.ReadAsStringAsync().Result.Contains("tuple")), - ItExpr.IsAny() - ); - - Assert.IsType(response); - Assert.Single(response.Tuples); - Assert.Equal(response, expectedResponse); - } + Assert.IsType(response); + Assert.Single(response.Tuples); + Assert.Equal(response, expectedResponse); + } - /// - /// Test Read with Empty Body - /// - [Fact] - public async Task ReadEmptyTest() { - var mockHandler = new Mock(MockBehavior.Strict); - var expectedResponse = new ReadResponse() { - Tuples = new List() { + /// + /// Test Read with Empty Body + /// + [Fact] + public async Task ReadEmptyTest() { + var mockHandler = new Mock(MockBehavior.Strict); + var expectedResponse = new ReadResponse() { + Tuples = new List() { new(new TupleKey { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", @@ -739,218 +744,218 @@ public async Task ReadEmptyTest() { }, DateTime.Now) } - }; - mockHandler.Protected() - .Setup>( + }; + mockHandler.Protected() + .Setup>( + "SendAsync", + ItExpr.Is(req => + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/read") && + req.Method == HttpMethod.Post && + !req.Content.ReadAsStringAsync().Result.Contains("tuple")), + ItExpr.IsAny() + ) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(expectedResponse), + }); + + var httpClient = new HttpClient(mockHandler.Object); + var fgaClient = new OpenFgaClient(_config, httpClient); + + var body = new ClientReadRequest() { }; + var options = new ClientReadOptions { }; + var response = await fgaClient.Read(body, options); + + mockHandler.Protected().Verify( "SendAsync", + Times.Exactly(1), ItExpr.Is(req => req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/read") && req.Method == HttpMethod.Post && !req.Content.ReadAsStringAsync().Result.Contains("tuple")), ItExpr.IsAny() - ) - .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = Utils.CreateJsonStringContent(expectedResponse), - }); + ); - var httpClient = new HttpClient(mockHandler.Object); - var fgaClient = new OpenFgaClient(_config, httpClient); - - var body = new ClientReadRequest() { }; - var options = new ClientReadOptions { }; - var response = await fgaClient.Read(body, options); - - mockHandler.Protected().Verify( - "SendAsync", - Times.Exactly(1), - ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/read") && - req.Method == HttpMethod.Post && - !req.Content.ReadAsStringAsync().Result.Contains("tuple")), - ItExpr.IsAny() - ); - - Assert.IsType(response); - Assert.Single(response.Tuples); - Assert.Equal(response, expectedResponse); - } + Assert.IsType(response); + Assert.Single(response.Tuples); + Assert.Equal(response, expectedResponse); + } - /// - /// Test Write (Write Relationship Tuples) - /// - [Fact] - public async Task WriteWriteTest() { - var mockHandler = new Mock(MockBehavior.Strict); - mockHandler.Protected() - .Setup>( - "SendAsync", - ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/write") && - req.Method == HttpMethod.Post), - ItExpr.IsAny() - ) - .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = Utils.CreateJsonStringContent(new Object()), - }); + /// + /// Test Write (Write Relationship Tuples) + /// + [Fact] + public async Task WriteWriteTest() { + var mockHandler = new Mock(MockBehavior.Strict); + mockHandler.Protected() + .Setup>( + "SendAsync", + ItExpr.Is(req => + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/write") && + req.Method == HttpMethod.Post), + ItExpr.IsAny() + ) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(new Object()), + }); - var httpClient = new HttpClient(mockHandler.Object); - var fgaClient = new OpenFgaClient(_config, httpClient); + var httpClient = new HttpClient(mockHandler.Object); + var fgaClient = new OpenFgaClient(_config, httpClient); - var body = new ClientWriteRequest() { - Writes = new List { + var body = new ClientWriteRequest() { + Writes = new List { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", } }, - Deletes = new List(), // should not get passed - }; - var response = await fgaClient.Write(body, new ClientWriteOptions { - AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1", - }); - - mockHandler.Protected().Verify( - "SendAsync", - Times.Exactly(1), - ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/write") && - req.Method == HttpMethod.Post), - ItExpr.IsAny() - ); - } + Deletes = new List(), // should not get passed + }; + var response = await fgaClient.Write(body, new ClientWriteOptions { + AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1", + }); - /// - /// Test Write (Delete Relationship Tuples) - /// - [Fact] - public async Task WriteDeleteTest() { - var mockHandler = new Mock(MockBehavior.Strict); - mockHandler.Protected() - .Setup>( + mockHandler.Protected().Verify( "SendAsync", + Times.Exactly(1), ItExpr.Is(req => req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/write") && req.Method == HttpMethod.Post), ItExpr.IsAny() - ) - .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = Utils.CreateJsonStringContent(new Object()), - }); + ); + } - var httpClient = new HttpClient(mockHandler.Object); - var fgaClient = new OpenFgaClient(_config, httpClient); + /// + /// Test Write (Delete Relationship Tuples) + /// + [Fact] + public async Task WriteDeleteTest() { + var mockHandler = new Mock(MockBehavior.Strict); + mockHandler.Protected() + .Setup>( + "SendAsync", + ItExpr.Is(req => + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/write") && + req.Method == HttpMethod.Post), + ItExpr.IsAny() + ) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(new Object()), + }); + + var httpClient = new HttpClient(mockHandler.Object); + var fgaClient = new OpenFgaClient(_config, httpClient); - var body = new ClientWriteRequest() { - Writes = new List { + var body = new ClientWriteRequest() { + Writes = new List { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", } }, - }; - var response = await fgaClient.Write(body, new ClientWriteOptions { - AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1", - }); - - mockHandler.Protected().Verify( - "SendAsync", - Times.Exactly(1), - ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/write") && - req.Method == HttpMethod.Post), - ItExpr.IsAny() - ); - } + }; + var response = await fgaClient.Write(body, new ClientWriteOptions { + AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1", + }); - /// - /// Test Write (Write and Delete Relationship Tuples of a Specific Authorization Model ID) - /// - [Fact] - public async Task WriteMixedWithAuthorizationModelIdTest() { - var mockHandler = new Mock(MockBehavior.Strict); - mockHandler.Protected() - .Setup>( + mockHandler.Protected().Verify( "SendAsync", + Times.Exactly(1), ItExpr.Is(req => req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/write") && req.Method == HttpMethod.Post), ItExpr.IsAny() - ) - .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = Utils.CreateJsonStringContent(new Object()), - }); + ); + } + + /// + /// Test Write (Write and Delete Relationship Tuples of a Specific Authorization Model ID) + /// + [Fact] + public async Task WriteMixedWithAuthorizationModelIdTest() { + var mockHandler = new Mock(MockBehavior.Strict); + mockHandler.Protected() + .Setup>( + "SendAsync", + ItExpr.Is(req => + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/write") && + req.Method == HttpMethod.Post), + ItExpr.IsAny() + ) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(new Object()), + }); - var httpClient = new HttpClient(mockHandler.Object); - var fgaClient = new OpenFgaClient(_config, httpClient); + var httpClient = new HttpClient(mockHandler.Object); + var fgaClient = new OpenFgaClient(_config, httpClient); - var body = new ClientWriteRequest() { - Writes = new List { + var body = new ClientWriteRequest() { + Writes = new List { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", }, }, - Deletes = new List { + Deletes = new List { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "writer", Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", } }, - }; - var response = await fgaClient.Write(body, new ClientWriteOptions { - AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1", - }); - - mockHandler.Protected().Verify( - "SendAsync", - Times.Exactly(1), - ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/write") && - req.Method == HttpMethod.Post), - ItExpr.IsAny() - ); - } + }; + var response = await fgaClient.Write(body, new ClientWriteOptions { + AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1", + }); - /// - /// Test Write (Non-transaction mode) - /// - [Fact] - public async Task WriteNonTransactionTest() { - var mockHandler = new Mock(MockBehavior.Strict); - mockHandler.Protected() - .SetupSequence>( + mockHandler.Protected().Verify( "SendAsync", + Times.Exactly(1), ItExpr.Is(req => req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/write") && req.Method == HttpMethod.Post), ItExpr.IsAny() - ) - .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = Utils.CreateJsonStringContent(new Object()), - }) - .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.NotFound, - Content = Utils.CreateJsonStringContent(new Object()), - }) - .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = Utils.CreateJsonStringContent(new Object()), - }); + ); + } + + /// + /// Test Write (Non-transaction mode) + /// + [Fact] + public async Task WriteNonTransactionTest() { + var mockHandler = new Mock(MockBehavior.Strict); + mockHandler.Protected() + .SetupSequence>( + "SendAsync", + ItExpr.Is(req => + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/write") && + req.Method == HttpMethod.Post), + ItExpr.IsAny() + ) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(new Object()), + }) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.NotFound, + Content = Utils.CreateJsonStringContent(new Object()), + }) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(new Object()), + }); - var httpClient = new HttpClient(mockHandler.Object); - var fgaClient = new OpenFgaClient(_config, httpClient); + var httpClient = new HttpClient(mockHandler.Object); + var fgaClient = new OpenFgaClient(_config, httpClient); - var body = new ClientWriteRequest() { - Writes = new List { + var body = new ClientWriteRequest() { + Writes = new List { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", @@ -962,65 +967,65 @@ public async Task WriteNonTransactionTest() { Object = "document:budget", } }, - Deletes = new List { + Deletes = new List { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "writer", Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", } }, - }; - var options = new ClientWriteOptions { - AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1", - Transaction = new TransactionOptions() { - Disable = true, - MaxParallelRequests = 1, - MaxPerChunk = 1, - } - }; - var response = await fgaClient.Write(body, options); - - mockHandler.Protected().Verify( - "SendAsync", - Times.Exactly(3), - ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/write") && - req.Method == HttpMethod.Post), - ItExpr.IsAny() - ); - Assert.IsType(response); - } + }; + var options = new ClientWriteOptions { + AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1", + Transaction = new TransactionOptions() { + Disable = true, + MaxParallelRequests = 1, + MaxPerChunk = 1, + } + }; + var response = await fgaClient.Write(body, options); - /************************ - * Relationship Queries * - ************************/ - /// - /// Test Check - /// - [Fact] - public async Task CheckTest() { - var mockHandler = new Mock(MockBehavior.Strict); - mockHandler.Protected() - .Setup>( + 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/{_config.StoreId}/write") && req.Method == HttpMethod.Post), ItExpr.IsAny() - ) - .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = Utils.CreateJsonStringContent(new CheckResponse { Allowed = true }), - }); + ); + Assert.IsType(response); + } - var httpClient = new HttpClient(mockHandler.Object); - var fgaClient = new OpenFgaClient(_config, httpClient); + /************************ + * Relationship Queries * + ************************/ + /// + /// Test Check + /// + [Fact] + public async Task CheckTest() { + var mockHandler = new Mock(MockBehavior.Strict); + mockHandler.Protected() + .Setup>( + "SendAsync", + ItExpr.Is(req => + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && + req.Method == HttpMethod.Post), + ItExpr.IsAny() + ) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(new CheckResponse { Allowed = true }), + }); - var body = new ClientCheckRequest { - User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", - Relation = "viewer", - Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", - ContextualTuples = new List() { + var httpClient = new HttpClient(mockHandler.Object); + var fgaClient = new OpenFgaClient(_config, httpClient); + + var body = new ClientCheckRequest { + User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation = "viewer", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", + ContextualTuples = new List() { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "editor", @@ -1031,52 +1036,52 @@ public async Task CheckTest() { } } }, - Context = new { ViewCount = 100 } - }; - var options = new ClientCheckOptions { }; - var response = await fgaClient.Check(body, options); - - mockHandler.Protected().Verify( - "SendAsync", - Times.Exactly(1), - ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && - req.Method == HttpMethod.Post), - ItExpr.IsAny() - ); - - Assert.IsType(response); - Assert.True(response.Allowed); - } + Context = new { ViewCount = 100 } + }; + var options = new ClientCheckOptions { }; + var response = await fgaClient.Check(body, options); - /// - /// Test Check with Consistency - /// - [Fact] - public async Task CheckWithConsistencyTest() { - var mockHandler = new Mock(MockBehavior.Strict); - mockHandler.Protected() - .Setup>( + mockHandler.Protected().Verify( "SendAsync", + Times.Exactly(1), ItExpr.Is(req => req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && - req.Method == HttpMethod.Post && - req.Content.ReadAsStringAsync().Result.Contains("MINIMIZE_LATENCY")), + req.Method == HttpMethod.Post), ItExpr.IsAny() - ) - .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = Utils.CreateJsonStringContent(new CheckResponse { Allowed = true }), - }); + ); - var httpClient = new HttpClient(mockHandler.Object); - var fgaClient = new OpenFgaClient(_config, httpClient); + Assert.IsType(response); + Assert.True(response.Allowed); + } - var body = new ClientCheckRequest { - User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", - Relation = "viewer", - Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", - ContextualTuples = new List() { + /// + /// Test Check with Consistency + /// + [Fact] + public async Task CheckWithConsistencyTest() { + var mockHandler = new Mock(MockBehavior.Strict); + mockHandler.Protected() + .Setup>( + "SendAsync", + ItExpr.Is(req => + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && + req.Method == HttpMethod.Post && + req.Content.ReadAsStringAsync().Result.Contains("MINIMIZE_LATENCY")), + ItExpr.IsAny() + ) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(new CheckResponse { Allowed = true }), + }); + + var httpClient = new HttpClient(mockHandler.Object); + var fgaClient = new OpenFgaClient(_config, httpClient); + + var body = new ClientCheckRequest { + User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation = "viewer", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", + ContextualTuples = new List() { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "editor", @@ -1087,74 +1092,74 @@ public async Task CheckWithConsistencyTest() { } } }, - Context = new { ViewCount = 100 }, - }; - var options = new ClientCheckOptions { - Consistency = ConsistencyPreference.MINIMIZELATENCY - }; - var response = await fgaClient.Check(body, options); - - mockHandler.Protected().Verify( - "SendAsync", - Times.Exactly(1), - ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && - req.Method == HttpMethod.Post && - req.Content.ReadAsStringAsync().Result.Contains("MINIMIZE_LATENCY")), - ItExpr.IsAny() - ); - - Assert.IsType(response); - Assert.True(response.Allowed); - } - /// - /// Test BatchCheck - /// - [Fact] - public async Task BatchCheckTest() { - var mockHandler = new Mock(MockBehavior.Strict); - mockHandler.Protected() - .SetupSequence>( + Context = new { ViewCount = 100 }, + }; + var options = new ClientCheckOptions { + Consistency = ConsistencyPreference.MINIMIZELATENCY + }; + var response = await fgaClient.Check(body, options); + + mockHandler.Protected().Verify( "SendAsync", + Times.Exactly(1), ItExpr.Is(req => req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && req.Method == HttpMethod.Post && - req.Content.ReadAsStringAsync().Result.Contains("HIGHER_CONSISTENCY")), + req.Content.ReadAsStringAsync().Result.Contains("MINIMIZE_LATENCY")), ItExpr.IsAny() - ) - .Returns(Task.Run(async () => { - await Task.Delay(500); - return new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = Utils.CreateJsonStringContent(new CheckResponse { Allowed = true }), - }; - })) - .Returns(Task.Run(async () => { - await Task.Delay(500); - return new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = Utils.CreateJsonStringContent(new CheckResponse { Allowed = false }), - }; - })) - .Returns(Task.Run(async () => { - await Task.Delay(500); - return new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = Utils.CreateJsonStringContent(new CheckResponse { Allowed = true }), - }; - })) - .Returns(Task.Run(async () => { - await Task.Delay(500); - return new HttpResponseMessage() { - StatusCode = HttpStatusCode.NotFound, - Content = Utils.CreateJsonStringContent(new Object { }), - }; - })); + ); - var httpClient = new HttpClient(mockHandler.Object); - var fgaClient = new OpenFgaClient(_config, httpClient); - - var body = new List(){ + Assert.IsType(response); + Assert.True(response.Allowed); + } + /// + /// Test BatchCheck + /// + [Fact] + public async Task BatchCheckTest() { + var mockHandler = new Mock(MockBehavior.Strict); + mockHandler.Protected() + .SetupSequence>( + "SendAsync", + ItExpr.Is(req => + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && + req.Method == HttpMethod.Post && + req.Content.ReadAsStringAsync().Result.Contains("HIGHER_CONSISTENCY")), + ItExpr.IsAny() + ) + .Returns(Task.Run(async () => { + await Task.Delay(500); + return new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(new CheckResponse { Allowed = true }), + }; + })) + .Returns(Task.Run(async () => { + await Task.Delay(500); + return new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(new CheckResponse { Allowed = false }), + }; + })) + .Returns(Task.Run(async () => { + await Task.Delay(500); + return new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(new CheckResponse { Allowed = true }), + }; + })) + .Returns(Task.Run(async () => { + await Task.Delay(500); + return new HttpResponseMessage() { + StatusCode = HttpStatusCode.NotFound, + Content = Utils.CreateJsonStringContent(new Object { }), + }; + })); + + var httpClient = new HttpClient(mockHandler.Object); + var fgaClient = new OpenFgaClient(_config, httpClient); + + var body = new List(){ new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", @@ -1190,182 +1195,190 @@ public async Task BatchCheckTest() { Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", } }; - var options = new ClientBatchCheckOptions { - Consistency = ConsistencyPreference.HIGHERCONSISTENCY - }; - var response = await fgaClient.BatchCheck(body, options); - - mockHandler.Protected().Verify( - "SendAsync", - Times.Exactly(4), - ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && - req.Method == HttpMethod.Post && - req.Content.ReadAsStringAsync().Result.Contains("HIGHER_CONSISTENCY")), - ItExpr.IsAny() - ); - - Assert.IsType(response); - - var allowedResponses = response.Responses.FindAll(res => res.Allowed); - Assert.Equal(2, allowedResponses.Count); - var notAllowedResponses = response.Responses.FindAll(res => res.Allowed == false); - Assert.Equal(2, notAllowedResponses.Count); - var failedResponses = response.Responses.FindAll(res => res.Error != null); - Assert.Single(failedResponses); - } + var options = new ClientBatchCheckOptions { + Consistency = ConsistencyPreference.HIGHERCONSISTENCY + }; + var response = await fgaClient.BatchCheck(body, options); - /// - /// Test Expand - /// - [Fact] - public async Task ExpandTest() { - var mockHandler = new Mock(MockBehavior.Strict); - - var jsonResponse = - "{\"tree\":{\"root\":{\"name\":\"document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#owner\", \"union\":{\"nodes\":[{\"name\":\"document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#owner\", \"leaf\":{\"users\":{\"users\":[\"team:product#member\"]}}}, {\"name\":\"document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#owner\", \"leaf\":{\"tupleToUserset\":{\"tupleset\":\"document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#owner\", \"computed\":[{\"userset\":\"org:contoso#admin\"}]}}}]}}}}"; - mockHandler.Protected() - .Setup>( + mockHandler.Protected().Verify( "SendAsync", + Times.Exactly(4), ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/expand") && + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && req.Method == HttpMethod.Post && req.Content.ReadAsStringAsync().Result.Contains("HIGHER_CONSISTENCY")), ItExpr.IsAny() - ) - .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = new StringContent(jsonResponse, Encoding.UTF8, "application/json"), + ); + + Assert.IsType(response); + + var allowedResponses = response.Responses.FindAll(res => res.Allowed); + Assert.Equal(2, allowedResponses.Count); + var notAllowedResponses = response.Responses.FindAll(res => res.Allowed == false); + Assert.Equal(2, notAllowedResponses.Count); + var failedResponses = response.Responses.FindAll(res => res.Error != null); + Assert.Single(failedResponses); + } + + /// + /// Test Expand + /// + [Fact] + public async Task ExpandTest() { + var mockHandler = new Mock(MockBehavior.Strict); + + var jsonResponse = + "{\"tree\":{\"root\":{\"name\":\"document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#owner\", \"union\":{\"nodes\":[{\"name\":\"document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#owner\", \"leaf\":{\"users\":{\"users\":[\"team:product#member\"]}}}, {\"name\":\"document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#owner\", \"leaf\":{\"tupleToUserset\":{\"tupleset\":\"document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#owner\", \"computed\":[{\"userset\":\"org:contoso#admin\"}]}}}]}}}}"; + mockHandler.Protected() + .Setup>( + "SendAsync", + ItExpr.Is(req => + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/expand") && + req.Method == HttpMethod.Post && + req.Content.ReadAsStringAsync().Result.Contains("HIGHER_CONSISTENCY")), + ItExpr.IsAny() + ) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = new StringContent(jsonResponse, Encoding.UTF8, "application/json"), + }); + + var httpClient = new HttpClient(mockHandler.Object); + var fgaClient = new OpenFgaClient(_config, httpClient); + + var body = new ClientExpandRequest { + Relation = "viewer", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", + ContextualTuples = new List() { + new() { + User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation = "editor", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", + } + }, + }; + var response = await fgaClient.Expand(body, new ClientExpandOptions() { + AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1", + Consistency = ConsistencyPreference.HIGHERCONSISTENCY }); - var httpClient = new HttpClient(mockHandler.Object); - var fgaClient = new OpenFgaClient(_config, httpClient); + mockHandler.Protected().Verify( + "SendAsync", + Times.Exactly(1), + ItExpr.Is(req => + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/expand") && + req.Method == HttpMethod.Post && + req.Content.ReadAsStringAsync().Result.Contains("HIGHER_CONSISTENCY") && + req.Content.ReadAsStringAsync().Result.Contains("user:81684243-9356-4421-8fbf-a4f8d36aa31b")), + ItExpr.IsAny() + ); - var body = new ClientExpandRequest { - Relation = "viewer", - Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", - }; - var response = await fgaClient.Expand(body, new ClientExpandOptions() { - AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1", - Consistency = ConsistencyPreference.HIGHERCONSISTENCY - }); - - mockHandler.Protected().Verify( - "SendAsync", - Times.Exactly(1), - ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/expand") && - req.Method == HttpMethod.Post && - req.Content.ReadAsStringAsync().Result.Contains("HIGHER_CONSISTENCY")), - ItExpr.IsAny() - ); - - Assert.IsType(response); - ExpandResponse expectedResponse = JsonSerializer.Deserialize(jsonResponse); - Assert.Equal(response, expectedResponse); - } + Assert.IsType(response); + ExpandResponse expectedResponse = JsonSerializer.Deserialize(jsonResponse); + Assert.Equal(response, expectedResponse); + } - /// - /// Test Expand with Complex Response - /// - [Fact] - public async Task ExpandComplexResponseTest() { - var mockHandler = new Mock(MockBehavior.Strict); - var mockResponse = new ExpandResponse( - tree: new UsersetTree( - root: new Node(name: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a1#owner", - union: new Nodes( - nodes: new List() { + /// + /// Test Expand with Complex Response + /// + [Fact] + public async Task ExpandComplexResponseTest() { + var mockHandler = new Mock(MockBehavior.Strict); + var mockResponse = new ExpandResponse( + tree: new UsersetTree( + root: new Node(name: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a1#owner", + union: new Nodes( + nodes: new List() { new Node(name: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a2#owner", leaf: new Leaf(users: new Users(users: new List() {"team:product#member"}))), new Node(name: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a3#owner", leaf: new Leaf(tupleToUserset: new UsersetTreeTupleToUserset( tupleset: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#owner", computed: new List() {new Computed(userset: "org:contoso#admin")}))), - }), - difference: new UsersetTreeDifference( - _base: new Node(name: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a3#owner", - leaf: new Leaf(users: new Users(users: new List() { "team:product#member" }))), - subtract: new Node(name: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a4#owner", - leaf: new Leaf(users: new Users(users: new List() { "team:product#member" }))) - ), - intersection: new Nodes( - nodes: new List() { + }), + difference: new UsersetTreeDifference( + _base: new Node(name: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a3#owner", + leaf: new Leaf(users: new Users(users: new List() { "team:product#member" }))), + subtract: new Node(name: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a4#owner", + leaf: new Leaf(users: new Users(users: new List() { "team:product#member" }))) + ), + intersection: new Nodes( + nodes: new List() { new Node(name: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a5#owner", leaf: new Leaf(users: new Users(users: new List() {"team:product#commentor"}))), new Node(name: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a6#owner", leaf: new Leaf(tupleToUserset: new UsersetTreeTupleToUserset( tupleset: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#viewer", computed: new List() {new Computed(userset: "org:contoso#owner")}))), - })) - )); + })) + )); + + mockHandler.Protected() + .Setup>( + "SendAsync", + ItExpr.Is(req => + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/expand") && + req.Method == HttpMethod.Post), + ItExpr.IsAny() + ) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(mockResponse), + }); + + var httpClient = new HttpClient(mockHandler.Object); + var fgaClient = new OpenFgaClient(_config, httpClient); + + var body = new ClientExpandRequest { + Relation = "viewer", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", + }; + var response = await fgaClient.Expand(body, new ClientExpandOptions { + AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1", + }); - mockHandler.Protected() - .Setup>( + mockHandler.Protected().Verify( "SendAsync", + Times.Exactly(1), ItExpr.Is(req => req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/expand") && req.Method == HttpMethod.Post), ItExpr.IsAny() - ) - .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = Utils.CreateJsonStringContent(mockResponse), - }); - - var httpClient = new HttpClient(mockHandler.Object); - var fgaClient = new OpenFgaClient(_config, httpClient); + ); - var body = new ClientExpandRequest { - Relation = "viewer", - Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", - }; - var response = await fgaClient.Expand(body, new ClientExpandOptions { - AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1", - }); - - mockHandler.Protected().Verify( - "SendAsync", - Times.Exactly(1), - ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/expand") && - req.Method == HttpMethod.Post), - ItExpr.IsAny() - ); - - Assert.IsType(response); - Assert.Equal(response, mockResponse); - } + Assert.IsType(response); + Assert.Equal(response, mockResponse); + } - /// - /// Test ListObjects - /// - [Fact] - public async Task ListObjectsTest() { - var mockHandler = new Mock(MockBehavior.Strict); - var expectedResponse = new ListObjectsResponse { Objects = new List { "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" } }; - mockHandler.Protected() - .Setup>( - "SendAsync", - ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/list-objects") && - req.Method == HttpMethod.Post && - req.Content.ReadAsStringAsync().Result.Contains("HIGHER_CONSISTENCY")), - ItExpr.IsAny() - ) - .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = Utils.CreateJsonStringContent(expectedResponse), - }); + /// + /// Test ListObjects + /// + [Fact] + public async Task ListObjectsTest() { + var mockHandler = new Mock(MockBehavior.Strict); + var expectedResponse = new ListObjectsResponse { Objects = new List { "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" } }; + mockHandler.Protected() + .Setup>( + "SendAsync", + ItExpr.Is(req => + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/list-objects") && + req.Method == HttpMethod.Post && + req.Content.ReadAsStringAsync().Result.Contains("HIGHER_CONSISTENCY")), + ItExpr.IsAny() + ) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(expectedResponse), + }); - var httpClient = new HttpClient(mockHandler.Object); - var fgaClient = new OpenFgaClient(_config, httpClient); + var httpClient = new HttpClient(mockHandler.Object); + var fgaClient = new OpenFgaClient(_config, httpClient); - var body = new ClientListObjectsRequest { - User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", - Relation = "can_read", - Type = "document", - ContextualTuples = new List { + var body = new ClientListObjectsRequest { + User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation = "can_read", + Type = "document", + ContextualTuples = new List { new() { User = "folder:product", Relation = "editor", @@ -1377,145 +1390,209 @@ public async Task ListObjectsTest() { Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", }, }, - }; - var response = await fgaClient.ListObjects(body, new ClientListObjectsOptions { - AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1", - Consistency = ConsistencyPreference.HIGHERCONSISTENCY - }); - - mockHandler.Protected().Verify( - "SendAsync", - Times.Exactly(1), - ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/list-objects") && - req.Method == HttpMethod.Post && - req.Content.ReadAsStringAsync().Result.Contains("HIGHER_CONSISTENCY")), - ItExpr.IsAny() - ); - - Assert.IsType(response); - Assert.Single(response.Objects); - Assert.Equal(response, expectedResponse); - } + }; + var response = await fgaClient.ListObjects(body, new ClientListObjectsOptions { + AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1", + Consistency = ConsistencyPreference.HIGHERCONSISTENCY + }); + + mockHandler.Protected().Verify( + "SendAsync", + Times.Exactly(1), + ItExpr.Is(req => + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/list-objects") && + req.Method == HttpMethod.Post && + req.Content.ReadAsStringAsync().Result.Contains("HIGHER_CONSISTENCY")), + ItExpr.IsAny() + ); + + Assert.IsType(response); + Assert.Single(response.Objects); + Assert.Equal(response, expectedResponse); + } + + /// + /// Test ListRelations + /// + [Fact] + public async Task ListRelationsTest() { + var mockHandler = new Mock(MockBehavior.Strict); + mockHandler.Protected() + .SetupSequence>( + "SendAsync", + ItExpr.Is(req => + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && + req.Method == HttpMethod.Post && + req.Content.ReadAsStringAsync().Result.Contains("MINIMIZE_LATENCY")), + ItExpr.IsAny() + ) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(new CheckResponse { Allowed = true }), + }) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(new CheckResponse { Allowed = false }), + }) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(new CheckResponse { Allowed = true }), + }) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(new CheckResponse { Allowed = false }), + }); + + var httpClient = new HttpClient(mockHandler.Object); + var fgaClient = new OpenFgaClient(_config, httpClient); + + var body = + new ClientListRelationsRequest() { + User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", + Relations = new List { "can_view", "can_edit", "can_delete", "can_rename" }, + ContextualTuples = new List() { + new() { + User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation = "editor", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", + } + } + }; + var options = new ClientListRelationsOptions { Consistency = ConsistencyPreference.MINIMIZELATENCY }; + var response = await fgaClient.ListRelations(body, options); - /// - /// Test ListRelations - /// - [Fact] - public async Task ListRelationsTest() { - var mockHandler = new Mock(MockBehavior.Strict); - mockHandler.Protected() - .SetupSequence>( + mockHandler.Protected().Verify( "SendAsync", + Times.Exactly(4), ItExpr.Is(req => req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && req.Method == HttpMethod.Post && req.Content.ReadAsStringAsync().Result.Contains("MINIMIZE_LATENCY")), ItExpr.IsAny() - ) - .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = Utils.CreateJsonStringContent(new CheckResponse { Allowed = true }), - }) - .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = Utils.CreateJsonStringContent(new CheckResponse { Allowed = false }), - }) - .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = Utils.CreateJsonStringContent(new CheckResponse { Allowed = true }), - }) - .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.NotFound, - Content = Utils.CreateJsonStringContent(new Object { }), - }); + ); - var httpClient = new HttpClient(mockHandler.Object); - var fgaClient = new OpenFgaClient(_config, httpClient); + Assert.IsType(response); + Assert.Equal(2, response.Relations.Count); + // TODO: Ensure the relations are correct, currently because the mocks are generic and we process in parallel, + // we do not know what order they will be processed in + } - var body = - new ClientListRelationsRequest() { - User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", - Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", - Relations = new List { "can_view", "can_edit", "can_delete", "can_rename" }, - ContextualTuples = new List() { + /// + /// Test ListRelations: One of the relations is not found + /// + [Fact] + public async Task ListRelationsRelationNotFoundTest() { + var mockHandler = new Mock(MockBehavior.Strict); + mockHandler.Protected() + .SetupSequence>( + "SendAsync", + ItExpr.Is(req => + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && + req.Method == HttpMethod.Post && + req.Content.ReadAsStringAsync().Result.Contains("MINIMIZE_LATENCY")), + ItExpr.IsAny() + ) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(new CheckResponse { Allowed = true }), + }) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(new CheckResponse { Allowed = false }), + }) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(new CheckResponse { Allowed = true }), + }) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.NotFound, + Content = Utils.CreateJsonStringContent(new Object { }), + }); + + var httpClient = new HttpClient(mockHandler.Object); + var fgaClient = new OpenFgaClient(_config, httpClient); + + var body = + new ClientListRelationsRequest() { + User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", + Relations = new List { "can_view", "can_edit", "can_delete", "can_rename" }, + ContextualTuples = new List() { new() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "editor", Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", } - } - }; - var options = new ClientListRelationsOptions { Consistency = ConsistencyPreference.MINIMIZELATENCY }; - var response = await fgaClient.ListRelations(body, options); - - mockHandler.Protected().Verify( - "SendAsync", - Times.Exactly(4), - ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && - req.Method == HttpMethod.Post && - req.Content.ReadAsStringAsync().Result.Contains("MINIMIZE_LATENCY")), - ItExpr.IsAny() - ); - - Assert.IsType(response); - Assert.Equal(2, response.Relations.Count); - // TODO: Ensure the relations are correct, currently because the mocks are generic and we process in parallel, - // we do not know what order they will be processed in - } + } + }; + var options = new ClientListRelationsOptions { Consistency = ConsistencyPreference.MINIMIZELATENCY }; + Task ApiError() => fgaClient.ListRelations(body, options); + var error = await Assert.ThrowsAsync(ApiError); - /// - /// Test ListRelationsNoRelationsProvided - /// - [Fact] - public async Task ListRelationsNoRelationsProvidedTest() { - var mockHandler = new Mock(MockBehavior.Strict); - mockHandler.Protected() - .Setup>( + mockHandler.Protected().Verify( "SendAsync", + Times.Exactly(4), ItExpr.Is(req => req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && - req.Method == HttpMethod.Post), + req.Method == HttpMethod.Post && + req.Content.ReadAsStringAsync().Result.Contains("MINIMIZE_LATENCY")), ItExpr.IsAny() - ) - .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = Utils.CreateJsonStringContent(new CheckResponse { Allowed = true }), - }); + ); + } - var httpClient = new HttpClient(mockHandler.Object); - var fgaClient = new OpenFgaClient(_config, httpClient); + /// + /// Test ListRelationsNoRelationsProvided + /// + [Fact] + public async Task ListRelationsNoRelationsProvidedTest() { + var mockHandler = new Mock(MockBehavior.Strict); + mockHandler.Protected() + .Setup>( + "SendAsync", + ItExpr.Is(req => + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && + req.Method == HttpMethod.Post), + ItExpr.IsAny() + ) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(new CheckResponse { Allowed = true }), + }); - var body = - new ClientListRelationsRequest() { - User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", - Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", - Relations = new List { }, - }; + var httpClient = new HttpClient(mockHandler.Object); + var fgaClient = new OpenFgaClient(_config, httpClient); - Task ApiError() => fgaClient.ListRelations(body); - var error = await Assert.ThrowsAsync(ApiError); - Assert.Equal("At least 1 relation to check has to be provided when calling ListRelations", error.Message); - - mockHandler.Protected().Verify( - "SendAsync", - Times.Exactly(0), - ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && - req.Method == HttpMethod.Post), - ItExpr.IsAny() - ); - } - /// - /// Test ListUsers - /// - [Fact] - public async Task ListUsersTest() { - var mockHandler = new Mock(MockBehavior.Strict); - var expectedResponse = new ListUsersResponse { - // A real API would not return all these for the filter provided, these are just for test purposes - Users = new List { + var body = + new ClientListRelationsRequest() { + User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", + Relations = new List { }, + }; + + Task ApiError() => fgaClient.ListRelations(body); + var error = await Assert.ThrowsAsync(ApiError); + Assert.Equal("At least 1 relation to check has to be provided when calling ListRelations", error.Message); + + mockHandler.Protected().Verify( + "SendAsync", + Times.Exactly(0), + ItExpr.Is(req => + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/check") && + req.Method == HttpMethod.Post), + ItExpr.IsAny() + ); + } + + /// + /// Test ListUsers + /// + [Fact] + public async Task ListUsersTest() { + var mockHandler = new Mock(MockBehavior.Strict); + var expectedResponse = new ListUsersResponse { + // A real API would not return all these for the filter provided, these are just for test purposes + Users = new List { new User() { Object = new FgaObject { Type = "user", @@ -1536,30 +1613,30 @@ public async Task ListUsersTest() { } }, - }; - mockHandler.Protected() - .Setup>( - "SendAsync", - ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/list-users") && - req.Method == HttpMethod.Post), - ItExpr.IsAny() - ) - .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = Utils.CreateJsonStringContent(expectedResponse), - }); + }; + mockHandler.Protected() + .Setup>( + "SendAsync", + ItExpr.Is(req => + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/list-users") && + req.Method == HttpMethod.Post), + ItExpr.IsAny() + ) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(expectedResponse), + }); - var httpClient = new HttpClient(mockHandler.Object); - var fgaClient = new OpenFgaClient(_config, httpClient); + var httpClient = new HttpClient(mockHandler.Object); + var fgaClient = new OpenFgaClient(_config, httpClient); - var body = new ClientListUsersRequest { - Relation = "can_read", - Object = new FgaObject { - Type = "document", - Id = "roadmap" - }, - UserFilters = new List { + var body = new ClientListUsersRequest { + Relation = "can_read", + Object = new FgaObject { + Type = "document", + Id = "roadmap" + }, + UserFilters = new List { // API does not allow sending multiple filters, done here for testing purposes new() { Type = "user" @@ -1569,7 +1646,7 @@ public async Task ListUsersTest() { Relation = "member" } }, - ContextualTuples = new List { + ContextualTuples = new List { new() { User = "folder:product", Relation = "editor", @@ -1581,116 +1658,117 @@ public async Task ListUsersTest() { Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", }, }, - Context = new { ViewCount = 100 } - }; - - var response = await fgaClient.ListUsers(body, new ClientListUsersOptions { - AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1", - }); - - mockHandler.Protected().Verify( - "SendAsync", - Times.Exactly(1), - ItExpr.Is(req => - req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/list-users") && - req.Method == HttpMethod.Post), - ItExpr.IsAny() - ); - - Assert.IsType(response); - Assert.Equal(3, response.Users.Count); - Assert.Equal(response, expectedResponse); - } - - /************** - * Assertions * - **************/ + Context = new { ViewCount = 100 } + }; - /// - /// Test ReadAssertions - /// - [Fact] - public async Task ReadAssertionsTest() { - const string authorizationModelId = "01FMJA27YCE3QAT8RDS9VZFN0T"; + var response = await fgaClient.ListUsers(body, new ClientListUsersOptions { + AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1", + }); - var mockHandler = new Mock(MockBehavior.Strict); - mockHandler.Protected() - .Setup>( + mockHandler.Protected().Verify( "SendAsync", + Times.Exactly(1), ItExpr.Is(req => - req.RequestUri == - new Uri($"{_config.BasePath}/stores/{_config.StoreId}/assertions/{authorizationModelId}") && - req.Method == HttpMethod.Get), + req.RequestUri == new Uri($"{_config.BasePath}/stores/{_storeId}/list-users") && + req.Method == HttpMethod.Post), ItExpr.IsAny() - ) - .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = Utils.CreateJsonStringContent(new ReadAssertionsResponse(authorizationModelId, - assertions: new List())), - }); + ); - var httpClient = new HttpClient(mockHandler.Object); - var fgaClient = new OpenFgaClient(_config, httpClient); - - var response = await fgaClient.ReadAssertions(new ClientReadAssertionsOptions { - AuthorizationModelId = authorizationModelId, - }); - - mockHandler.Protected().Verify( - "SendAsync", - Times.Exactly(1), - ItExpr.Is(req => - req.RequestUri == - new Uri($"{_config.BasePath}/stores/{_config.StoreId}/assertions/{authorizationModelId}") && - req.Method == HttpMethod.Get), - ItExpr.IsAny() - ); - - Assert.IsType(response); - Assert.Equal(authorizationModelId, response.AuthorizationModelId); - Assert.Empty(response.Assertions); - } + Assert.IsType(response); + Assert.Equal(3, response.Users.Count); + Assert.Equal(response, expectedResponse); + } + + /************** + * Assertions * + **************/ + + /// + /// Test ReadAssertions + /// + [Fact] + public async Task ReadAssertionsTest() { + const string authorizationModelId = "01FMJA27YCE3QAT8RDS9VZFN0T"; + + var mockHandler = new Mock(MockBehavior.Strict); + mockHandler.Protected() + .Setup>( + "SendAsync", + ItExpr.Is(req => + req.RequestUri == + new Uri($"{_config.BasePath}/stores/{_config.StoreId}/assertions/{authorizationModelId}") && + req.Method == HttpMethod.Get), + ItExpr.IsAny() + ) + .ReturnsAsync(new HttpResponseMessage() { + StatusCode = HttpStatusCode.OK, + Content = Utils.CreateJsonStringContent(new ReadAssertionsResponse(authorizationModelId, + assertions: new List())), + }); + + var httpClient = new HttpClient(mockHandler.Object); + var fgaClient = new OpenFgaClient(_config, httpClient); + + var response = await fgaClient.ReadAssertions(new ClientReadAssertionsOptions { + AuthorizationModelId = authorizationModelId, + }); - /// - /// Test WriteAssertions - /// - [Fact] - public async Task WriteAssertionsTest() { - const string authorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1"; - var mockHandler = new Mock(MockBehavior.Strict); - mockHandler.Protected() - .Setup>( + mockHandler.Protected().Verify( "SendAsync", + Times.Exactly(1), ItExpr.Is(req => req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/assertions/{authorizationModelId}") && - req.Method == HttpMethod.Put), + req.Method == HttpMethod.Get), ItExpr.IsAny() - ) - .ReturnsAsync(new HttpResponseMessage() { StatusCode = HttpStatusCode.NoContent, }); + ); - var httpClient = new HttpClient(mockHandler.Object); - var fgaClient = new OpenFgaClient(_config, httpClient); + Assert.IsType(response); + Assert.Equal(authorizationModelId, response.AuthorizationModelId); + Assert.Empty(response.Assertions); + } - var body = new List() {new ClientAssertion() { + /// + /// Test WriteAssertions + /// + [Fact] + public async Task WriteAssertionsTest() { + const string authorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1"; + var mockHandler = new Mock(MockBehavior.Strict); + mockHandler.Protected() + .Setup>( + "SendAsync", + ItExpr.Is(req => + req.RequestUri == + new Uri($"{_config.BasePath}/stores/{_config.StoreId}/assertions/{authorizationModelId}") && + req.Method == HttpMethod.Put), + ItExpr.IsAny() + ) + .ReturnsAsync(new HttpResponseMessage() { StatusCode = HttpStatusCode.NoContent, }); + + var httpClient = new HttpClient(mockHandler.Object); + var fgaClient = new OpenFgaClient(_config, httpClient); + + var body = new List() {new ClientAssertion() { User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b", Relation = "viewer", Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", Expectation = true, }}; - await fgaClient.WriteAssertions(body, new ClientWriteAssertionsOptions { - AuthorizationModelId = authorizationModelId, - }); - - mockHandler.Protected().Verify( - "SendAsync", - Times.Exactly(1), - ItExpr.Is(req => - req.RequestUri == - new Uri($"{_config.BasePath}/stores/{_config.StoreId}/assertions/{authorizationModelId}") && - req.Method == HttpMethod.Put), - ItExpr.IsAny() - ); + await fgaClient.WriteAssertions(body, new ClientWriteAssertionsOptions { + AuthorizationModelId = authorizationModelId, + }); + + mockHandler.Protected().Verify( + "SendAsync", + Times.Exactly(1), + ItExpr.Is(req => + req.RequestUri == + new Uri($"{_config.BasePath}/stores/{_config.StoreId}/assertions/{authorizationModelId}") && + req.Method == HttpMethod.Put), + ItExpr.IsAny() + ); + } } } \ No newline at end of file diff --git a/src/OpenFga.Sdk.Test/Models/Client/ClientBatchCheckResponseTest.cs b/src/OpenFga.Sdk.Test/Models/Client/ClientBatchCheckResponseTest.cs new file mode 100644 index 0000000..d36beb1 --- /dev/null +++ b/src/OpenFga.Sdk.Test/Models/Client/ClientBatchCheckResponseTest.cs @@ -0,0 +1,48 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 1.x +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://openfga.dev/community +// 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.Client.Model; +using System.Collections.Generic; +using Xunit; + +public class ClientBatchCheckClientResponseTests { + [Fact] + public void Equals_ReturnsTrue_WhenResponsesAreEqual() { + var response1 = new BatchCheckSingleResponse(true, new ClientCheckRequest(), null); + var response2 = new BatchCheckSingleResponse(true, new ClientCheckRequest(), null); + var clientResponse1 = new ClientBatchCheckClientResponse(new List { response1 }); + var clientResponse2 = new ClientBatchCheckClientResponse(new List { response2 }); + + Assert.True(clientResponse1.Equals(clientResponse2)); + } + + [Fact] + public void Equals_ReturnsFalse_WhenResponsesAreNotEqual() { + var response1 = new BatchCheckSingleResponse(true, new ClientCheckRequest(), null); + var response2 = new BatchCheckSingleResponse(false, new ClientCheckRequest(), null); + var clientResponse1 = new ClientBatchCheckClientResponse(new List { response1 }); + var clientResponse2 = new ClientBatchCheckClientResponse(new List { response2 }); + + Assert.False(clientResponse1.Equals(clientResponse2)); + } + + [Fact] + public void AppendResponse_AddsResponseToList() { + var clientResponse = new ClientBatchCheckClientResponse(); + var response = new BatchCheckSingleResponse(true, new ClientCheckRequest(), null); + + clientResponse.AppendResponse(response); + + Assert.Contains(response, clientResponse.Responses); + } +} \ No newline at end of file diff --git a/src/OpenFga.Sdk.Test/OpenFga.Sdk.Test.csproj b/src/OpenFga.Sdk.Test/OpenFga.Sdk.Test.csproj index 37b71ab..071fabb 100644 --- a/src/OpenFga.Sdk.Test/OpenFga.Sdk.Test.csproj +++ b/src/OpenFga.Sdk.Test/OpenFga.Sdk.Test.csproj @@ -7,28 +7,26 @@ net6.0 false disable - 10.0 + 9.0 + NETSTANDARD2_0 - all - all - all - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers - - b8d9e3e9-0156-4948-9de7-5e0d3f9c4d9e - OpenFga.Sdk - + - + \ No newline at end of file diff --git a/src/OpenFga.Sdk/Api/OpenFgaApi.cs b/src/OpenFga.Sdk/Api/OpenFgaApi.cs index c07fe6e..292ed23 100644 --- a/src/OpenFga.Sdk/Api/OpenFgaApi.cs +++ b/src/OpenFga.Sdk/Api/OpenFgaApi.cs @@ -480,7 +480,8 @@ public async Task ReadAuthorizationModel(string queryParams.Add("continuation_token", continuationToken.ToString()); } if (startTime != null) { - queryParams.Add("start_time", startTime.ToString()); + // call the specific date time stringify + queryParams.Add("start_time", startTime?.ToString("O")); } var requestBuilder = new RequestBuilder { diff --git a/src/OpenFga.Sdk/Client/Client.cs b/src/OpenFga.Sdk/Client/Client.cs index cc676d5..970b763 100644 --- a/src/OpenFga.Sdk/Client/Client.cs +++ b/src/OpenFga.Sdk/Client/Client.cs @@ -457,6 +457,11 @@ await api.Expand( GetStoreId(options), new ExpandRequest { TupleKey = new ExpandRequestTupleKey { Relation = body.Relation, Object = body.Object }, + ContextualTuples = + new ContextualTupleKeys { + TupleKeys = body.ContextualTuples?.ConvertAll(tupleKey => tupleKey.ToTupleKey()) ?? + new List() + }, AuthorizationModelId = GetAuthorizationModelId(options), Consistency = options?.Consistency }, cancellationToken); @@ -507,8 +512,12 @@ public async Task ListRelations(IClientListRelationsReque var batchCheckResponse = await BatchCheck(batchCheckRequests, options, cancellationToken); - for (var index = 0; index < batchCheckResponse.Responses.Count; index++) { - var batchCheckSingleResponse = batchCheckResponse.Responses[index]; + + foreach (var batchCheckSingleResponse in batchCheckResponse.Responses) { + if (batchCheckSingleResponse.Error != null) { + throw batchCheckSingleResponse.Error; + } + if (batchCheckSingleResponse.Allowed && batchCheckSingleResponse.Request?.Relation != null) { responses.AddRelation(batchCheckSingleResponse.Request.Relation); } diff --git a/src/OpenFga.Sdk/Client/Model/ClientBatchCheckResponse.cs b/src/OpenFga.Sdk/Client/Model/ClientBatchCheckResponse.cs index 4531d5a..b08cc46 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientBatchCheckResponse.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientBatchCheckResponse.cs @@ -49,6 +49,7 @@ public BatchCheckSingleResponse() { } [JsonPropertyName("error")] public Exception? Error { get; set; } + /// /// Returns true if objects are equal /// @@ -93,6 +94,7 @@ public override int GetHashCode() { return hashCode; } + } public IEnumerable Validate(ValidationContext validationContext) { @@ -123,6 +125,7 @@ public ClientBatchCheckClientResponse(List responses) [JsonPropertyName("responses")] public List Responses { get; set; } + /// /// Returns true if objects are equal /// @@ -171,6 +174,7 @@ public override int GetHashCode() { return hashCode; } + } public IEnumerable Validate(ValidationContext validationContext) { diff --git a/src/OpenFga.Sdk/Client/Model/ClientExpandRequest.cs b/src/OpenFga.Sdk/Client/Model/ClientExpandRequest.cs index 4ef9acf..9439edf 100644 --- a/src/OpenFga.Sdk/Client/Model/ClientExpandRequest.cs +++ b/src/OpenFga.Sdk/Client/Model/ClientExpandRequest.cs @@ -25,6 +25,8 @@ public interface IClientExpandRequest { /// Object /// public string Object { get; set; } + + public List? ContextualTuples { get; set; } } /// @@ -40,6 +42,13 @@ public class ClientExpandRequest : IClientExpandRequest, IEquatable + /// Gets or Sets Contextual Tuples + /// + [DataMember(Name = "contextual_tuples", EmitDefaultValue = false)] + [JsonPropertyName("contextual_tuples")] + public List? ContextualTuples { get; set; } + public bool Equals(ClientExpandRequest input) { if (input == null) { return false; @@ -55,6 +64,11 @@ public bool Equals(ClientExpandRequest input) { Object == input.Object || (Object != null && Object.Equals(input.Object)) + ) && + ( + ContextualTuples == input.ContextualTuples || + (ContextualTuples != null && + ContextualTuples.Equals(input.ContextualTuples)) ); } @@ -81,6 +95,10 @@ public override int GetHashCode() { hashCode = (hashCode * 9923) + Object.GetHashCode(); } + if (ContextualTuples != null) { + hashCode = (hashCode * 9923) + ContextualTuples.GetHashCode(); + } + return hashCode; } } diff --git a/src/OpenFga.Sdk/Client/Model/ClientListStoresRequest.cs b/src/OpenFga.Sdk/Client/Model/ClientListStoresRequest.cs new file mode 100644 index 0000000..3462f89 --- /dev/null +++ b/src/OpenFga.Sdk/Client/Model/ClientListStoresRequest.cs @@ -0,0 +1,67 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 1.x +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://openfga.dev/community +// 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 IClientListStoresRequest { + public string? Name { get; set; } +} + +/// +/// ClientListStoresRequest +/// +public class ClientListStoresRequest : IClientListStoresRequest, IEquatable, + IValidatableObject { + /// + /// Gets or Sets Name + /// + [DataMember(Name = "name", EmitDefaultValue = false)] + [JsonPropertyName("name")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string? Name { get; set; } + + public bool Equals(ClientListStoresRequest input) { + if (input == null) { + return false; + } + + return + ( + Name == input.Name || + (Name != null && + Name.Equals(input.Name)) + ); + } + + public IEnumerable Validate(ValidationContext validationContext) { + yield break; + } + + public virtual string ToJson() => JsonSerializer.Serialize(this); + + public static ClientListStoresRequest FromJson(string jsonString) => + JsonSerializer.Deserialize(jsonString) ?? throw new InvalidOperationException(); + + public override bool Equals(object input) => Equals(input as ClientListStoresRequest); + + public override int GetHashCode() { + unchecked // Overflow is fine, just wrap + { + var hashCode = 9661; + if (Name != null) { + hashCode = (hashCode * 9923) + Name.GetHashCode(); + } + + return hashCode; + } + } +} \ No newline at end of file diff --git a/src/OpenFga.Sdk/OpenFga.Sdk.csproj b/src/OpenFga.Sdk/OpenFga.Sdk.csproj index fb8d1f7..25bb216 100644 --- a/src/OpenFga.Sdk/OpenFga.Sdk.csproj +++ b/src/OpenFga.Sdk/OpenFga.Sdk.csproj @@ -37,10 +37,10 @@ - + - - + +