Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ADMINAPI-1117] - Adds /v2/resourceClaimActions and /v2/resourceClaimActionAuthStrategies endpoints. #221

Merged
merged 24 commits into from
Feb 5, 2025
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
7788d08
Add features
dfernandez-gap Jan 20, 2025
65fefb2
Add ResourceClaimActions and ResourceClaimActionAuthStrategies endpoints
dfernandez-gap Jan 24, 2025
25f2865
Fix appsettings
dfernandez-gap Jan 24, 2025
5c4d1da
Add Integration Tests
dfernandez-gap Jan 24, 2025
8610448
Undoing some changes on appsettings.Development.json
DavidJGapCR Jan 27, 2025
1158622
Fix using statements
dfernandez-gap Jan 27, 2025
1172917
Fix compiling issues
dfernandez-gap Jan 27, 2025
4afd60b
Add resource information to queries
dfernandez-gap Jan 28, 2025
36e3e6c
Fix formatting for ResourceClaimActions and ResourceClaimActionAuthSt…
dfernandez-gap Jan 29, 2025
96a906f
Fix tests
dfernandez-gap Jan 30, 2025
dba330d
Add features
dfernandez-gap Jan 20, 2025
90a254b
Return IReadOnlyList for resource claim queries
dfernandez-gap Feb 4, 2025
22a7264
Merge branch 'main' of https://github.com/Ed-Fi-Alliance-OSS/AdminAPI…
DavidJGapCR Feb 4, 2025
4ac1b34
Undoing some changes on appsettings.Development.json
DavidJGapCR Jan 27, 2025
041e335
Fix using statements
dfernandez-gap Jan 27, 2025
d9685f7
Fix compiling issues
dfernandez-gap Jan 27, 2025
f1be4c2
Add resource information to queries
dfernandez-gap Jan 28, 2025
9debc65
Fix formatting for ResourceClaimActions and ResourceClaimActionAuthSt…
dfernandez-gap Jan 29, 2025
e2e8ce9
Fix tests
dfernandez-gap Jan 30, 2025
149c6c1
Add features
dfernandez-gap Jan 20, 2025
ba6f714
Return IReadOnlyList for resource claim queries
dfernandez-gap Feb 4, 2025
e00975b
Merge branch 'ADMINAPI-1117-David' of https://github.com/Ed-Fi-Allian…
dfernandez-gap Feb 5, 2025
6b39878
Remove conn strings
dfernandez-gap Feb 5, 2025
7f40067
Change AllowRegistration attribute
dfernandez-gap Feb 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// 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 System.Collections.Generic;
using System.Linq;
using EdFi.Ods.AdminApi.Features.ResourceClaimActions;
using EdFi.Ods.AdminApi.Infrastructure;
using EdFi.Ods.AdminApi.Infrastructure.Database.Queries;
using EdFi.Security.DataAccess.Models;
using NUnit.Framework;
using Shouldly;

namespace EdFi.Ods.AdminApi.DBTests.Database.QueryTests;

[TestFixture]
public class GetResourceClaimActionsQueryTests : SecurityDataTestBase
{
[Test]
public void ShouldGetResourceClaimActions()
{
var skip = 0;
ResourceClaimActionModel[] results = null;
using var securityContext = TestContext;
var actions = SetupActions().Select(s => s.ActionId).ToArray();
var resourceClaimId = SetupResourceClaims().FirstOrDefault().ResourceClaimId;
var testResourceClaimActions = SetupResourceClaimActions(actions, resourceClaimId);
var query = new GetResourceClaimActionsQuery(securityContext, Testing.GetAppSettings());
results = query.Execute(new CommonQueryParams(skip, Testing.DefaultPageSizeLimit)).ToArray();
results.SelectMany(x => x.Actions).Count().ShouldBe(testResourceClaimActions.Count);
results.Select(x => x.ResourceClaimId).ShouldBe(testResourceClaimActions.Select(s => s.ResourceClaimId).Distinct(), true);
results.Select(x => x.ResourceName).ShouldBe(testResourceClaimActions.Select(x => x.ResourceClaim.ResourceName).Distinct(), true);
}

[Test]
public void ShouldGetAllResourceClaimActions_With_Offset_and_Limit()
{
var offset = 1;
var limit = 2;

ResourceClaimActionModel[] results = null;
using var securityContext = TestContext;
//Set actions
var actions = SetupActions().Select(s => s.ActionId).ToArray();
//Set resourceClaims
var resourceClaims = SetupResourceClaims(4);

foreach (var resourceClaim in resourceClaims)
{
var testResourceClaimActions = SetupResourceClaimActions(actions, resourceClaim.ResourceClaimId);
}
//Add ResourceClaimActions
var query = new GetResourceClaimActionsQuery(securityContext, Testing.GetAppSettings());
results = query.Execute(new CommonQueryParams(offset, limit)).ToArray();

results.Length.ShouldBe(2);
results[0].ResourceName.ShouldBe("TestResourceClaim2.00");
results[1].ResourceName.ShouldBe("TestResourceClaim3.00");
results[0].Actions.Any().ShouldBe(true);
results[1].Actions.Any().ShouldBe(true);
}

private IReadOnlyCollection<ResourceClaimAction> SetupResourceClaimActions(int[] actions, int resourceClaimId)
{
var resourceClaimActions = new List<ResourceClaimAction>();
var resourceClaimCount = actions.Length;
foreach (var index in Enumerable.Range(1, resourceClaimCount))
{
var resourceClaim = new ResourceClaimAction
{
ActionId = actions[index - 1],
ResourceClaimId = resourceClaimId,
ValidationRuleSetName = $"Test{index}"
};
resourceClaimActions.Add(resourceClaim);
}
Save(resourceClaimActions.Cast<object>().ToArray());
return resourceClaimActions;
}

private IReadOnlyCollection<ResourceClaim> SetupResourceClaims(int resourceClaimCount = 1)
{
var resourceClaims = new List<ResourceClaim>();
foreach (var index in Enumerable.Range(1, resourceClaimCount))
{
var resourceClaim = new ResourceClaim
{
ClaimName = $"TestResourceClaim{index:N}",
ResourceName = $"TestResourceClaim{index:N}",
};
resourceClaims.Add(resourceClaim);
}

Save(resourceClaims.Cast<object>().ToArray());

return resourceClaims;
}

private IReadOnlyCollection<Security.DataAccess.Models.Action> SetupActions(int resourceClaimCount = 5)
{
var actions = new List<Security.DataAccess.Models.Action>();
foreach (var index in Enumerable.Range(1, resourceClaimCount))
{
var action = new Security.DataAccess.Models.Action
{
ActionName = $"TestResourceClaim{index:N}",
ActionUri = $"http://ed-fi.org/odsapi/actions/TestResourceClaim{index:N}"
};
actions.Add(action);
}

Save(actions.Cast<object>().ToArray());

return actions;
}
}
4 changes: 2 additions & 2 deletions Application/EdFi.Ods.AdminApi.DBTests/Testing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ public static IConfiguration Configuration()

public static string SecurityConnectionString { get { return Configuration().GetConnectionString("EdFi_Security"); } }

public static int DefaultPageSizeOffset => (int)Configuration().GetValue(typeof(int), "DefaultPageSizeOffset");
public static int DefaultPageSizeOffset => Configuration().GetSection("AppSettings").GetValue<int>("DefaultPageSizeOffset");

public static int DefaultPageSizeLimit => (int)Configuration().GetValue(typeof(int), "DefaultPageSizeLimit");
public static int DefaultPageSizeLimit => Configuration().GetSection("AppSettings").GetValue<int>("DefaultPageSizeLimit");

public static DbContextOptions GetDbContextOptions(string connectionString)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// 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 AutoMapper;
using EdFi.Ods.AdminApi.Infrastructure;
using EdFi.Ods.AdminApi.Infrastructure.Database.Queries;

namespace EdFi.Ods.AdminApi.Features.ResourceClaimActionAuthStrategies;

public class ReadResourceClaimActionAuthStrategies : IFeature
{
public void MapEndpoints(IEndpointRouteBuilder endpoints)
{
AdminApiEndpointBuilder.MapGet(endpoints, "/resourceClaimActionAuthStrategies", GetResourceClaimActionAuthorizationStrategies)
.WithDefaultSummaryAndDescription()
.WithRouteOptions(b => b.WithResponse<List<ResourceClaimActionAuthStrategyModel>>(200))
.BuildForVersions(AdminApiVersions.V2);
}

internal Task<IResult> GetResourceClaimActionAuthorizationStrategies(IGetResourceClaimActionAuthorizationStrategiesQuery getResourceClaimActionAuthorizationStrategiesQuery, [AsParameters] CommonQueryParams commonQueryParams)
{
var resourceClaims = getResourceClaimActionAuthorizationStrategiesQuery.Execute(commonQueryParams);
return Task.FromResult(Results.Ok(resourceClaims));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// 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.

namespace EdFi.Ods.AdminApi.Features.ResourceClaimActionAuthStrategies
{
public class ResourceClaimActionAuthStrategyModel
{
public int ResourceClaimId { get; set; }
public string ResourceClaimName { get; set; } = string.Empty;

public IReadOnlyList<ActionWithAuthorizationStrategy> AuthorizationStrategiesForActions { get; set; } = new List<ActionWithAuthorizationStrategy>();
}

public class ActionWithAuthorizationStrategy
{
public int ActionId { get; set; }
public string ActionName { get; set; } = string.Empty;
public IReadOnlyList<AuthorizationStrategyModelForAction> AuthorizationStrategies { get; set; } = new List<AuthorizationStrategyModelForAction>();

}

public class AuthorizationStrategyModelForAction
{
public int AuthStrategyId { get; set; }
public string AuthStrategyName { get; set; } = string.Empty;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// 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 AutoMapper;
using EdFi.Ods.AdminApi.Infrastructure;
using EdFi.Ods.AdminApi.Infrastructure.Database.Queries;

namespace EdFi.Ods.AdminApi.Features.ResourceClaimActions;

public class ReadResourceClaimActions : IFeature
{
public void MapEndpoints(IEndpointRouteBuilder endpoints)
{
AdminApiEndpointBuilder.MapGet(endpoints, "/resourceClaimActions", GetResourceClaimsActions)
.WithDefaultSummaryAndDescription()
.WithRouteOptions(b => b.WithResponse<List<ResourceClaimActionModel>>(200))
.BuildForVersions(AdminApiVersions.V2);
}

internal Task<IResult> GetResourceClaimsActions(IGetResourceClaimActionsQuery getResourceClaimActionsQuery, IMapper mapper, [AsParameters] CommonQueryParams commonQueryParams)
{
var resourceClaimActions = getResourceClaimActionsQuery.Execute(commonQueryParams);
return Task.FromResult(Results.Ok(resourceClaimActions));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// 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.

namespace EdFi.Ods.AdminApi.Features.ResourceClaimActions
{
public class ResourceClaimActionModel
{
public int ResourceClaimId { get; set; }
public string ResourceName { get; set; } = string.Empty;
public List<ActionForResourceClaimModel> Actions { get; set; } = new List<ActionForResourceClaimModel>();
}

public class ActionForResourceClaimModel
{
public string Name { get; set; } = string.Empty;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
using EdFi.Ods.AdminApi.Features.ClaimSets;
using EdFi.Ods.AdminApi.Features.ODSInstances;
using EdFi.Ods.AdminApi.Features.Profiles;
using EdFi.Ods.AdminApi.Features.ResourceClaimActionAuthStrategies;
using EdFi.Ods.AdminApi.Features.ResourceClaimActions;
using EdFi.Ods.AdminApi.Features.Vendors;
using EdFi.Ods.AdminApi.Infrastructure.AutoMapper;
using EdFi.Ods.AdminApi.Infrastructure.ClaimSetEditor;
Expand Down Expand Up @@ -155,5 +157,10 @@ public AdminApiMappingProfile()
.ForMember(dst => dst.Name, opt => opt.MapFrom(src => src.Name))
.ForMember(dst => dst.OdsInstanceDerivatives, opt => opt.MapFrom(src => src.OdsInstanceDerivatives))
.ForMember(dst => dst.OdsInstanceContexts, opt => opt.MapFrom(src => src.OdsInstanceContexts));

CreateMap<EdFi.Security.DataAccess.Models.ResourceClaimAction, ResourceClaimActionModel>()
.ForMember(dest => dest.ResourceClaimId, opt => opt.MapFrom(src => src.ResourceClaim.ResourceClaimId))
.ForMember(dest => dest.ResourceName, opt => opt.MapFrom(src => src.ResourceClaim.ResourceName))
.ForMember(dest => dest.Actions, opt => opt.Ignore());//Action is ignore as we build it manually
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// 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 System.Linq.Expressions;
using EdFi.Ods.AdminApi.Features.ResourceClaimActionAuthStrategies;
using EdFi.Ods.AdminApi.Helpers;
using EdFi.Ods.AdminApi.Infrastructure.Extensions;
using EdFi.Ods.AdminApi.Infrastructure.Helpers;
using EdFi.Security.DataAccess.Contexts;
using EdFi.Security.DataAccess.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using Polly;

namespace EdFi.Ods.AdminApi.Infrastructure.Database.Queries;

public interface IGetResourceClaimActionAuthorizationStrategiesQuery
{
public List<ResourceClaimActionAuthStrategyModel> Execute(CommonQueryParams commonQueryParams);
}

public class GetResourceClaimActionAuthorizationStrategiesQuery : IGetResourceClaimActionAuthorizationStrategiesQuery
{
private readonly ISecurityContext _securityContext;
private readonly IOptions<AppSettings> _options;
private readonly Dictionary<string, Expression<Func<ResourceClaimActionAuthStrategyModel, object>>> _orderByColumns;

public GetResourceClaimActionAuthorizationStrategiesQuery(ISecurityContext securityContext, IOptions<AppSettings> options)
{
_securityContext = securityContext;
_options = options;
_orderByColumns = new Dictionary<string, Expression<Func<ResourceClaimActionAuthStrategyModel, object>>>
(StringComparer.OrdinalIgnoreCase)
{
{ SortingColumns.DefaultIdColumn, x => x.ResourceClaimId },
{ nameof(ResourceClaimActionAuthStrategyModel.ResourceClaimName), x => x.ResourceClaimName }
};
}

public List<ResourceClaimActionAuthStrategyModel> Execute(CommonQueryParams commonQueryParams)
{
Expression<Func<ResourceClaimActionAuthStrategyModel, object>> columnToOrderBy = _orderByColumns.GetColumnToOrderBy(commonQueryParams.OrderBy);

return _securityContext.ResourceClaimActionAuthorizationStrategies
// Group by ResourceClaimId and ResourceName to structure the JSON correctly
.GroupBy(gb => new
{
gb.ResourceClaimAction.ResourceClaimId,
gb.ResourceClaimAction.ResourceClaim.ResourceName
})
.Select(group => new ResourceClaimActionAuthStrategyModel
{
ResourceClaimId = group.Key.ResourceClaimId,
ResourceClaimName = group.Key.ResourceName,
// Group by ActionId and ActionName to create a list of actions within the resource
AuthorizationStrategiesForActions = group.GroupBy(gb => new
{
gb.ResourceClaimAction.Action.ActionId,
gb.ResourceClaimAction.Action.ActionName
})
.Select(groupedActions => new ActionWithAuthorizationStrategy
{
ActionId = groupedActions.Key.ActionId,
ActionName = groupedActions.Key.ActionName,
// For each action, get the associated authorization strategies
AuthorizationStrategies = groupedActions.Select(resourceClaimActionAuthorizationStrategies =>
new AuthorizationStrategyModelForAction
{
AuthStrategyId = resourceClaimActionAuthorizationStrategies.AuthorizationStrategy.AuthorizationStrategyId,
AuthStrategyName = resourceClaimActionAuthorizationStrategies.AuthorizationStrategy.AuthorizationStrategyName,
}).ToList()
}).ToList()
})
.OrderByColumn(columnToOrderBy, commonQueryParams.IsDescending)
.Paginate(commonQueryParams.Offset, commonQueryParams.Limit, _options)
.ToList();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// 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 System.Linq.Expressions;
using EdFi.Ods.AdminApi.Features.ResourceClaimActions;
using EdFi.Ods.AdminApi.Helpers;
using EdFi.Ods.AdminApi.Infrastructure.Extensions;
using EdFi.Ods.AdminApi.Infrastructure.Helpers;
using EdFi.Security.DataAccess.Contexts;
using EdFi.Security.DataAccess.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using Polly;

namespace EdFi.Ods.AdminApi.Infrastructure.Database.Queries;

public interface IGetResourceClaimActionsQuery
{
public List<ResourceClaimActionModel> Execute(CommonQueryParams commonQueryParams);
}

public class GetResourceClaimActionsQuery : IGetResourceClaimActionsQuery
{
private readonly ISecurityContext _securityContext;
private readonly IOptions<AppSettings> _options;
private readonly Dictionary<string, Expression<Func<ResourceClaimActionModel, object>>> _orderByColumns;

public GetResourceClaimActionsQuery(ISecurityContext securityContext, IOptions<AppSettings> options)
{
_securityContext = securityContext;
_options = options;
var isSQLServerEngine = _options.Value.DatabaseEngine?.ToLowerInvariant() == DatabaseEngineEnum.SqlServer.ToLowerInvariant();
_orderByColumns = new Dictionary<string, Expression<Func<ResourceClaimActionModel, object>>>
(StringComparer.OrdinalIgnoreCase)
{
{ nameof(ResourceClaimActionModel.ResourceClaimId), x => x.ResourceClaimId},
{ nameof(ResourceClaimActionModel.ResourceName), x => isSQLServerEngine ? EF.Functions.Collate(x.ResourceName, DatabaseEngineEnum.SqlServerCollation) : x.ResourceName},
};
}

public List<ResourceClaimActionModel> Execute(CommonQueryParams commonQueryParams)
{
Expression<Func<ResourceClaimActionModel, object>> columnToOrderBy = _orderByColumns.GetColumnToOrderBy(commonQueryParams.OrderBy);

return _securityContext.ResourceClaimActions
.Include(i => i.ResourceClaim)
.Include(i => i.Action)
.GroupBy(r => new { r.ResourceClaim.ResourceClaimId, r.ResourceClaim.ResourceName })
.Select(group => new ResourceClaimActionModel
{
ResourceClaimId = group.Key.ResourceClaimId,
ResourceName = group.Key.ResourceName,
Actions = group.Select(g => new ActionForResourceClaimModel { Name = g.Action.ActionName }).Distinct().ToList()
})
.OrderByColumn(columnToOrderBy, commonQueryParams.IsDescending)
.Paginate(commonQueryParams.Offset, commonQueryParams.Limit, _options)
.ToList();
}
}
Loading
Loading