Skip to content

Commit

Permalink
[DMS-434] Build Validation for resourceClaims (#378)
Browse files Browse the repository at this point in the history
* Adding the table and basic CRUD for ClaimSet

* Frontend basic CRUD for claimSets

* Fixing things after testing endpoints on postman

* Adding Copy functionallity

* Adding support for Export

* Adding support for import claimsets

* Adding verbose parameter for get by id and get all

* Adding detail: Data validation failed. See 'validationErrors' for details. For Unit Test

* Adding Claimset Postgresql integration test

* first step on frontend unit test success scenarios

* success test for copy export and import

* Adding test more scenarios for claimsets

* Renaming ClaimSetName to name to follow the AdminAPI standard

* adding a collection of applications to get all and get by id

* collection of applications also for export option

* JsonPropertyName for _applications and _isSystemREserved

* removing IsSystemReserved from parameter for import put and post

* Chance type JsonElement to ResourceClaim on import

* Paging change namespace location after merge

* Testing solution for on pull request error

* setup dotnet

* codeql

* setup net 8 on pull request for config

* updating detail for e2e data validation error

* adding net8 setup step on scheduled build

* Take ResourceClaim and serialize it to store in db

* Validation: ActionName and AuthStrategyName must exist

* Adding ResourceClaimValidator to ClaimSetImportCommand

* DataProvider to get to the repository data actions and AuthStrategies

* Fixing Tests

* Common Validator for import, insert and update and testing scenarios

* Adding claimsetname unique name validation for claimset

* Adding propper response for validation of duplicate claimsetname

* Testing frontend response for duplicated claimsetname

* Unify serialze for resourceclaim

* Minor adjustments
  • Loading branch information
JBrenesSimpat authored Jan 6, 2025
1 parent 4c1d4c4 commit 09768b6
Show file tree
Hide file tree
Showing 21 changed files with 634 additions and 178 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
// The Ed-Fi Alliance licenses this file to you under the Apache License, Version 2.0.
// See the LICENSE and NOTICES files in the project root for more information.

using System.Text.Json;
using EdFi.DmsConfigurationService.Backend.Postgresql.Repositories;
using EdFi.DmsConfigurationService.Backend.Repositories;
using EdFi.DmsConfigurationService.DataModel.Model;
Expand Down Expand Up @@ -65,6 +64,15 @@ public async Task Should_get_test_claimSet_from_get_by_id()
var reducedResponse = (ClaimSetResponseReduced)claimSetFromDb;
reducedResponse.Name.Should().Be("Test ClaimSet");
}

[Test]
public async Task Should_get_duplicate_failure()
{
ClaimSetInsertCommand claimSetDup = new() { Name = "Test ClaimSet" };

var resultDup = await _repository.InsertClaimSet(claimSetDup);
resultDup.Should().BeOfType<ClaimSetInsertResult.FailureDuplicateClaimSetName>();
}
}

[TestFixture]
Expand Down Expand Up @@ -199,12 +207,29 @@ public class ImportTest : ClaimSetTests
[SetUp]
public async Task Setup()
{
string resourceClaimsJson = """
var resourceClaims = new List<ResourceClaim>
{
new()
{
"Resource": "Value"
}
""";
JsonElement resourceClaims = JsonDocument.Parse(resourceClaimsJson).RootElement;
Name = "resourceClaim1",
Actions = [new ResourceClaimAction { Enabled = true, Name = "Create" }],
DefaultAuthorizationStrategiesForCRUD =
[
new()
{
AuthorizationStrategies = new List<AuthorizationStrategy>
{
new()
{
AuthStrategyId = 1,
AuthStrategyName = "AuthStrategy1",
DisplayName = "AuthStrategy1",
},
},
},
],
},
};

ClaimSetImportCommand claimSet = new()
{
Expand Down Expand Up @@ -240,6 +265,43 @@ public async Task Should_get_test_claimSet_from_get_by_id()
response.Name.Should().Be("Test Import ClaimSet");
response.ResourceClaims.Should().NotBeNull();
}

[Test]
public async Task Should_get_duplicate_failure()
{
var resourceClaims = new List<ResourceClaim>
{
new()
{
Name = "resourceClaim1",
Actions = [new ResourceClaimAction { Enabled = true, Name = "Create" }],
DefaultAuthorizationStrategiesForCRUD =
[
new()
{
AuthorizationStrategies = new List<AuthorizationStrategy>
{
new()
{
AuthStrategyId = 1,
AuthStrategyName = "AuthStrategy1",
DisplayName = "AuthStrategy1",
},
},
},
],
},
};

ClaimSetImportCommand claimSetDup = new()
{
Name = "Test Import ClaimSet",
ResourceClaims = resourceClaims,
};

var resultDup = await _repository.Import(claimSetDup);
resultDup.Should().BeOfType<ClaimSetImportResult.FailureDuplicateClaimSetName>();
}
}

[TestFixture]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: Apache-2.0
// Licensed to the Ed-Fi Alliance under one or more agreements.
// The Ed-Fi Alliance licenses this file to you under the Apache License, Version 2.0.
// See the LICENSE and NOTICES files in the project root for more information.

using EdFi.DmsConfigurationService.Backend.Repositories;
using EdFi.DmsConfigurationService.DataModel.Model.ClaimSets;

namespace EdFi.DmsConfigurationService.Backend.Postgresql;

public class ClaimSetDataProvider(IClaimSetRepository repository) : IClaimSetDataProvider
{
public List<string> GetActions()
{
return repository.GetActions().Select(a => a.Name).ToList();
}

public List<string> GetAuthorizationStrategies()
{
return repository.GetAuthorizationStrategies().Select(a => a.AuthStrategyName).ToList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,17 @@ CREATE TABLE IF NOT EXISTS dmscs.ClaimSet
IsSystemReserved BOOLEAN NOT NULL,
ResourceClaims JSONB NOT NULL,
CONSTRAINT claimset_pkey PRIMARY KEY (id)
)
);

TABLESPACE pg_default;
ALTER TABLE dmscs.ClaimSet ADD CONSTRAINT uq_ClaimSetName UNIQUE (ClaimSetName);

ALTER TABLE IF EXISTS dmscs.claimset
OWNER to postgres;
CREATE UNIQUE INDEX idx_ClaimSetName ON dmscs.ClaimSet (ClaimSetName);

COMMENT ON COLUMN dmscs.claimset.id
IS 'ClaimSet id';

COMMENT ON COLUMN dmscs.claimset.ClaimSetName
IS 'Claim set name';
IS 'Claim set name and must be unique';

COMMENT ON COLUMN dmscs.claimset.IsSystemReserved
IS 'Is system reserved';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,54 @@
// See the LICENSE and NOTICES files in the project root for more information.

using System.Text.Json;
using System.Text.Json.Serialization;
using Dapper;
using EdFi.DmsConfigurationService.Backend.Repositories;
using EdFi.DmsConfigurationService.DataModel.Model;
using EdFi.DmsConfigurationService.DataModel.Model.ClaimSets;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Npgsql;
using Action = EdFi.DmsConfigurationService.DataModel.Model.Action.Action;

namespace EdFi.DmsConfigurationService.Backend.Postgresql.Repositories;

public class ClaimSetRepository(IOptions<DatabaseOptions> databaseOptions, ILogger<ClaimSetRepository> logger)
: IClaimSetRepository
{
public IEnumerable<Action> GetActions()
{
var actions = new Action[]
{
new()
{
Id = 1,
Name = "Create",
Uri = "uri://ed-fi.org/api/actions/create",
},
new()
{
Id = 2,
Name = "Read",
Uri = "uri://ed-fi.org/api/actions/read",
},
new()
{
Id = 3,
Name = "Update",
Uri = "uri://ed-fi.org/api/actions/update",
},
new()
{
Id = 4,
Name = "Delete",
Uri = "uri://ed-fi.org/api/actions/delete",
},
};

return actions;
}

public IEnumerable<AuthorizationStrategy> GetAuthorizationStrategies()
{
var authStrategies = new AuthorizationStrategy[]
Expand Down Expand Up @@ -99,6 +134,18 @@ public IEnumerable<AuthorizationStrategy> GetAuthorizationStrategies()
return authStrategies;
}

private static string SerializeResourceClaim(List<ResourceClaim>? resourceClaims)
{
return JsonSerializer.Serialize(
resourceClaims,
new JsonSerializerOptions
{
WriteIndented = false,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
}
);
}

public async Task<ClaimSetInsertResult> InsertClaimSet(ClaimSetInsertCommand command)
{
await using var connection = new NpgsqlConnection(databaseOptions.Value.DatabaseConnection);
Expand All @@ -117,16 +164,20 @@ INSERT INTO dmscs.ClaimSet (ClaimSetName, IsSystemReserved, ResourceClaims)
{
ClaimSetName = command.Name,
IsSystemReserved = false,
ResourceClaims = command.ResourceClaims.ValueKind != JsonValueKind.Undefined
? command.ResourceClaims.ToString()
: "{}",
ResourceClaims = SerializeResourceClaim(command.ResourceClaims),
};

long id = await connection.ExecuteScalarAsync<long>(sql, parameters);
await transaction.CommitAsync();

return new ClaimSetInsertResult.Success(id);
}
catch (PostgresException ex) when (ex.SqlState == "23505" && ex.Message.Contains("uq_claimsetname"))
{
logger.LogWarning(ex, "ClaimSetName must be unique");
await transaction.RollbackAsync();
return new ClaimSetInsertResult.FailureDuplicateClaimSetName();
}
catch (Exception ex)
{
logger.LogError(ex, "Insert claim set failure");
Expand Down Expand Up @@ -260,7 +311,7 @@ UPDATE dmscs.ClaimSet
command.Id,
ClaimSetName = command.Name,
IsSystemReserved = false,
ResourceClaims = JsonSerializer.Serialize(command.ResourceClaims),
ResourceClaims = SerializeResourceClaim(command.ResourceClaims),
};

int affectedRows = await connection.ExecuteAsync(sql, parameters);
Expand Down Expand Up @@ -357,14 +408,20 @@ INSERT INTO dmscs.ClaimSet (ClaimSetName, IsSystemReserved, ResourceClaims)
{
ClaimSetName = command.Name,
IsSystemReserved = false,
ResourceClaims = command.ResourceClaims.ToString(),
ResourceClaims = SerializeResourceClaim(command.ResourceClaims),
};

long id = await connection.ExecuteScalarAsync<long>(sql, parameters);
await transaction.CommitAsync();

return new ClaimSetImportResult.Success(id);
}
catch (PostgresException ex) when (ex.SqlState == "23505" && ex.Message.Contains("uq_claimsetname"))
{
logger.LogWarning(ex, "ClaimSetName must be unique");
await transaction.RollbackAsync();
return new ClaimSetImportResult.FailureDuplicateClaimSetName();
}
catch (Exception ex)
{
logger.LogError(ex, "Insert claim set failure");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@

using EdFi.DmsConfigurationService.DataModel.Model;
using EdFi.DmsConfigurationService.DataModel.Model.ClaimSets;
using Action = EdFi.DmsConfigurationService.DataModel.Model.Action.Action;

namespace EdFi.DmsConfigurationService.Backend.Repositories;

public interface IClaimSetRepository
{
IEnumerable<Action> GetActions();
IEnumerable<AuthorizationStrategy> GetAuthorizationStrategies();
Task<ClaimSetInsertResult> InsertClaimSet(ClaimSetInsertCommand command);
Task<ClaimSetQueryResult> QueryClaimSet(PagingQuery query, bool verbose);
Expand All @@ -33,6 +35,11 @@ public record Success(long Id) : ClaimSetInsertResult();
/// Unexpected exception thrown and caught
/// </summary>
public record FailureUnknown(string FailureMessage) : ClaimSetInsertResult();

/// <summary>
/// ClaimSetName must be unique
/// </summary>
public record FailureDuplicateClaimSetName() : ClaimSetInsertResult();
}

public record ClaimSetQueryResult
Expand Down Expand Up @@ -147,4 +154,9 @@ public record Success(long Id) : ClaimSetImportResult();
/// Unexpected exception thrown and caught
/// </summary>
public record FailureUnknown(string FailureMessage) : ClaimSetImportResult();

/// <summary>
/// ClaimSetName must be unique
/// </summary>
public record FailureDuplicateClaimSetName() : ClaimSetImportResult();
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,12 @@

namespace EdFi.DmsConfigurationService.DataModel.Model.Action;

public class AdminAction
public class Action
{
[JsonPropertyName("id")]
public required int Id { get; set; }

[JsonPropertyName("name")]
public required string Name { get; set; }

[JsonPropertyName("uri")]
public required string Uri { get; set; }
}

public class ActionResponse
{
public required AdminAction[] AdminActions;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public class AuthorizationStrategy
{
public int AuthStrategyId { get; set; }

public string? AuthStrategyName { get; set; }
public required string AuthStrategyName { get; set; }

public string? DisplayName { get; set; }

Expand Down
Loading

0 comments on commit 09768b6

Please sign in to comment.