From 36f6052374c9ac971038265394539f9658177504 Mon Sep 17 00:00:00 2001 From: David Jimenez Date: Mon, 22 Sep 2025 11:27:13 -0600 Subject: [PATCH] Fixes build warnings in the new EdFi.Ods.AdminApi.V1 project --- .../CommandTests/AddApiClientCommandTests.cs | 20 +- .../CommandTests/EditApiClientCommandTests.cs | 14 +- .../Contexts/UsersContextFactory.cs | 29 +- .../Admin.DataAccess/Models/AccountModels.cs | 57 +- .../Admin.DataAccess/Models/ApiClient.cs | 103 +--- .../Models/ApiClientOwnershipToken.cs | 20 +- .../Admin.DataAccess/Models/Application.cs | 19 +- .../ApplicationEducationOrganization.cs | 2 +- .../Models/ClientAccessToken.cs | 4 +- .../Models/OAuthTokenClient.cs | 12 +- .../Admin.DataAccess/Models/OdsInstance.cs | 12 +- .../Models/OdsInstanceComponent.cs | 8 +- .../Admin.DataAccess/Models/OwnershipToken.cs | 4 +- .../Admin.DataAccess/Models/Profile.cs | 2 +- .../Admin.DataAccess/Models/Vendor.cs | 19 +- .../Models/VendorNamespacePrefix.cs | 4 +- .../Repositories/ClientAppRepo.cs | 563 ++++++++---------- .../Repositories/IClientAppRepo.cs | 8 +- .../EdFiAdminApiClientSecretWriter.cs | 2 +- .../Utils/DefaultApplicationCreator.cs | 15 +- .../EdFi.Ods.AdminApi.V1.csproj | 1 + .../Features/Applications/AddApplication.cs | 2 +- .../Features/Applications/EditApplication.cs | 6 +- .../Features/ClaimSets/ClaimSetModel.cs | 2 +- .../Features/OdsInstances/AddOdsInstance.cs | 8 +- .../Features/OdsInstances/EditOdsInstance.cs | 8 +- .../Features/Vendors/AddVendor.cs | 8 +- .../Features/Vendors/EditVendor.cs | 6 +- .../AutoMapper/AdminApiMappingProfile.cs | 20 +- .../Commands/AddApplicationCommand.cs | 22 +- .../Commands/AddOdsInstanceCommand.cs | 8 +- .../Database/Commands/AddVendorCommand.cs | 16 +- .../Commands/DeleteApplicationCommand.cs | 2 +- .../Commands/EditApplicationCommand.cs | 18 +- .../Commands/EditOdsInstanceCommand.cs | 8 +- .../Database/Commands/EditVendorCommand.cs | 8 +- .../RegenerateApiClientSecretCommand.cs | 2 +- ...eworkCoreDatabaseModelBuilderExtensions.cs | 3 +- .../GetApplicationsByOdsInstanceIdQuery.cs | 2 +- .../Database/Queries/GetApplicationsQuery.cs | 14 +- .../GetResourceClaimsAsFlatListQuery.cs | 2 +- .../Database/Queries/GetVendorsQuery.cs | 4 +- .../ClaimSetEditor/AddClaimSetCommand.cs | 2 +- .../AddOrEditResourcesOnClaimSetCommand.cs | 2 +- .../GetApplicationsByClaimSetIdQuery.cs | 2 +- .../GetResourcesByClaimSetIdQueryService.cs | 33 +- ...rideDefaultAuthorizationStrategyService.cs | 21 +- ...UpdateResourcesOnClaimSetCommandService.cs | 5 +- .../Contexts/SecurityContextFactory.cs | 47 +- .../Security.DataAccess/Models/Action.cs | 4 +- .../Security.DataAccess/Models/Application.cs | 2 +- .../Models/AuthorizationStrategy.cs | 6 +- .../Security.DataAccess/Models/ClaimSet.cs | 8 +- .../Models/ClaimSetResourceClaimAction.cs | 8 +- ...aimActionAuthorizationStrategyOverrides.cs | 6 +- .../Models/ResourceClaim.cs | 10 +- .../Models/ResourceClaimAction.cs | 7 +- ...ourceClaimActionAuthorizationStrategies.cs | 4 +- .../Repositories/CachedSecurityRepository.cs | 10 +- .../Repositories/ISecurityRepository.cs | 6 +- .../Repositories/SecurityRepository.cs | 27 +- .../Repositories/SecurityRepositoryBase.cs | 26 +- .../WebApplicationBuilderExtensions.cs | 2 +- 63 files changed, 588 insertions(+), 737 deletions(-) diff --git a/Application/EdFi.Ods.AdminApi.DBTests/Database/CommandTests/AddApiClientCommandTests.cs b/Application/EdFi.Ods.AdminApi.DBTests/Database/CommandTests/AddApiClientCommandTests.cs index e4db60d34..ff850f589 100644 --- a/Application/EdFi.Ods.AdminApi.DBTests/Database/CommandTests/AddApiClientCommandTests.cs +++ b/Application/EdFi.Ods.AdminApi.DBTests/Database/CommandTests/AddApiClientCommandTests.cs @@ -5,8 +5,6 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading.Tasks; using EdFi.Admin.DataAccess.Models; using EdFi.Ods.AdminApi.Common.Settings; @@ -23,17 +21,19 @@ internal class AddApiClientCommandTests : PlatformUsersContextTestBase private int applicationId { get; set; } [SetUp] - public virtual async Task SetUp() + public new virtual async Task SetUp() { - AppSettings appSettings = new AppSettings(); - appSettings.PreventDuplicateApplications = false; + AppSettings appSettings = new() + { + PreventDuplicateApplications = false + }; _options = Options.Create(appSettings); await Task.Yield(); var vendor = new Vendor { VendorId = 0, - VendorNamespacePrefixes = new List { new VendorNamespacePrefix { NamespacePrefix = "http://tests.com" } }, + VendorNamespacePrefixes = [new() { NamespacePrefix = "http://tests.com" }], VendorName = "Integration Tests" }; @@ -62,7 +62,7 @@ public void ShouldFailForInvalidApplication() Name = "Test ApiClient", ApplicationId = 0, IsApproved = true, - OdsInstanceIds = new List { 1, 2 } + OdsInstanceIds = [1, 2] }; Assert.Throws(() => command.Execute(newApiClient, _options)); @@ -75,7 +75,7 @@ public void ShouldCreateApiClientWithOdsInstances() var vendor = new Vendor { VendorId = 0, - VendorNamespacePrefixes = new List { new VendorNamespacePrefix { NamespacePrefix = "http://tests.com" } }, + VendorNamespacePrefixes = [new() { NamespacePrefix = "http://tests.com" }], VendorName = "Integration Tests" }; @@ -98,7 +98,7 @@ public void ShouldCreateApiClientWithOdsInstances() Name = "Test ApiClient", ApplicationId = application.ApplicationId, IsApproved = true, - OdsInstanceIds = new List { 1, 2 } + OdsInstanceIds = [1, 2] }; command.Execute(newApiClient, _options); @@ -111,7 +111,7 @@ public void ShouldCreateApiClientWithOutOdsInstances() var vendor = new Vendor { VendorId = 0, - VendorNamespacePrefixes = new List { new VendorNamespacePrefix { NamespacePrefix = "http://tests.com" } }, + VendorNamespacePrefixes = [new() { NamespacePrefix = "http://tests.com" }], VendorName = "Integration Tests" }; diff --git a/Application/EdFi.Ods.AdminApi.DBTests/Database/CommandTests/EditApiClientCommandTests.cs b/Application/EdFi.Ods.AdminApi.DBTests/Database/CommandTests/EditApiClientCommandTests.cs index a23c415b1..17ccb2d0c 100644 --- a/Application/EdFi.Ods.AdminApi.DBTests/Database/CommandTests/EditApiClientCommandTests.cs +++ b/Application/EdFi.Ods.AdminApi.DBTests/Database/CommandTests/EditApiClientCommandTests.cs @@ -11,11 +11,9 @@ using EdFi.Ods.AdminApi.Common.Infrastructure; using EdFi.Ods.AdminApi.Common.Settings; using EdFi.Ods.AdminApi.Infrastructure.Database.Commands; -using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Options; using NUnit.Framework; using Shouldly; -using Profile = EdFi.Admin.DataAccess.Models.Profile; using VendorUser = EdFi.Admin.DataAccess.Models.User; namespace EdFi.Ods.AdminApi.DBTests.Database.CommandTests; @@ -33,10 +31,12 @@ internal class EditApiClientCommandTests : PlatformUsersContextTestBase private IOptions _options { get; set; } [SetUp] - public virtual async Task SetUp() + public new virtual async Task SetUp() { - AppSettings appSettings = new AppSettings(); - appSettings.PreventDuplicateApplications = false; + AppSettings appSettings = new() + { + PreventDuplicateApplications = false + }; _options = Options.Create(appSettings); await Task.Yield(); } @@ -52,7 +52,7 @@ private void SetupTestEntities() _vendor = new Vendor { - VendorNamespacePrefixes = new List { new VendorNamespacePrefix { NamespacePrefix = "http://tests.com" } }, + VendorNamespacePrefixes = [new() { NamespacePrefix = "http://tests.com" }], VendorName = "Integration Tests" }; @@ -190,7 +190,7 @@ public void ShouldAddOdsInstancesIfNew() ApplicationId = _application.ApplicationId, Name = _apiClient.Name, IsApproved = true, - OdsInstanceIds = new List { _odsInstance.OdsInstanceId, _newOdsInstance.OdsInstanceId } + OdsInstanceIds = [_odsInstance.OdsInstanceId, _newOdsInstance.OdsInstanceId] }; Transaction(usersContext => diff --git a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Contexts/UsersContextFactory.cs b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Contexts/UsersContextFactory.cs index a90650b9a..92846e643 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Contexts/UsersContextFactory.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Contexts/UsersContextFactory.cs @@ -26,11 +26,12 @@ public class UsersContextFactory : IUsersContextFactory public UsersContextFactory(IAdminDatabaseConnectionStringProvider connectionStringsProvider, DatabaseEngine databaseEngine) { _connectionStringsProvider = Preconditions.ThrowIfNull(connectionStringsProvider, nameof(connectionStringsProvider)); - _databaseEngine = Preconditions.ThrowIfNull(databaseEngine, nameof(databaseEngine)); + _databaseEngine = Preconditions.ThrowIfNull(databaseEngine, nameof(databaseEngine)); } + public Type GetUsersContextType() { - if (_usersContextTypeByDatabaseEngine.TryGetValue(_databaseEngine, out Type contextType)) + if (_usersContextTypeByDatabaseEngine.TryGetValue(_databaseEngine, out Type? contextType) && contextType != null) { return contextType; } @@ -44,23 +45,23 @@ public IUsersContext CreateContext() if (_databaseEngine == DatabaseEngine.SqlServer) { return Activator.CreateInstance( - GetUsersContextType(), - new DbContextOptionsBuilder() - .UseLazyLoadingProxies() - .UseSqlServer(_connectionStringsProvider.GetConnectionString()) - .Options) as - IUsersContext; + GetUsersContextType(), + new DbContextOptionsBuilder() + .UseLazyLoadingProxies() + .UseSqlServer(_connectionStringsProvider.GetConnectionString()) + .Options) as + IUsersContext ?? throw new InvalidOperationException("Failed to create SqlServerUsersContext instance."); } if (_databaseEngine == DatabaseEngine.Postgres) { return Activator.CreateInstance( - GetUsersContextType(), - new DbContextOptionsBuilder() - .UseLazyLoadingProxies() - .UseNpgsql(_connectionStringsProvider.GetConnectionString()) - .Options) as - IUsersContext; + GetUsersContextType(), + new DbContextOptionsBuilder() + .UseLazyLoadingProxies() + .UseNpgsql(_connectionStringsProvider.GetConnectionString()) + .Options) as + IUsersContext ?? throw new InvalidOperationException("Failed to create PostgresUsersContext instance."); } throw new InvalidOperationException( diff --git a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/AccountModels.cs b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/AccountModels.cs index ea6630eee..6427d1e11 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/AccountModels.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/AccountModels.cs @@ -3,8 +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.Collections.Generic; -using System.Collections.ObjectModel; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; @@ -14,35 +12,30 @@ public class User { public User() { - ApiClients = new Collection(); + ApiClients = []; } [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int UserId { get; set; } - public string Email { get; set; } + public required string Email { get; set; } - public string FullName { get; set; } + public required string FullName { get; set; } - public virtual Vendor Vendor { get; set; } + public required Vendor Vendor { get; set; } public virtual ICollection ApiClients { get; set; } - /// - /// Create a new sandbox client - /// - /// The visible name of the sandbox - /// Empty, Minimal, Populated - /// optional parameter, value is created randomly if it is null or empty. Both Key and Secret are required if providing either. - /// optional parameter, value is created randomly if it is null or empty. Both Key and Secret are required if providing either. - /// ApiClient information about the created sandbox public ApiClient AddSandboxClient(string name, SandboxType sandboxType, string key, string secret) { var client = new ApiClient(true) - { - Name = name, IsApproved = true, UseSandbox = true, SandboxType = sandboxType - }; + { + Name = name, + IsApproved = true, + UseSandbox = true, + SandboxType = sandboxType + }; if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(secret)) { @@ -54,13 +47,13 @@ public ApiClient AddSandboxClient(string name, SandboxType sandboxType, string k return client; } - public static User Create(string userEmail, string userName, Vendor vendor = null) + public static User Create(string userEmail, string userName, Vendor vendor) { return new User { Email = userEmail, FullName = userName, - Vendor = vendor + Vendor = vendor }; } } @@ -69,9 +62,9 @@ public class RegisterExternalLoginModel { [Required] [Display(Name = "User name")] - public string UserName { get; set; } + public string UserName { get; set; } = string.Empty; - public string ExternalLoginData { get; set; } + public string ExternalLoginData { get; set; } = string.Empty; } public class LocalPasswordModel @@ -79,30 +72,30 @@ public class LocalPasswordModel [Required] [DataType(DataType.Password)] [Display(Name = "Current password")] - public string OldPassword { get; set; } + public string OldPassword { get; set; } = string.Empty; [Required] [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] [DataType(DataType.Password)] [Display(Name = "New password")] - public string NewPassword { get; set; } + public string NewPassword { get; set; } = string.Empty; [DataType(DataType.Password)] [Display(Name = "Confirm new password")] [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")] - public string ConfirmPassword { get; set; } + public string ConfirmPassword { get; set; } = string.Empty; } public class LoginModel { [Required] [Display(Name = "Email Address")] - public string EmailAddress { get; set; } + public required string EmailAddress { get; set; } [Required] [DataType(DataType.Password)] [Display(Name = "Password")] - public string Password { get; set; } + public required string Password { get; set; } [Display(Name = "Remember me?")] public bool RememberMe { get; set; } @@ -112,26 +105,26 @@ public class RegisterModel { [Required] [Display(Name = "User name")] - public string UserName { get; set; } + public required string UserName { get; set; } [Required] [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] [DataType(DataType.Password)] [Display(Name = "Password")] - public string Password { get; set; } + public required string Password { get; set; } [DataType(DataType.Password)] [Display(Name = "Confirm password")] [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] - public string ConfirmPassword { get; set; } + public required string ConfirmPassword { get; set; } } public class ExternalLogin { - public string Provider { get; set; } + public string Provider { get; set; } = string.Empty; - public string ProviderDisplayName { get; set; } + public string ProviderDisplayName { get; set; } = string.Empty; - public string ProviderUserId { get; set; } + public string ProviderUserId { get; set; } = string.Empty; } } diff --git a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/ApiClient.cs b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/ApiClient.cs index c61de3811..07464b393 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/ApiClient.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/ApiClient.cs @@ -26,10 +26,6 @@ public ApiClient() Domains = new Dictionary(); } - /// - /// Constructor, optionally generating a new key and secret - /// - /// true to generate a new key and secret public ApiClient(bool generateKey = false) : this() { @@ -42,127 +38,62 @@ public ApiClient(bool generateKey = false) Secret = GenerateRandomString(); } - /// - /// Numeric Identifier - /// public int ApiClientId { get; set; } - /// - /// Primary lookup for the application - /// Also known as the client_id - /// [Required] [StringLength(50)] - public string Key { get; set; } + public string Key { get; set; } = string.Empty; - /// - /// 128-bit crypto-strength string - /// [Required] [StringLength(100)] - public string Secret { get; set; } + public string Secret { get; set; } = string.Empty; - /// - /// Indicates if the secret is hashed - /// public bool SecretIsHashed { get; set; } - /// - /// Something friendly to display to the users - /// [Required] [StringLength(50)] - public string Name { get; set; } + public required string Name { get; set; } = string.Empty; - /// - /// Lock-out the application if not approved (Auto-approve in sandbox) - /// public bool IsApproved { get; set; } - /// - /// Does the client API access their own database (copy of empty EdFi Ods) - /// true - use a sandbox - /// false - use a shared instance - /// public bool UseSandbox { get; set; } public SandboxType SandboxType { get; set; } - public string SandboxTypeName - { - get { return SandboxType.ToString(); } - } + public string SandboxTypeName => SandboxType.ToString(); [NotMapped] - public string Status { get; set; } - - /// - /// Indicates client access status to the key. - /// "Not Sent": credentials has not been sent to the client yet - /// "Sent": challenge has been sent to the client and waiting for activation - /// "Active": client has successfully retrieved the credentials - /// "Locked": client has retried more than what they are supposed to - /// - public string KeyStatus { get; set; } - - /// - /// A random ID to be emailed to the client to enable them to challenge activationCode - /// - public string ChallengeId { get; set; } - - /// - /// Time-stamp of ChallengeId and ActivationCode generation - /// + public string Status { get; set; } = string.Empty; + + public string KeyStatus { get; set; } = string.Empty; + + public string ChallengeId { get; set; } = string.Empty; + public DateTime? ChallengeExpiry { get; set; } - /// - /// Expecting challenge answer to activate the api and send credentials - /// - public string ActivationCode { get; set; } + public string ActivationCode { get; set; } = string.Empty; - /// - /// Number of retries client has done to get the credentials. - /// public int? ActivationRetried { get; set; } - /// - /// Have a reference to OwnershipToken table ownershiptokenid for specific apiclient. - /// - public virtual OwnershipToken CreatorOwnershipToken { get; set; } + public virtual OwnershipToken? CreatorOwnershipToken { get; set; } [Column("CreatorOwnershipTokenId_OwnershipTokenId")] public short? CreatorOwnershipTokenId { get; set; } - /// - /// Fully namespaced URI reference to the StudentIdentificationSystemDescriptor value to use for identification mapping - /// [StringLength(306)] - public string StudentIdentificationSystemDescriptor { get; set; } + public string StudentIdentificationSystemDescriptor { get; set; } = string.Empty; - public virtual Application Application { get; set; } + public virtual Application? Application { get; set; } - public virtual User User { get; set; } + public virtual User? User { get; set; } public virtual ICollection ApplicationEducationOrganizations { get; set; } public virtual List ClientAccessTokens { get; set; } - /// - /// Key-value store of EdOrg and Domain Connection information - /// - /// - /// EdOrg is the key, Domain Connection information is the value. - /// The end-user should never see the Data Connection information - /// [NotMapped] public Dictionary Domains { get; set; } - /// - /// Method to generate a new secret 128-bit crypto-strength random number - /// and returns the new secret for display or other purposes. - /// - /// The length of the string to be generated - /// Random string with only alphanumeric values (no '+' or '/') private static string GenerateRandomString(int length = 24) { string result; @@ -182,10 +113,6 @@ private static string GenerateRandomString(int length = 24) return result.Substring(0, length); } - /// - /// Set a new secret for the Client - /// - /// New client secret value public string GenerateSecret() { return Secret = GenerateRandomString(); diff --git a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/ApiClientOwnershipToken.cs b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/ApiClientOwnershipToken.cs index f305decf5..a7217cd8e 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/ApiClientOwnershipToken.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/ApiClientOwnershipToken.cs @@ -8,21 +8,23 @@ namespace EdFi.Ods.AdminApi.V1.Admin.DataAccess.Models { - /// - /// Class representing the assignment of one or more ownership tokens to an API client. - /// A API Client has a list of Ownership tokens. - /// + /// + /// Class representing the assignment of one or more ownership tokens to an API client. + /// A API Client has a list of Ownership tokens. + /// public class ApiClientOwnershipToken { - /// - /// Numeric Identifier which is an Identity column which distinguish the uniques combination of ApiClient and Ownership Token - /// + /// + /// Numeric Identifier which is an Identity column which distinguish the uniques combination of ApiClient and Ownership Token + /// [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int ApiClientOwnershipTokenId { get; set; } - public virtual ApiClient ApiClient { get; set; } + [Required] + public virtual ApiClient ApiClient { get; set; } = null!; - public virtual OwnershipToken OwnershipToken { get; set; } + [Required] + public virtual OwnershipToken OwnershipToken { get; set; } = null!; } } diff --git a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/Application.cs b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/Application.cs index 2a1ed3091..970a07f30 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/Application.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/Application.cs @@ -3,8 +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.Collections.Generic; -using System.Collections.ObjectModel; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; @@ -14,27 +12,28 @@ public class Application { public Application() { - ApplicationEducationOrganizations = new Collection(); - ApiClients = new Collection(); - Profiles = new Collection(); + ApplicationEducationOrganizations = []; + ApiClients = []; + Profiles = []; + OperationalContextUri = string.Empty; } [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int ApplicationId { get; set; } - public string ApplicationName { get; set; } + public string? ApplicationName { get; set; } [StringLength(255)] - public string ClaimSetName { get; set; } + public string? ClaimSetName { get; set; } - public virtual Vendor Vendor { get; set; } + public virtual Vendor? Vendor { get; set; } public virtual OdsInstance? OdsInstance { get; set; } [StringLength(255)] [Required] - public string OperationalContextUri { get; set; } + public required string OperationalContextUri { get; set; } public virtual ICollection ApplicationEducationOrganizations { get; set; } @@ -43,7 +42,7 @@ public Application() public virtual ICollection Profiles { get; set; } public ApplicationEducationOrganization CreateApplicationEducationOrganization(int educationOrganizationId) - => new ApplicationEducationOrganization + => new() { EducationOrganizationId = educationOrganizationId, Application = this, diff --git a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/ApplicationEducationOrganization.cs b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/ApplicationEducationOrganization.cs index e5e52dd6c..b9dfc79ff 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/ApplicationEducationOrganization.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/ApplicationEducationOrganization.cs @@ -21,7 +21,7 @@ public ApplicationEducationOrganization() [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int ApplicationEducationOrganizationId { get; set; } - public virtual Application Application { get; set; } + public virtual Application? Application { get; set; } public int EducationOrganizationId { get; set; } diff --git a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/ClientAccessToken.cs b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/ClientAccessToken.cs index 42469c423..96ff8d854 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/ClientAccessToken.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/ClientAccessToken.cs @@ -36,14 +36,14 @@ public Guid Id set { _id = value; } } - public virtual ApiClient ApiClient { get; set; } + public virtual ApiClient? ApiClient { get; set; } public DateTime Expiration { get; set; } [NotMapped] public TimeSpan Duration { get; } - public string Scope { get; set; } + public string? Scope { get; set; } public override string ToString() { diff --git a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/OAuthTokenClient.cs b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/OAuthTokenClient.cs index f79e31e3c..e1cc6d6bd 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/OAuthTokenClient.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/OAuthTokenClient.cs @@ -9,24 +9,24 @@ namespace EdFi.Ods.AdminApi.V1.Admin.DataAccess.Models { public class OAuthTokenClient { - public string Key { get; set; } + public string Key { get; set; } = string.Empty; public bool UseSandbox { get; set; } - public string StudentIdentificationSystemDescriptor { get; set; } + public string StudentIdentificationSystemDescriptor { get; set; } = string.Empty; public int? EducationOrganizationId { get; set; } - public string ClaimSetName { get; set; } + public string ClaimSetName { get; set; } = string.Empty; - public string NamespacePrefix { get; set; } + public string NamespacePrefix { get; set; } = string.Empty; - public string ProfileName { get; set; } + public string ProfileName { get; set; } = string.Empty; public short? CreatorOwnershipTokenId { get; set; } public short? OwnershipTokenId { get; set; } - + public DateTime Expiration { get; set; } public int ApiClientId { get; set; } diff --git a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/OdsInstance.cs b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/OdsInstance.cs index c1ec2d968..0ba2a2244 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/OdsInstance.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/OdsInstance.cs @@ -3,8 +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.Collections.Generic; -using System.Collections.ObjectModel; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; @@ -14,7 +12,7 @@ public class OdsInstance { public OdsInstance() { - OdsInstanceComponents = new Collection(); + OdsInstanceComponents = []; } [Key] @@ -26,21 +24,21 @@ public OdsInstance() /// [Required] [StringLength(100)] - public string Name { get; set; } + public required string Name { get; set; } /// /// Type of ODS instance this identifies (e.g. "Enterprise" or "Cloud") /// [Required] [StringLength(100)] - public string InstanceType { get; set; } + public required string InstanceType { get; set; } /// /// Current status of this ODS instance, for display/use by management tooling /// [Required] [StringLength(100)] - public string Status { get; set; } + public required string Status { get; set; } /// /// If set to true, signifies that this ODS installation has been extended with custom code @@ -52,7 +50,7 @@ public OdsInstance() /// [Required] [StringLength(20)] - public string Version { get; set; } + public required string Version { get; set; } public virtual ICollection OdsInstanceComponents { get; set; } } diff --git a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/OdsInstanceComponent.cs b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/OdsInstanceComponent.cs index 25374260c..cb16db3b5 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/OdsInstanceComponent.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/OdsInstanceComponent.cs @@ -19,22 +19,22 @@ public class OdsInstanceComponent /// [Required] [StringLength(100)] - public string Name { get; set; } + public required string Name { get; set; } /// /// Url at which this component is accessible, for use by management tooling /// [Required] [StringLength(200)] - public string Url { get; set; } + public required string Url { get; set; } /// /// Version number of this ODS component /// [Required] [StringLength(20)] - public string Version { get; set; } + public required string Version { get; set; } - public virtual OdsInstance OdsInstance { get; set; } + public required virtual OdsInstance OdsInstance { get; set; } } } diff --git a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/OwnershipToken.cs b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/OwnershipToken.cs index d31faf533..92e2c6aeb 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/OwnershipToken.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/OwnershipToken.cs @@ -25,12 +25,12 @@ public OwnershipToken() /// [Key] public short OwnershipTokenId { get; set; } - + /// /// Descriptive name for the token string length is 50 char /// [StringLength(50)] - public string Description { get; set; } + public string Description { get; set; } = string.Empty; public virtual ICollection ApiClients { get; set; } } diff --git a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/Profile.cs b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/Profile.cs index 6a36ca241..383e7d3b0 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/Profile.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/Profile.cs @@ -22,7 +22,7 @@ public Profile() public int ProfileId { get; set; } [Required] - public string ProfileName { get; set; } + public required string ProfileName { get; set; } public virtual ICollection Applications { get; set; } } diff --git a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/Vendor.cs b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/Vendor.cs index 1103d15be..47b97a3f6 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/Vendor.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/Vendor.cs @@ -3,8 +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.Collections.Generic; -using System.Collections.ObjectModel; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; @@ -14,22 +12,22 @@ public class Vendor { public Vendor() { - Applications = new Collection(); - Users = new Collection(); - VendorNamespacePrefixes = new Collection(); + Applications = []; + Users = []; + VendorNamespacePrefixes = []; } [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int VendorId { get; set; } - public string VendorName { get; set; } + public string? VendorName { get; set; } public virtual ICollection Applications { get; set; } public virtual ICollection Users { get; set; } - public virtual ICollection VendorNamespacePrefixes { get; set; } + public virtual ICollection? VendorNamespacePrefixes { get; set; } public Application CreateApplication(string applicationName, string claimSetName) { @@ -37,7 +35,8 @@ public Application CreateApplication(string applicationName, string claimSetName { ApplicationName = applicationName, Vendor = this, - ClaimSetName = claimSetName + ClaimSetName = claimSetName, + OperationalContextUri = string.Empty }; Applications.Add(application); @@ -46,10 +45,12 @@ public Application CreateApplication(string applicationName, string claimSetName public static Vendor Create(string vendorName, IEnumerable namespacePrefixes) { - var vendor = new Vendor {VendorName = vendorName}; + var vendor = new Vendor { VendorName = vendorName }; foreach (string namespacePrefix in namespacePrefixes) { + vendor.VendorNamespacePrefixes ??= []; + vendor.VendorNamespacePrefixes.Add( new VendorNamespacePrefix { diff --git a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/VendorNamespacePrefix.cs b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/VendorNamespacePrefix.cs index e4d965651..0452e34ff 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/VendorNamespacePrefix.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Models/VendorNamespacePrefix.cs @@ -15,10 +15,10 @@ public class VendorNamespacePrefix public int VendorNamespacePrefixId { get; set; } [Required] - public virtual Vendor Vendor { get; set; } + public required virtual Vendor Vendor { get; set; } [Required] [StringLength(255)] - public string NamespacePrefix { get; set; } + public required string NamespacePrefix { get; set; } } } diff --git a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Repositories/ClientAppRepo.cs b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Repositories/ClientAppRepo.cs index 7fbeae092..2eb35640a 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Repositories/ClientAppRepo.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Repositories/ClientAppRepo.cs @@ -14,11 +14,9 @@ namespace EdFi.Ods.AdminApi.V1.Admin.DataAccess.Repositories { public class ClientAppRepo : IClientAppRepo { - private const int DefaultDuration = 60; private readonly IUsersContextFactory _contextFactory; private readonly ILog _logger = LogManager.GetLogger(typeof(ClientAppRepo)); - private readonly Lazy _duration; private readonly Lazy _defaultOperationalContextUri; private readonly Lazy _defaultAppName; private readonly Lazy _defaultClaimSetName; @@ -30,127 +28,102 @@ public ClientAppRepo( _contextFactory = Preconditions.ThrowIfNull(contextFactory, nameof(contextFactory)); Preconditions.ThrowIfNull(config, nameof(config)); - _duration = new Lazy( - () => - { - // Get the config value, defaulting to 1 hour - if (!int.TryParse( - config.GetSection("BearerTokenTimeoutMinutes") - .Value, - out int duration)) - { - duration = DefaultDuration; - } - - return duration; - }); - _defaultOperationalContextUri = new Lazy( - () => config.GetSection("DefaultOperationalContextUri") - .Value); + () => config.GetSection("DefaultOperationalContextUri")?.Value ?? string.Empty); _defaultAppName = new Lazy( - () => config.GetSection("DefaultApplicationName") - .Value); + () => config.GetSection("DefaultApplicationName")?.Value ?? string.Empty); _defaultClaimSetName = new Lazy( - () => config.GetSection("DefaultClaimSetName") - .Value); + () => config.GetSection("DefaultClaimSetName")?.Value ?? string.Empty); } private Profile GetOrCreateProfile(string profileName) { - using (var context = _contextFactory.CreateContext()) - { - var profiles = context.Profiles.FirstOrDefault(s => s.ProfileName == profileName); - - if (profiles == null) - { - context.Profiles.Add(new Profile { ProfileName = profileName }); - context.SaveChanges(); - } + using var context = _contextFactory.CreateContext(); + var profiles = context.Profiles.FirstOrDefault(s => s.ProfileName == profileName); - return context.Profiles.FirstOrDefault(s => s.ProfileName == profileName); + if (profiles == null) + { + context.Profiles.Add(new Profile { ProfileName = profileName }); + context.SaveChanges(); } + + return context.Profiles.First(s => s.ProfileName == profileName); } private OwnershipToken GetOrCreateOwnershipToken(string ownershipToken) { - using (var context = _contextFactory.CreateContext()) - { - var ownershipTokens = context.OwnershipTokens.FirstOrDefault(s => s.Description == ownershipToken); - - if (ownershipTokens == null) - { - context.OwnershipTokens.Add(new OwnershipToken { Description = ownershipToken }); - context.SaveChanges(); - } + using var context = _contextFactory.CreateContext(); + var ownershipTokens = context.OwnershipTokens.FirstOrDefault(s => s.Description == ownershipToken); - return context.OwnershipTokens.FirstOrDefault(s => s.Description == ownershipToken); + if (ownershipTokens == null) + { + context.OwnershipTokens.Add(new OwnershipToken { Description = ownershipToken }); + context.SaveChanges(); } + + return context.OwnershipTokens.First(s => s.Description == ownershipToken); } public void AddOwnershipTokensToApiClient(string ownershipToken, int apiClientId) { - using (var context = _contextFactory.CreateContext()) - { - var ownershiptoken = GetOrCreateOwnershipToken(ownershipToken); + using var context = _contextFactory.CreateContext(); + var ownershiptoken = GetOrCreateOwnershipToken(ownershipToken); - var currentOwnershipToken = context.OwnershipTokens - .Include(u => u.ApiClients) - .FirstOrDefault(u => u.OwnershipTokenId == ownershiptoken.OwnershipTokenId); + var currentOwnershipToken = context.OwnershipTokens + .Include(u => u.ApiClients) + .FirstOrDefault(u => u.OwnershipTokenId == ownershiptoken.OwnershipTokenId); - if (!currentOwnershipToken.ApiClients.Any(a => a.ApiClientId == apiClientId)) + if (currentOwnershipToken != null) + { + var apiClient = context.Clients.FirstOrDefault(a => a.ApiClientId == apiClientId); + if (apiClient != null && !currentOwnershipToken.ApiClients.Any(a => a.ApiClientId == apiClientId)) { - var apiClient = context.Clients.FirstOrDefault(a => a.ApiClientId == apiClientId); currentOwnershipToken.ApiClients.Add(apiClient); } - - context.SaveChanges(); } + + context.SaveChanges(); } public void AddApiClientOwnershipTokens(List ownershipTokens, int apiClientId) { - using (var context = _contextFactory.CreateContext()) + using var context = _contextFactory.CreateContext(); + var apiClientOwnershipTokenList = new List(); + foreach (var ownershipToken in ownershipTokens) { - var apiClientOwnershipTokenList = new List(); - foreach (var ownershipToken in ownershipTokens) + var ownershiptoken = context.OwnershipTokens.First(x => x.Description == ownershipToken); + var apiClient = context.Clients.First(u => u.ApiClientId == apiClientId); + apiClientOwnershipTokenList.Add(new ApiClientOwnershipToken { - var ownershiptoken = context.OwnershipTokens.FirstOrDefault(x => x.Description == ownershipToken); - var apiClient = context.Clients.FirstOrDefault(u => u.ApiClientId == apiClientId); - apiClientOwnershipTokenList.Add(new ApiClientOwnershipToken - { - ApiClient = apiClient, - OwnershipToken = ownershiptoken - }); - } - context.ApiClientOwnershipTokens.AddRange(apiClientOwnershipTokenList); - context.SaveChanges(); + ApiClient = apiClient, + OwnershipToken = ownershiptoken + }); } + context.ApiClientOwnershipTokens.AddRange(apiClientOwnershipTokenList); + context.SaveChanges(); } public void AddProfilesToApplication(List profileNames, int applicationId) { - using (var context = _contextFactory.CreateContext()) + using var context = _contextFactory.CreateContext(); + foreach (var profileName in profileNames) { - foreach (var profileName in profileNames) - { - var profile = GetOrCreateProfile(profileName); + var profile = GetOrCreateProfile(profileName); - var currentProfile = context.Profiles - .Include(u => u.Applications) - .FirstOrDefault(u => u.ProfileId == profile.ProfileId); + var currentProfile = context.Profiles + .Include(u => u.Applications) + .First(u => u.ProfileId == profile.ProfileId); - if (!currentProfile.Applications.Any(a => a.ApplicationId == applicationId)) - { - var application = context.Applications.FirstOrDefault(a => a.ApplicationId == applicationId); - currentProfile.Applications.Add(application); - } + if (!currentProfile.Applications.Any(a => a.ApplicationId == applicationId)) + { + var application = context.Applications.First(a => a.ApplicationId == applicationId); + currentProfile.Applications.Add(application); } - - context.SaveChanges(); } + + context.SaveChanges(); } public User CreateUser(User user) @@ -166,171 +139,144 @@ public User CreateUser(User user) public IEnumerable GetUsers() { - using (var context = _contextFactory.CreateContext()) - { - return context.Users.Include(u => u.ApiClients).ThenInclude(ac => ac.Application).ToList(); - } + using var context = _contextFactory.CreateContext(); + return [.. context.Users.Include(u => u.ApiClients).ThenInclude(ac => ac.Application)]; } public User GetUser(int userId) { - using (var context = _contextFactory.CreateContext()) - { - return - context.Users.Include(u => u.ApiClients).ThenInclude(ac => ac.Application) - .FirstOrDefault(u => u.UserId == userId); - } + using var context = _contextFactory.CreateContext(); + return + context.Users.Include(u => u.ApiClients).ThenInclude(ac => ac.Application) + .First(u => u.UserId == userId); } public User GetUser(string userName) { - using (var context = _contextFactory.CreateContext()) - { - return - context.Users.Include(u => u.ApiClients).ThenInclude(a => a.Application) - .Include(u => u.Vendor) - .FirstOrDefault(x => x.Email == userName); - } + using var context = _contextFactory.CreateContext(); + return + context.Users.Include(u => u.ApiClients).ThenInclude(a => a.Application) + .Include(u => u.Vendor) + .First(x => x.Email == userName); } public void DeleteUser(User userProfile) { - using (var context = _contextFactory.CreateContext()) - { - var user = - context.Users.Include(u => u.ApiClients).ThenInclude(ac => ac.Application) - .FirstOrDefault(x => x.UserId == userProfile.UserId); - - if (user == null) - { - return; - } + using var context = _contextFactory.CreateContext(); + var user = + context.Users.Include(u => u.ApiClients).ThenInclude(ac => ac.Application) + .FirstOrDefault(x => x.UserId == userProfile.UserId); - var arraySoThatUnderlyingCollectionCanBeModified = user.ApiClients.ToArray(); + if (user == null) + { + return; + } - foreach (var client in arraySoThatUnderlyingCollectionCanBeModified) - { - context.Clients.Remove(client); - } + var arraySoThatUnderlyingCollectionCanBeModified = user.ApiClients.ToArray(); - context.Users.Remove(user); - context.SaveChanges(); + foreach (var client in arraySoThatUnderlyingCollectionCanBeModified) + { + context.Clients.Remove(client); } + + context.Users.Remove(user); + context.SaveChanges(); } - public ApiClient GetClient(string key) + public ApiClient? GetClient(string key) { - using (var context = _contextFactory.CreateContext()) - { - return context.Clients - .Include(c => c.Application) - .ThenInclude(c => c.Vendor) - .ThenInclude(c => c.VendorNamespacePrefixes) - .Include(c => c.Application) - .ThenInclude(c => c.Profiles) - .Include(c => c.ApplicationEducationOrganizations) - .Include(c => c.CreatorOwnershipToken) - .FirstOrDefault(c => c.Key == key); - } + using var context = _contextFactory.CreateContext(); + return context.Clients + .Include(c => c.Application) + .ThenInclude(c => c!.Vendor) + .ThenInclude(c => c!.VendorNamespacePrefixes) + .Include(c => c.Application) + .ThenInclude(c => c!.Profiles) + .Include(c => c.ApplicationEducationOrganizations) + .Include(c => c.CreatorOwnershipToken) + .FirstOrDefault(c => c.Key == key); } - public async Task GetClientAsync(string key) + public async Task GetClientAsync(string key) { - using (var context = _contextFactory.CreateContext()) - { - return await context.Clients - .Include(c => c.Application) - .ThenInclude(c => c.Vendor) - .ThenInclude(c => c.VendorNamespacePrefixes) - .Include(c => c.Application) - .ThenInclude(c => c.Profiles) - .Include(c => c.ApplicationEducationOrganizations) - .Include(c => c.CreatorOwnershipTokenId) - .FirstOrDefaultAsync(c => c.Key == key); - } + using var context = _contextFactory.CreateContext(); + return await context.Clients + .Include(c => c.Application!) + .ThenInclude(c => c.Vendor) + .ThenInclude(c => c!.VendorNamespacePrefixes) + .Include(c => c.Application!) + .ThenInclude(c => c.Profiles) + .Include(c => c.ApplicationEducationOrganizations) + .Include(c => c.CreatorOwnershipTokenId) + .FirstOrDefaultAsync(c => c.Key == key); } - public ApiClient GetClient(string key, string secret) + public ApiClient? GetClient(string key, string secret) { - using (var context = _contextFactory.CreateContext()) - { - return context.Clients.FirstOrDefault(c => c.Key == key && c.Secret == secret); - } + using var context = _contextFactory.CreateContext(); + return context.Clients.FirstOrDefault(c => c.Key == key && c.Secret == secret); } - public ApiClient GetClientByKey(string key) + public ApiClient? GetClientByKey(string key) { - using (var context = _contextFactory.CreateContext()) - { - return context.Clients.FirstOrDefault(c => c.Key == key); - } + using var context = _contextFactory.CreateContext(); + return context.Clients.FirstOrDefault(c => c.Key == key); } public ApiClient UpdateClient(ApiClient client) { - using (var context = _contextFactory.CreateContext()) - { - context.Clients.Update(client); - context.SaveChanges(); - return client; - } + using var context = _contextFactory.CreateContext(); + context.Clients.Update(client); + context.SaveChanges(); + return client; } public void DeleteClient(string key) { - using (var context = _contextFactory.CreateContext()) - { - var client = context.Clients.First(x => x.Key == key); + using var context = _contextFactory.CreateContext(); + var client = context.Clients.First(x => x.Key == key); - context.ExecuteSqlCommandAsync( - @"delete from dbo.ClientAccessTokens where ApiClient_ApiClientId = @p0; delete from dbo.ApiClients where ApiClientId = @p0", - client.ApiClientId).Wait(); - } + context.ExecuteSqlCommandAsync( + @"delete from dbo.ClientAccessTokens where ApiClient_ApiClientId = @p0; delete from dbo.ApiClients where ApiClientId = @p0", + client.ApiClientId).Wait(); } public Application[] GetVendorApplications(int vendorId) { - using (var context = _contextFactory.CreateContext()) - { - return context.Applications.Where(a => a.Vendor.VendorId == vendorId) - .ToArray(); - } + using var context = _contextFactory.CreateContext(); + return [.. context.Applications.Where(a => a.Vendor != null && a.Vendor.VendorId == vendorId)]; } public void AddApiClientToUserWithVendorApplication(int userId, ApiClient client) { - using (var context = _contextFactory.CreateContext()) - { - var user = context.Users - .Include(u => u.Vendor) - .Include(v => v.Vendor.Applications) - .SingleOrDefault(u => u.UserId == userId); - - if (user == null) - { - return; - } + using var context = _contextFactory.CreateContext(); + var user = context.Users + .Include(u => u.Vendor) + .Include(v => v.Vendor.Applications) + .SingleOrDefault(u => u.UserId == userId); - if (user.Vendor != null) - { - client.Application = user.Vendor.Applications.FirstOrDefault(); - } + if (user == null) + { + return; + } - context.Clients.Add(client); - context.SaveChanges(); + if (user.Vendor != null) + { + client.Application = user.Vendor.Applications.FirstOrDefault(); } + + context.Clients.Add(client); + context.SaveChanges(); } public ApiClient CreateApiClient(int userId, string name, string key, string secret) { - using (var context = _contextFactory.CreateContext()) - { - var client = CreateApiClient(context, userId, name, SandboxType.Sample, key, secret); + using var context = _contextFactory.CreateContext(); + var client = CreateApiClient(context, userId, name, SandboxType.Sample, key, secret); - context.SaveChanges(); + context.SaveChanges(); - return client; - } + return client; } public void SetupKeySecret( @@ -341,56 +287,54 @@ public void SetupKeySecret( int userId, int applicationId) { - using (var context = _contextFactory.CreateContext()) - { - var client = CreateApiClient(context, userId, name, sandboxType, key, secret); + using var context = _contextFactory.CreateContext(); + var client = CreateApiClient(context, userId, name, sandboxType, key, secret); - AddApplicationEducationOrganizations(context, applicationId, client); + AddApplicationEducationOrganizations(context, applicationId, client); - context.SaveChanges(); - } + context.SaveChanges(); } private ApiClient CreateApiClient( - IUsersContext context, - int userId, - string name, - SandboxType sandboxType, - string key, - string secret) + IUsersContext context, + int userId, + string name, + SandboxType sandboxType, + string key, + string secret) { var attachedUser = context.Users.Find(userId); - return attachedUser.AddSandboxClient(name, sandboxType, key, secret); + return attachedUser == null + ? throw new InvalidOperationException($"User with ID {userId} not found.") + : attachedUser.AddSandboxClient(name, sandboxType, key, secret); } public void AddEdOrgIdsToApiClient(int userId, int apiClientId, IList edOrgIds, int applicationId) { - using (var context = _contextFactory.CreateContext()) - { - var application = context.Applications - .Include(a => a.ApplicationEducationOrganizations) - .Single(a => a.ApplicationId == applicationId); - - var user = context.Users.FirstOrDefault(u => u.UserId == userId); + using var context = _contextFactory.CreateContext(); + var application = context.Applications + .Include(a => a.ApplicationEducationOrganizations) + .Single(a => a.ApplicationId == applicationId); - var client = user?.ApiClients.FirstOrDefault(c => c.ApiClientId == apiClientId); + var user = context.Users.FirstOrDefault(u => u.UserId == userId); - if (client == null) - { - return; - } + var client = user?.ApiClients.FirstOrDefault(c => c.ApiClientId == apiClientId); - client.Application = application; + if (client == null) + { + return; + } - foreach (var applicationEducationOrganization in application.ApplicationEducationOrganizations.Where( - s => edOrgIds.Contains(s.EducationOrganizationId))) - { - client.ApplicationEducationOrganizations.Add(applicationEducationOrganization); - } + client.Application = application; - context.SaveChanges(); + foreach (var applicationEducationOrganization in application.ApplicationEducationOrganizations.Where( + s => edOrgIds.Contains(s.EducationOrganizationId))) + { + client.ApplicationEducationOrganizations.Add(applicationEducationOrganization); } + + context.SaveChanges(); } private void AddApplicationEducationOrganizations(IUsersContext context, int applicationId, ApiClient client) @@ -415,32 +359,29 @@ public ApiClient SetupDefaultSandboxClient( int userId, int applicationId) { - using (var context = _contextFactory.CreateContext()) - { - _logger.Debug($"Creating API Client"); - var client = GetClient(key, secret) ?? CreateApiClient(context, userId, name, sandboxType, key, secret); + using var context = _contextFactory.CreateContext(); + _logger.Debug($"Creating API Client"); + var client = GetClient(key, secret) ?? CreateApiClient(context, userId, name, sandboxType, key, secret); - _logger.Debug($"Adding Education Organization to client"); - AddApplicationEducationOrganizations(context, applicationId, client); + _logger.Debug($"Adding Education Organization to client"); + AddApplicationEducationOrganizations(context, applicationId, client); - context.SaveChanges(); + context.SaveChanges(); - return client; - } + return client; } public void Reset() { try { - using (var context = _contextFactory.CreateContext()) + using var context = _contextFactory.CreateContext(); + if (context is DbContext dbContext) { - var dbContext = context as DbContext; - try { - //Admin.Web Creates table webpages_UsersInRoles. - //If exists remove rows, if not swallow exception. + // Admin.Web Creates table webpages_UsersInRoles. + // If exists remove rows, if not swallow exception. dbContext.DeleteAll(); context.SaveChanges(); } @@ -466,30 +407,28 @@ public void SetDefaultVendorOnUserFromEmailAndName(string userEmail, string user { var namespacePrefix = "uri://" + userEmail.Split('@')[1].ToLower(); - SetDefaultVendorOnUserFromEmailAndName(userEmail, userName, new List { namespacePrefix }); + SetDefaultVendorOnUserFromEmailAndName(userEmail, userName, [namespacePrefix]); } public void SetDefaultVendorOnUserFromEmailAndName(string userEmail, string userName, IEnumerable namespacePrefixes) { - using (var context = _contextFactory.CreateContext()) - { - var vendor = FindOrCreateVendorByDomainName(userName, namespacePrefixes); + using var context = _contextFactory.CreateContext(); + var vendor = FindOrCreateVendorByDomainName(userName, namespacePrefixes); - var user = context.Users.FirstOrDefault(u => u.Email.Equals(userEmail)); + var user = context.Users.FirstOrDefault(u => u.Email.Equals(userEmail)); - if (user == null) - { - user = User.Create(userEmail, userName, vendor); - } - else - { - user.Vendor = vendor; - } - - context.Vendors.Update(vendor); - context.Users.Update(user); - context.SaveChanges(); + if (user == null) + { + user = User.Create(userEmail, userName, vendor); + } + else + { + user.Vendor = vendor; } + + context.Vendors.Update(vendor); + context.Users.Update(user); + context.SaveChanges(); } public Vendor CreateOrGetVendor(string userEmail, string userName, IEnumerable namespacePrefixes) @@ -497,104 +436,96 @@ public Vendor CreateOrGetVendor(string userEmail, string userName, IEnumerable v.VendorName == vendorName); - - if (vendor == null) - { - vendor = Vendor.Create(vendorName, namespacePrefixes); - context.SaveChanges(); - } + using var context = _contextFactory.CreateContext(); + var vendor = context.Vendors.SingleOrDefault(v => v.VendorName == vendorName); - return vendor; + if (vendor == null) + { + vendor = Vendor.Create(vendorName, namespacePrefixes); + context.SaveChanges(); } + + return vendor; } private Vendor FindOrCreateVendorByDomainName(string vendorName, IEnumerable namespacePrefixes) { - using (var context = _contextFactory.CreateContext()) - { - var vendor = context.Vendors.FirstOrDefault(v => v.VendorName == vendorName); + using var context = _contextFactory.CreateContext(); + var vendor = context.Vendors.FirstOrDefault(v => v.VendorName == vendorName); - if (vendor != null) - { - return vendor; - } + if (vendor != null) + { + return vendor; + } - var newVendor = Vendor.Create(vendorName, namespacePrefixes); + var newVendor = Vendor.Create(vendorName, namespacePrefixes); - context.Vendors.Update(newVendor); + context.Vendors.Update(newVendor); - //TODO: DEA - Move this behavior to happen during client creation. No need to do this in two places. At a minimum, remove the duplicated code. - CreateDefaultApplicationForVendor(newVendor); + //TODO: DEA - Move this behavior to happen during client creation. No need to do this in two places. At a minimum, remove the duplicated code. + CreateDefaultApplicationForVendor(newVendor); - return newVendor; - } + return newVendor!; } public Application CreateApplicationForVendor(int vendorId, string applicationName, string claimSetName) { - using (var context = _contextFactory.CreateContext()) - { - var app = - context.Applications.SingleOrDefault( - a => a.ApplicationName == applicationName && a.Vendor.VendorId == vendorId); + using var context = _contextFactory.CreateContext(); + var app = + context.Applications.SingleOrDefault( + a => a.ApplicationName == applicationName && a.Vendor != null && a.Vendor.VendorId == vendorId); - if (app != null) - { - return app; - } + if (app != null) + { + return app; + } - var vendor = context.Vendors.FirstOrDefault(v => v.VendorId == vendorId); + var vendor = context.Vendors.FirstOrDefault(v => v.VendorId == vendorId); - app = new Application - { - ApplicationName = applicationName, - Vendor = vendor, - ClaimSetName = claimSetName, - OperationalContextUri = _defaultOperationalContextUri.Value - }; + app = new Application + { + ApplicationName = applicationName, + Vendor = vendor, + ClaimSetName = claimSetName, + OperationalContextUri = _defaultOperationalContextUri.Value + }; - context.Applications.Update(app); + context.Applications.Update(app); - context.SaveChanges(); + context.SaveChanges(); - return app; - } + return app; } private void CreateDefaultApplicationForVendor(Vendor vendor) { - using (var context = _contextFactory.CreateContext()) + using var context = _contextFactory.CreateContext(); + var app = context.Applications.SingleOrDefault( + a => a.ApplicationName == _defaultAppName.Value && a.Vendor != null && a.Vendor.VendorId == vendor.VendorId); + + if (app != null) { - var app = context.Applications.SingleOrDefault( - a => a.ApplicationName == _defaultAppName.Value && a.Vendor.VendorId == vendor.VendorId); + return; + } - if (app != null) + context.Applications.Update( + new Application { - return; - } - - context.Applications.Update( - new Application - { - ApplicationName = _defaultAppName.Value, - Vendor = vendor, - ClaimSetName = _defaultClaimSetName.Value, - OperationalContextUri = _defaultOperationalContextUri.Value - }); - } + ApplicationName = _defaultAppName.Value, + Vendor = vendor, + ClaimSetName = _defaultClaimSetName.Value, + OperationalContextUri = _defaultOperationalContextUri.Value + }); } internal class EmailResult { - public string Email { get; set; } + public string Email { get; set; } = string.Empty; } internal class ConfirmationTokenResult { - public string ConfirmationToken { get; set; } + public string ConfirmationToken { get; set; } = string.Empty; } } } diff --git a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Repositories/IClientAppRepo.cs b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Repositories/IClientAppRepo.cs index 4807382e0..6a15b4906 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Repositories/IClientAppRepo.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Repositories/IClientAppRepo.cs @@ -22,11 +22,11 @@ public interface IClientAppRepo void DeleteUser(User userProfile); - ApiClient GetClient(string key); + ApiClient? GetClient(string key); - Task GetClientAsync(string key); + Task GetClientAsync(string key); - ApiClient GetClient(string key, string secret); + ApiClient? GetClient(string key, string secret); ApiClient UpdateClient(ApiClient client); @@ -58,6 +58,6 @@ public interface IClientAppRepo void AddApiClientOwnershipTokens(List ownershipTokens, int apiClientId); - ApiClient GetClientByKey(string key); + ApiClient? GetClientByKey(string key); } } diff --git a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Security/EdFiAdminApiClientSecretWriter.cs b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Security/EdFiAdminApiClientSecretWriter.cs index a994d5b36..008c3b597 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Security/EdFiAdminApiClientSecretWriter.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Security/EdFiAdminApiClientSecretWriter.cs @@ -33,7 +33,7 @@ public void SetSecret(string key, ApiClientSecret secret) private ApiClient GetClientByKey(string key) { - var client = _clientAppRepo.GetClientByKey(key); + var client = _clientAppRepo.GetClientByKey(key); if (client == null) { diff --git a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Utils/DefaultApplicationCreator.cs b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Utils/DefaultApplicationCreator.cs index 8ad53e8bb..afa919afc 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Utils/DefaultApplicationCreator.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Admin.DataAccess/Utils/DefaultApplicationCreator.cs @@ -80,9 +80,22 @@ private Application GetApplication(IUsersContext context, Vendor vendor, string } var defaultClaimSetName = _configuration.GetSection("DefaultClaimSetName").Value; + + if (string.IsNullOrWhiteSpace(defaultClaimSetName)) + { + throw new InvalidOperationException("DefaultClaimSetName configuration value is missing or empty."); + } + + var defaultOperationalContextUri = _configuration.GetSection("DefaultOperationalContextUri").Value; + + if (string.IsNullOrWhiteSpace(defaultOperationalContextUri)) + { + throw new InvalidOperationException("DefaultOperationalContextUri configuration value is missing or empty."); + } + var newApplication = vendor.CreateApplication(applicationName, defaultClaimSetName); - newApplication.OperationalContextUri = _configuration.GetSection("DefaultOperationalContextUri").Value; + newApplication.OperationalContextUri = defaultOperationalContextUri; context.Applications.Add(newApplication); return newApplication; } diff --git a/Application/EdFi.Ods.AdminApi.V1/EdFi.Ods.AdminApi.V1.csproj b/Application/EdFi.Ods.AdminApi.V1/EdFi.Ods.AdminApi.V1.csproj index cc148753c..93c83a920 100644 --- a/Application/EdFi.Ods.AdminApi.V1/EdFi.Ods.AdminApi.V1.csproj +++ b/Application/EdFi.Ods.AdminApi.V1/EdFi.Ods.AdminApi.V1.csproj @@ -11,6 +11,7 @@ --no-cache .env adminapi-dev + true Library diff --git a/Application/EdFi.Ods.AdminApi.V1/Features/Applications/AddApplication.cs b/Application/EdFi.Ods.AdminApi.V1/Features/Applications/AddApplication.cs index 37a7fb91d..4de0d3474 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Features/Applications/AddApplication.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Features/Applications/AddApplication.cs @@ -51,7 +51,7 @@ private void GuardAgainstInvalidEntityReferences(AddApplicationRequest request, public class AddApplicationRequest : IAddApplicationModel { [SwaggerSchema(Description = FeatureConstants.ApplicationNameDescription, Nullable = false)] - public string? ApplicationName { get; set; } + public string ApplicationName { get; set; } = string.Empty; [SwaggerSchema(Description = FeatureConstants.VendorIdDescription, Nullable = false)] public int VendorId { get; set; } diff --git a/Application/EdFi.Ods.AdminApi.V1/Features/Applications/EditApplication.cs b/Application/EdFi.Ods.AdminApi.V1/Features/Applications/EditApplication.cs index 98033e783..0b9b35d74 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Features/Applications/EditApplication.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Features/Applications/EditApplication.cs @@ -41,10 +41,10 @@ public async Task Handle(IEditApplicationCommand editApplicationCommand private static void GuardAgainstInvalidEntityReferences(EditApplicationRequest request, IUsersContext db) { if (null == db.Vendors.Find(request.VendorId)) - throw new ValidationException(new[] { new ValidationFailure(nameof(request.VendorId), $"Vendor with ID {request.VendorId} not found.") }); + throw new ValidationException([new ValidationFailure(nameof(request.VendorId), $"Vendor with ID {request.VendorId} not found.")]); if (request.ProfileId.HasValue && db.Profiles.Find(request.ProfileId) == null) - throw new ValidationException(new[] { new ValidationFailure(nameof(request.ProfileId), $"Profile with ID {request.ProfileId} not found.") }); + throw new ValidationException([new ValidationFailure(nameof(request.ProfileId), $"Profile with ID {request.ProfileId} not found.")]); } [SwaggerSchema(Title = "EditApplicationRequest")] @@ -54,7 +54,7 @@ public class EditApplicationRequest : IEditApplicationModel public int ApplicationId { get; set; } [SwaggerSchema(Description = FeatureConstants.ApplicationNameDescription, Nullable = false)] - public string? ApplicationName { get; set; } + public string ApplicationName { get; set; } = string.Empty; [SwaggerSchema(Description = FeatureConstants.VendorIdDescription, Nullable = false)] public int VendorId { get; set; } diff --git a/Application/EdFi.Ods.AdminApi.V1/Features/ClaimSets/ClaimSetModel.cs b/Application/EdFi.Ods.AdminApi.V1/Features/ClaimSets/ClaimSetModel.cs index 51ff55ce3..bb49614a3 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Features/ClaimSets/ClaimSetModel.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Features/ClaimSets/ClaimSetModel.cs @@ -67,7 +67,7 @@ public RequestResourceClaimModel() public class ChildrenRequestResourceClaimModel : RequestResourceClaimModel { - public List Children { get; set; } + public new List Children { get; set; } = new List(); } [SwaggerSchema(Title = "AuthorizationStrategies")] diff --git a/Application/EdFi.Ods.AdminApi.V1/Features/OdsInstances/AddOdsInstance.cs b/Application/EdFi.Ods.AdminApi.V1/Features/OdsInstances/AddOdsInstance.cs index 4260529ad..4d3656ce0 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Features/OdsInstances/AddOdsInstance.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Features/OdsInstances/AddOdsInstance.cs @@ -35,15 +35,15 @@ public async Task Handle(Validator validator, IAddOdsInstanceCommand ad public class AddOdsInstanceRequest : IAddOdsInstanceModel { [SwaggerSchema(Description = FeatureConstants.OdsInstanceName, Nullable = false)] - public string? Name { get; set; } + public string Name { get; set; } = string.Empty; [SwaggerSchema(Description = FeatureConstants.OdsInstanceInstanceType, Nullable = true)] - public string? InstanceType { get; set; } + public string InstanceType { get; set; } = string.Empty; [SwaggerSchema(Description = FeatureConstants.OdsInstanceStatus, Nullable = true)] - public string? Status { get; set; } + public string Status { get; set; } = string.Empty; [SwaggerSchema(Description = FeatureConstants.OdsInstanceIsExtended, Nullable = true)] public bool? IsExtended { get; set; } [SwaggerSchema(Description = FeatureConstants.OdsInstanceVersion, Nullable = true)] - public string? Version { get; set; } + public string Version { get; set; } = string.Empty; } public class Validator : AbstractValidator diff --git a/Application/EdFi.Ods.AdminApi.V1/Features/OdsInstances/EditOdsInstance.cs b/Application/EdFi.Ods.AdminApi.V1/Features/OdsInstances/EditOdsInstance.cs index 91a7158b4..a2970c5b0 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Features/OdsInstances/EditOdsInstance.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Features/OdsInstances/EditOdsInstance.cs @@ -45,19 +45,19 @@ public class EditOdsInstanceRequest : IEditOdsInstanceModel public int OdsInstanceId { get; set; } [SwaggerSchema(Description = FeatureConstants.OdsInstanceName, Nullable = false)] - public string? Name { get; set; } + public string Name { get; set; } = string.Empty; [SwaggerSchema(Description = FeatureConstants.OdsInstanceInstanceType, Nullable = true)] - public string? InstanceType { get; set; } + public string InstanceType { get; set; } = string.Empty; [SwaggerSchema(Description = FeatureConstants.OdsInstanceStatus, Nullable = true)] - public string? Status { get; set; } + public string Status { get; set; } = string.Empty; [SwaggerSchema(Description = FeatureConstants.OdsInstanceIsExtended, Nullable = true)] public bool? IsExtended { get; set; } [SwaggerSchema(Description = FeatureConstants.OdsInstanceVersion, Nullable = true)] - public string? Version { get; set; } + public string Version { get; set; } = string.Empty; } public class Validator : AbstractValidator diff --git a/Application/EdFi.Ods.AdminApi.V1/Features/Vendors/AddVendor.cs b/Application/EdFi.Ods.AdminApi.V1/Features/Vendors/AddVendor.cs index f27f04292..fba6c0e46 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Features/Vendors/AddVendor.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Features/Vendors/AddVendor.cs @@ -36,16 +36,16 @@ public async Task Handle(Validator validator, AddVendorCommand addVendo public class AddVendorRequest : IAddVendorModel { [SwaggerSchema(Description = FeatureConstants.VendorNameDescription, Nullable = false)] - public string? Company { get; set; } + public string Company { get; set; } = string.Empty; [SwaggerSchema(Description = FeatureConstants.VendorNamespaceDescription, Nullable = false)] - public string? NamespacePrefixes { get; set; } + public string NamespacePrefixes { get; set; } = string.Empty; [SwaggerSchema(Description = FeatureConstants.VendorContactDescription, Nullable = false)] - public string? ContactName { get; set; } + public string ContactName { get; set; } = string.Empty; [SwaggerSchema(Description = FeatureConstants.VendorContactEmailDescription, Nullable = false)] - public string? ContactEmailAddress { get; set; } + public string ContactEmailAddress { get; set; } = string.Empty; } public class Validator : AbstractValidator diff --git a/Application/EdFi.Ods.AdminApi.V1/Features/Vendors/EditVendor.cs b/Application/EdFi.Ods.AdminApi.V1/Features/Vendors/EditVendor.cs index 5c5a87f16..dd04c5e96 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Features/Vendors/EditVendor.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Features/Vendors/EditVendor.cs @@ -40,16 +40,16 @@ public class EditVendorRequest : IEditVendor public int VendorId { get; set; } [SwaggerSchema(Description = FeatureConstants.VendorNameDescription, Nullable = false)] - public string? Company { get; set; } + public string Company { get; set; } = string.Empty; [SwaggerSchema(Description = FeatureConstants.VendorNamespaceDescription, Nullable = false)] public string? NamespacePrefixes { get; set; } [SwaggerSchema(Description = FeatureConstants.VendorContactDescription, Nullable = false)] - public string? ContactName { get; set; } + public string ContactName { get; set; } = string.Empty; [SwaggerSchema(Description = FeatureConstants.VendorContactEmailDescription, Nullable = false)] - public string? ContactEmailAddress { get; set; } + public string ContactEmailAddress { get; set; } = string.Empty; } public class Validator : AbstractValidator diff --git a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/AutoMapper/AdminApiMappingProfile.cs b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/AutoMapper/AdminApiMappingProfile.cs index c018ea29f..f9e598639 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/AutoMapper/AdminApiMappingProfile.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/AutoMapper/AdminApiMappingProfile.cs @@ -13,7 +13,7 @@ using EdFi.Ods.AdminApi.V1.Infrastructure.Services.ClaimSetEditor; using Profile = AutoMapper.Profile; -namespace EdFi.Ods.AdminApi.V1.Infrastructure; +namespace EdFi.Ods.AdminApi.V1.Infrastructure.AutoMapper; public class AdminApiMappingProfile : Profile { @@ -23,22 +23,21 @@ public AdminApiMappingProfile() .ForMember(dst => dst.Company, opt => opt.MapFrom(src => src.VendorName)) .ForMember(dst => dst.ContactName, opt => opt.MapFrom(src => src.ContactName())) .ForMember(dst => dst.ContactEmailAddress, opt => opt.MapFrom(src => src.ContactEmail())) - .ForMember(dst => dst.NamespacePrefixes, opt => opt.MapFrom(src => src.VendorNamespacePrefixes.ToCommaSeparated())); + .ForMember(dst => dst.NamespacePrefixes, opt => opt.MapFrom(src => src.VendorNamespacePrefixes != null ? src.VendorNamespacePrefixes.ToCommaSeparated() : null)); CreateMap() .ForMember(dst => dst.Company, opt => opt.MapFrom(src => src.VendorName)) .ForMember(dst => dst.ContactName, opt => opt.MapFrom(src => src.ContactName())) .ForMember(dst => dst.ContactEmailAddress, opt => opt.MapFrom(src => src.ContactEmail())) - .ForMember(dst => dst.NamespacePrefixes, opt => opt.MapFrom(src => src.VendorNamespacePrefixes.ToCommaSeparated())); + .ForMember(dst => dst.NamespacePrefixes, opt => opt.MapFrom(src => src.VendorNamespacePrefixes != null ? src.VendorNamespacePrefixes.ToCommaSeparated() : null)); CreateMap() .ForMember(dst => dst.EducationOrganizationIds, opt => opt.MapFrom(src => src.EducationOrganizationIds())) .ForMember(dst => dst.ProfileName, opt => opt.MapFrom(src => src.ProfileName())) - .ForMember(dst => dst.OdsInstanceId, opt => opt.MapFrom(src => src.OdsInstance.OdsInstanceId)) + .ForMember(dst => dst.OdsInstanceId, opt => opt.MapFrom(src => src.OdsInstance != null ? src.OdsInstance.OdsInstanceId : 0)) .ForMember(dst => dst.OdsInstanceName, opt => opt.MapFrom(src => src.OdsInstanceName())) .ForMember(dst => dst.VendorId, opt => opt.MapFrom(src => src.VendorId())) .ForMember(dst => dst.Profiles, opt => opt.MapFrom(src => src.Profiles())); - CreateMap() .ForMember(dst => dst.ApplicationId, opt => opt.MapFrom(src => src.ApplicationId)) @@ -79,24 +78,24 @@ public AdminApiMappingProfile() .ForMember(dst => dst.DefaultAuthStrategiesForCRUD, opt => opt.MapFrom(src => src.DefaultAuthStrategiesForCRUD)) .ForMember(dst => dst.Children, opt => opt.MapFrom(src => src.Children)); - CreateMap() + CreateMap() .ForMember(dst => dst.AuthStrategyId, opt => opt.MapFrom(src => src.AuthStrategyId)) .ForMember(dst => dst.AuthStrategyName, opt => opt.MapFrom(src => src.AuthStrategyName)) .ForMember(dst => dst.DisplayName, opt => opt.MapFrom(src => src.DisplayName)) .ForMember(dst => dst.IsInheritedFromParent, opt => opt.MapFrom(src => src.IsInheritedFromParent)); - CreateMap() + CreateMap() .ForMember(dst => dst.AuthStrategyId, opt => opt.MapFrom(src => src.AuthStrategyId)) .ForMember(dst => dst.AuthStrategyName, opt => opt.MapFrom(src => src.AuthStrategyName)) .ForMember(dst => dst.DisplayName, opt => opt.MapFrom(src => src.DisplayName)) .ForMember(dst => dst.IsInheritedFromParent, opt => opt.MapFrom(src => src.IsInheritedFromParent)); - CreateMap() + CreateMap() .ForMember(dst => dst.AuthStrategyName, opt => opt.MapFrom(src => src.AuthorizationStrategyName)) .ForMember(dst => dst.AuthStrategyId, opt => opt.MapFrom(src => src.AuthorizationStrategyId)) .ForMember(dst => dst.IsInheritedFromParent, opt => opt.Ignore()); - CreateMap() + CreateMap() .ForMember(dst => dst.Name, opt => opt.MapFrom(src => src.Name)) .ForMember(dst => dst.Read, opt => opt.MapFrom(src => src.Read)) .ForMember(dst => dst.Update, opt => opt.MapFrom(src => src.Update)) @@ -109,9 +108,8 @@ public AdminApiMappingProfile() CreateMap() .ForMember(dst => dst.AuthorizationStrategies, opt => opt.MapFrom(src => src.AuthorizationStrategies)).ReverseMap(); - ; - CreateMap() + CreateMap() .ForMember(dst => dst.Name, opt => opt.MapFrom(src => src.Name)) .ForMember(dst => dst.Read, opt => opt.MapFrom(src => src.Read)) .ForMember(dst => dst.Update, opt => opt.MapFrom(src => src.Update)) diff --git a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/AddApplicationCommand.cs b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/AddApplicationCommand.cs index c318307bb..12d181a16 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/AddApplicationCommand.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/AddApplicationCommand.cs @@ -15,16 +15,10 @@ public interface IAddApplicationCommand AddApplicationResult Execute(IAddApplicationModel applicationModel); } -public class AddApplicationCommand : IAddApplicationCommand +public class AddApplicationCommand(IUsersContext usersContext, InstanceContext instanceContext) : IAddApplicationCommand { - private readonly IUsersContext _usersContext; - private readonly InstanceContext _instanceContext; - - public AddApplicationCommand(IUsersContext usersContext, InstanceContext instanceContext) - { - _usersContext = usersContext; - _instanceContext = instanceContext; - } + private readonly IUsersContext _usersContext = usersContext; + private readonly InstanceContext _instanceContext = instanceContext; public AddApplicationResult Execute(IAddApplicationModel applicationModel) { @@ -59,20 +53,20 @@ public AddApplicationResult Execute(IAddApplicationModel applicationModel) }; var applicationEdOrgs = applicationModel.EducationOrganizationIds == null - ? Enumerable.Empty() + ? [] : applicationModel.EducationOrganizationIds.Select(id => new ApplicationEducationOrganization { - Clients = new List { apiClient }, + Clients = [apiClient], EducationOrganizationId = id }); var application = new Application { ApplicationName = applicationModel.ApplicationName, - ApiClients = new List { apiClient }, + ApiClients = [apiClient], ApplicationEducationOrganizations = new List(applicationEdOrgs), ClaimSetName = applicationModel.ClaimSetName, - Profiles = new List(), + Profiles = [], Vendor = vendor, OperationalContextUri = OperationalContext.DefaultOperationalContextUri, OdsInstance = odsInstance @@ -97,7 +91,7 @@ public AddApplicationResult Execute(IAddApplicationModel applicationModel) public interface IAddApplicationModel { - string? ApplicationName { get; } + string ApplicationName { get; } int VendorId { get; } string? ClaimSetName { get; } int? ProfileId { get; } diff --git a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/AddOdsInstanceCommand.cs b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/AddOdsInstanceCommand.cs index 1ef39564c..b1239d632 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/AddOdsInstanceCommand.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/AddOdsInstanceCommand.cs @@ -40,9 +40,9 @@ public OdsInstance Execute(IAddOdsInstanceModel newOdsInstance) public interface IAddOdsInstanceModel { - string? Name { get; } - string? InstanceType { get; } - string? Status { get; set; } + string Name { get; } + string InstanceType { get; } + string Status { get; set; } bool? IsExtended { get; } - string? Version { get; set; } + string Version { get; set; } } diff --git a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/AddVendorCommand.cs b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/AddVendorCommand.cs index 78d777bd3..e48af4d05 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/AddVendorCommand.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/AddVendorCommand.cs @@ -24,20 +24,22 @@ public Vendor Execute(IAddVendorModel newVendor) .Where(namespacePrefix => !string.IsNullOrWhiteSpace(namespacePrefix)) .Select(namespacePrefix => new VendorNamespacePrefix { - NamespacePrefix = namespacePrefix.Trim() + NamespacePrefix = namespacePrefix.Trim(), + Vendor = new Vendor() }) .ToList(); var vendor = new Vendor { - VendorName = newVendor.Company?.Trim(), + VendorName = newVendor.Company.Trim(), VendorNamespacePrefixes = namespacePrefixes }; var user = new VendorUser { - FullName = newVendor.ContactName?.Trim(), - Email = newVendor.ContactEmailAddress?.Trim() + FullName = newVendor.ContactName.Trim(), + Email = newVendor.ContactEmailAddress.Trim(), + Vendor = vendor }; vendor.Users.Add(user); @@ -50,8 +52,8 @@ public Vendor Execute(IAddVendorModel newVendor) public interface IAddVendorModel { - string? Company { get; } + string Company { get; } string? NamespacePrefixes { get; } - string? ContactName { get; } - string? ContactEmailAddress { get; } + string ContactName { get; } + string ContactEmailAddress { get; } } diff --git a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/DeleteApplicationCommand.cs b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/DeleteApplicationCommand.cs index 50ca5a88e..00b97c071 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/DeleteApplicationCommand.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/DeleteApplicationCommand.cs @@ -31,7 +31,7 @@ public void Execute(int id) .Include(a => a.ApplicationEducationOrganizations) .SingleOrDefault(a => a.ApplicationId == id) ?? throw new NotFoundException("application", id); - if (application != null && application.Vendor.IsSystemReservedVendor()) + if (application != null && application.Vendor != null && application.Vendor.IsSystemReservedVendor()) { throw new Exception("This Application is required for proper system function and may not be modified"); } diff --git a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/EditApplicationCommand.cs b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/EditApplicationCommand.cs index bdeb64d1a..de9675d23 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/EditApplicationCommand.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/EditApplicationCommand.cs @@ -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.Collections.ObjectModel; using EdFi.Common.Utils.Extensions; using EdFi.Ods.AdminApi.Common.Infrastructure.ErrorHandling; using EdFi.Ods.AdminApi.V1.Admin.DataAccess.Contexts; @@ -18,14 +17,9 @@ public interface IEditApplicationCommand Application Execute(IEditApplicationModel model); } -public class EditApplicationCommand : IEditApplicationCommand +public class EditApplicationCommand(IUsersContext context) : IEditApplicationCommand { - private readonly IUsersContext _context; - - public EditApplicationCommand(IUsersContext context) - { - _context = context; - } + private readonly IUsersContext _context = context; public Application Execute(IEditApplicationModel model) { @@ -36,7 +30,7 @@ public Application Execute(IEditApplicationModel model) .Include(a => a.Profiles) .SingleOrDefault(a => a.ApplicationId == model.ApplicationId) ?? throw new NotFoundException("application", model.ApplicationId); - if (application.Vendor.IsSystemReservedVendor()) + if (application.Vendor != null && application.Vendor.IsSystemReservedVendor()) { throw new Exception("This Application is required for proper system function and may not be modified"); } @@ -53,7 +47,7 @@ public Application Execute(IEditApplicationModel model) application.ClaimSetName = model.ClaimSetName; application.Vendor = newVendor; - application.ApplicationEducationOrganizations ??= new Collection(); + application.ApplicationEducationOrganizations ??= []; // Quick and dirty: simply remove all existing links to ApplicationEducationOrganizations... application.ApplicationEducationOrganizations.ToList().ForEach(x => _context.ApplicationEducationOrganizations.Remove(x)); @@ -61,7 +55,7 @@ public Application Execute(IEditApplicationModel model) // ... and now create the new proper list. model.EducationOrganizationIds?.ForEach(id => application.ApplicationEducationOrganizations.Add(application.CreateApplicationEducationOrganization(id))); - application.Profiles ??= new Collection(); + application.Profiles ??= []; application.Profiles.Clear(); @@ -78,7 +72,7 @@ public Application Execute(IEditApplicationModel model) public interface IEditApplicationModel { int ApplicationId { get; } - string? ApplicationName { get; } + string ApplicationName { get; } int VendorId { get; } string? ClaimSetName { get; } int? ProfileId { get; } diff --git a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/EditOdsInstanceCommand.cs b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/EditOdsInstanceCommand.cs index dfcb754ab..11ec329c2 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/EditOdsInstanceCommand.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/EditOdsInstanceCommand.cs @@ -42,10 +42,10 @@ public OdsInstance Execute(IEditOdsInstanceModel changedOdsInstanceData) public interface IEditOdsInstanceModel { public int OdsInstanceId { get; set; } - string? Name { get; } - string? InstanceType { get; } - string? Status { get; set; } + string Name { get; } + string InstanceType { get; } + string Status { get; set; } bool? IsExtended { get; } - string? Version { get; set; } + string Version { get; set; } } diff --git a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/EditVendorCommand.cs b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/EditVendorCommand.cs index 57e8ebfb8..0ab906d7b 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/EditVendorCommand.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/EditVendorCommand.cs @@ -35,7 +35,7 @@ public Vendor Execute(IEditVendor changedVendorData) vendor.VendorName = changedVendorData.Company; - if (vendor.VendorNamespacePrefixes.Any()) + if (vendor.VendorNamespacePrefixes != null && vendor.VendorNamespacePrefixes.Any()) { foreach (var vendorNamespacePrefix in vendor.VendorNamespacePrefixes.ToList()) { @@ -81,8 +81,8 @@ public Vendor Execute(IEditVendor changedVendorData) public interface IEditVendor { int VendorId { get; set; } - string? Company { get; set; } + string Company { get; set; } string? NamespacePrefixes { get; set; } - string? ContactName { get; set; } - string? ContactEmailAddress { get; set; } + string ContactName { get; set; } + string ContactEmailAddress { get; set; } } diff --git a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/RegenerateApiClientSecretCommand.cs b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/RegenerateApiClientSecretCommand.cs index f760b7c83..29555811e 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/RegenerateApiClientSecretCommand.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Commands/RegenerateApiClientSecretCommand.cs @@ -48,5 +48,5 @@ public class RegenerateApiClientSecretResult { public string? Key { get; set; } public string? Secret { get; set; } - public Application Application { get; set; } = new(); + public Application Application { get; set; } = new() { OperationalContextUri = string.Empty }; } diff --git a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/EntityFrameworkCoreDatabaseModelBuilderExtensions.cs b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/EntityFrameworkCoreDatabaseModelBuilderExtensions.cs index e2e13bcfc..8766e2205 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/EntityFrameworkCoreDatabaseModelBuilderExtensions.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/EntityFrameworkCoreDatabaseModelBuilderExtensions.cs @@ -30,7 +30,8 @@ public static void ApplyDatabaseServerSpecificConventions(this ModelBuilder mode { var tableId = StoreObjectIdentifier.Table(tableName); var columnName = property.GetColumnName(tableId) ?? property.GetDefaultColumnName(tableId); - property.SetColumnName(columnName.ToLowerInvariant()); + if (columnName != null) + property.SetColumnName(columnName.ToLowerInvariant()); } foreach (var key in entity.GetKeys()) diff --git a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Queries/GetApplicationsByOdsInstanceIdQuery.cs b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Queries/GetApplicationsByOdsInstanceIdQuery.cs index 26e046138..42ceed8da 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Queries/GetApplicationsByOdsInstanceIdQuery.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Queries/GetApplicationsByOdsInstanceIdQuery.cs @@ -31,7 +31,7 @@ public List Execute(int odsInstanceId) .Include(aco => aco.ApplicationEducationOrganizations) .Include(api => api.Profiles) .Include(api => api.Vendor) - .Where(a => a.OdsInstance.OdsInstanceId == odsInstanceId) + .Where(a => a.OdsInstance == null || a.OdsInstance.OdsInstanceId == odsInstanceId) .ToList(); if (!applications.Any() && _context.OdsInstances.Find(odsInstanceId) == null) diff --git a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Queries/GetApplicationsQuery.cs b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Queries/GetApplicationsQuery.cs index 36ea3a536..3af54180b 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Queries/GetApplicationsQuery.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Queries/GetApplicationsQuery.cs @@ -32,26 +32,26 @@ public GetApplicationsQuery(IUsersContext context, IOptions options public List Execute() { return _context.Applications - .Include(ap => ap.Vendor).ThenInclude(ap => ap.VendorNamespacePrefixes) - .Include(ap => ap.Vendor).ThenInclude(ap => ap.Users) + .Include(ap => ap.Vendor!).ThenInclude(ap => ap.VendorNamespacePrefixes) + .Include(ap => ap.Vendor!).ThenInclude(ap => ap.Users) .Include(ap => ap.Profiles) .Include(ap => ap.OdsInstance) .Include(ap => ap.ApplicationEducationOrganizations) - .OrderBy(v => v.Vendor.VendorName) - .Where(v => !VendorExtensions.ReservedNames.Contains(v.Vendor.VendorName.Trim())) + .OrderBy(v => v.Vendor!.VendorName) + .Where(v => v.Vendor != null && v.Vendor.VendorName != null && !VendorExtensions.ReservedNames.Contains(v.Vendor.VendorName.Trim())) .ToList(); } public List Execute(CommonQueryParams commonQueryParams) { return _context.Applications - .Include(ap => ap.Vendor).ThenInclude(ap => ap.VendorNamespacePrefixes) - .Include(ap => ap.Vendor).ThenInclude(ap => ap.Users) + .Include(ap => ap.Vendor!).ThenInclude(ap => ap.VendorNamespacePrefixes) + .Include(ap => ap.Vendor!).ThenInclude(ap => ap.Users) .Include(ap => ap.Profiles) .Include(ap => ap.OdsInstance) .Include(ap => ap.ApplicationEducationOrganizations) .OrderBy(v => v.ApplicationName) - .Where(v => !VendorExtensions.ReservedNames.Contains(v.Vendor.VendorName.Trim())) + .Where(v => v.Vendor != null && v.Vendor.VendorName != null && !VendorExtensions.ReservedNames.Contains(v.Vendor.VendorName.Trim())) .Paginate(commonQueryParams.Offset, commonQueryParams.Limit, _options) .ToList(); } diff --git a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Queries/GetResourceClaimsAsFlatListQuery.cs b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Queries/GetResourceClaimsAsFlatListQuery.cs index 9d8bc7108..62b292940 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Queries/GetResourceClaimsAsFlatListQuery.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Queries/GetResourceClaimsAsFlatListQuery.cs @@ -30,7 +30,7 @@ public IReadOnlyList Execute() Id = x.ResourceClaimId, Name = x.ResourceName, ParentId = x.ParentResourceClaimId ?? 0, - ParentName = x.ParentResourceClaim.ResourceName + ParentName = x.ParentResourceClaim != null ? x.ParentResourceClaim.ResourceName : null }) .Distinct() .OrderBy(x => x.Name) diff --git a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Queries/GetVendorsQuery.cs b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Queries/GetVendorsQuery.cs index f8e7bc713..6d51b4a67 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Queries/GetVendorsQuery.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Database/Queries/GetVendorsQuery.cs @@ -38,7 +38,7 @@ public List Execute() .Include(x => x.Applications).ThenInclude(x => x.ApplicationEducationOrganizations) .Include(x => x.Applications).ThenInclude(x => x.Profiles) .Include(x => x.Applications).ThenInclude(x => x.OdsInstance) - .OrderBy(v => v.VendorName).Where(v => !VendorExtensions.ReservedNames.Contains(v.VendorName.Trim())) + .OrderBy(v => v.VendorName).Where(v => v.VendorName != null && !VendorExtensions.ReservedNames.Contains(v.VendorName.Trim())) .ToList(); } @@ -50,7 +50,7 @@ public List Execute(CommonQueryParams commonQueryParams) .Include(x => x.Applications).ThenInclude(x => x.ApplicationEducationOrganizations) .Include(x => x.Applications).ThenInclude(x => x.Profiles) .Include(x => x.Applications).ThenInclude(x => x.OdsInstance) - .OrderBy(v => v.VendorName).Where(v => !VendorExtensions.ReservedNames.Contains(v.VendorName.Trim())) + .OrderBy(v => v.VendorName).Where(v => v.VendorName != null && !VendorExtensions.ReservedNames.Contains(v.VendorName.Trim())) .Paginate(commonQueryParams.Offset, commonQueryParams.Limit, _options) .ToList(); } diff --git a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Services/ClaimSetEditor/AddClaimSetCommand.cs b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Services/ClaimSetEditor/AddClaimSetCommand.cs index cffa20953..24c948e6a 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Services/ClaimSetEditor/AddClaimSetCommand.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Services/ClaimSetEditor/AddClaimSetCommand.cs @@ -22,5 +22,5 @@ public int Execute(IAddClaimSetModel claimSet) public interface IAddClaimSetModel { - string? ClaimSetName { get; } + string ClaimSetName { get; } } diff --git a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Services/ClaimSetEditor/AddOrEditResourcesOnClaimSetCommand.cs b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Services/ClaimSetEditor/AddOrEditResourcesOnClaimSetCommand.cs index 928e3cee8..2c3e73bf3 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Services/ClaimSetEditor/AddOrEditResourcesOnClaimSetCommand.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Services/ClaimSetEditor/AddOrEditResourcesOnClaimSetCommand.cs @@ -104,7 +104,7 @@ private List GetDbResources() public class AddClaimSetModel : IAddClaimSetModel { - public string? ClaimSetName { get; set; } + public string ClaimSetName { get; set; } = string.Empty; } public class EditResourceOnClaimSetModel : IEditResourceOnClaimSetModel diff --git a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Services/ClaimSetEditor/GetApplicationsByClaimSetIdQuery.cs b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Services/ClaimSetEditor/GetApplicationsByClaimSetIdQuery.cs index dece3da04..fd0c877eb 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Services/ClaimSetEditor/GetApplicationsByClaimSetIdQuery.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Services/ClaimSetEditor/GetApplicationsByClaimSetIdQuery.cs @@ -41,7 +41,7 @@ private IEnumerable GetApplicationsByClaimSetName(string claimSetNa .Select(x => new Application { Name = x.ApplicationName, - VendorName = x.Vendor.VendorName + VendorName = x.Vendor != null ? x.Vendor.VendorName : null }) .ToList(); } diff --git a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Services/ClaimSetEditor/GetResourcesByClaimSetIdQueryService.cs b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Services/ClaimSetEditor/GetResourcesByClaimSetIdQueryService.cs index 37f6b6e23..cfeee77df 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Services/ClaimSetEditor/GetResourcesByClaimSetIdQueryService.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Services/ClaimSetEditor/GetResourcesByClaimSetIdQueryService.cs @@ -45,7 +45,8 @@ internal IList GetParentResources(int claimSetId) .Include(x => x.ResourceClaim) .Include(x => x.ResourceClaim.ParentResourceClaim) .Include(x => x.Action) - .Include(x => x.AuthorizationStrategyOverrides).ThenInclude(x => x.AuthorizationStrategy) + .Include(x => x.AuthorizationStrategyOverrides!) + .ThenInclude(x => x.AuthorizationStrategy) .Where(x => x.ClaimSet.ClaimSetId == claimSetId && x.ResourceClaim.ParentResourceClaimId == null).ToList(); @@ -75,8 +76,8 @@ internal IList GetParentResources(int claimSetId) var resultDictionary = new Dictionary(); var defaultAuthStrategies = _securityContext.ResourceClaimActions - .Include(x => x.ResourceClaim).Include(x => x.Action).Include(x => x.AuthorizationStrategies). - ThenInclude(x => x.AuthorizationStrategy).ToList(); + .Include(x => x.ResourceClaim).Include(x => x.Action).Include(x => x.AuthorizationStrategies!) + .ThenInclude(x => x.AuthorizationStrategy).ToList(); var defaultAuthStrategiesForParents = defaultAuthStrategies .Where(x => x.ResourceClaim.ParentResourceClaimId == null).ToList(); @@ -91,26 +92,26 @@ internal IList GetParentResources(int claimSetId) { var createDefaultStrategy = defaultAuthStrategiesForParents.SingleOrDefault(x => x.ResourceClaim.ResourceClaimId == resourceClaim.ResourceClaimId && - x.Action.ActionName == Action.Create.Value)?.AuthorizationStrategies.Select(x => x.AuthorizationStrategy); + x.Action.ActionName == Action.Create.Value)?.AuthorizationStrategies?.Select(x => x.AuthorizationStrategy); AddStrategyToParentResource(createDefaultStrategy); var readDefaultStrategy = defaultAuthStrategiesForParents.SingleOrDefault(x => x.ResourceClaim.ResourceClaimId == resourceClaim.ResourceClaimId && - x.Action.ActionName == Action.Read.Value)?.AuthorizationStrategies.Select(x => x.AuthorizationStrategy); + x.Action.ActionName == Action.Read.Value)?.AuthorizationStrategies?.Select(x => x.AuthorizationStrategy); AddStrategyToParentResource(readDefaultStrategy); var updateDefaultStrategy = defaultAuthStrategiesForParents .SingleOrDefault(x => x.ResourceClaim.ResourceClaimId == resourceClaim.ResourceClaimId && - x.Action.ActionName == Action.Update.Value)?.AuthorizationStrategies.Select(x => x.AuthorizationStrategy); + x.Action.ActionName == Action.Update.Value)?.AuthorizationStrategies?.Select(x => x.AuthorizationStrategy); AddStrategyToParentResource(updateDefaultStrategy); var deleteDefaultStrategy = defaultAuthStrategiesForParents .SingleOrDefault(x => x.ResourceClaim.ResourceClaimId == resourceClaim.ResourceClaimId && - x.Action.ActionName == Action.Delete.Value)?.AuthorizationStrategies.Select(x => x.AuthorizationStrategy); + x.Action.ActionName == Action.Delete.Value)?.AuthorizationStrategies?.Select(x => x.AuthorizationStrategy); AddStrategyToParentResource(deleteDefaultStrategy); var readChangesDefaultStrategy = defaultAuthStrategiesForParents .SingleOrDefault(x => x.ResourceClaim.ResourceClaimId == resourceClaim.ResourceClaimId && - x.Action.ActionName == Action.ReadChanges.Value)?.AuthorizationStrategies.Select(x => x.AuthorizationStrategy); + x.Action.ActionName == Action.ReadChanges.Value)?.AuthorizationStrategies?.Select(x => x.AuthorizationStrategy); AddStrategyToParentResource(readChangesDefaultStrategy); void AddStrategyToParentResource(IEnumerable? defaultStrategy) @@ -125,27 +126,27 @@ void AddStrategyToParentResource(IEnumerable? def { var createDefaultStrategies = defaultAuthStrategiesForChildren.SingleOrDefault(x => x.ResourceClaim.ResourceClaimId == resourceClaim.ResourceClaimId && - x.Action.ActionName == Action.Create.Value)?.AuthorizationStrategies.Select(x => x.AuthorizationStrategy); + x.Action.ActionName == Action.Create.Value)?.AuthorizationStrategies?.Select(x => x.AuthorizationStrategy); actions = AddStrategyToChildResource(createDefaultStrategies, Action.Create); var readDefaultStrategies = defaultAuthStrategiesForChildren.SingleOrDefault(x => x.ResourceClaim.ResourceClaimId == resourceClaim.ResourceClaimId && - x.Action.ActionName == Action.Read.Value)?.AuthorizationStrategies.Select(x => x.AuthorizationStrategy); + x.Action.ActionName == Action.Read.Value)?.AuthorizationStrategies?.Select(x => x.AuthorizationStrategy); actions = AddStrategyToChildResource(readDefaultStrategies, Action.Read); var updateDefaultStrategies = defaultAuthStrategiesForChildren.SingleOrDefault(x => x.ResourceClaim.ResourceClaimId == resourceClaim.ResourceClaimId && - x.Action.ActionName == Action.Update.Value)?.AuthorizationStrategies.Select(x => x.AuthorizationStrategy); + x.Action.ActionName == Action.Update.Value)?.AuthorizationStrategies?.Select(x => x.AuthorizationStrategy); actions = AddStrategyToChildResource(updateDefaultStrategies, Action.Update); var deleteDefaultStrategies = defaultAuthStrategiesForChildren.SingleOrDefault(x => x.ResourceClaim.ResourceClaimId == resourceClaim.ResourceClaimId && - x.Action.ActionName == Action.Delete.Value)?.AuthorizationStrategies.Select(x => x.AuthorizationStrategy); + x.Action.ActionName == Action.Delete.Value)?.AuthorizationStrategies?.Select(x => x.AuthorizationStrategy); actions = AddStrategyToChildResource(deleteDefaultStrategies, Action.Delete); var readChangesDefaultStrategy = defaultAuthStrategiesForChildren.SingleOrDefault(x => x.ResourceClaim.ResourceClaimId == resourceClaim.ResourceClaimId && - x.Action.ActionName == Action.ReadChanges.Value)?.AuthorizationStrategies.Select(x => x.AuthorizationStrategy); + x.Action.ActionName == Action.ReadChanges.Value)?.AuthorizationStrategies?.Select(x => x.AuthorizationStrategy); actions = AddStrategyToChildResource(readChangesDefaultStrategy, Action.ReadChanges); List AddStrategyToChildResource(IEnumerable? defaultStrategies, Action action) @@ -154,7 +155,7 @@ void AddStrategyToParentResource(IEnumerable? def { defaultStrategies = defaultAuthStrategiesForParents.SingleOrDefault(x => x.ResourceClaim.ResourceClaimId == resourceClaim.ParentResourceClaimId && - x.Action.ActionName == action.Value)?.AuthorizationStrategies.Select(x => x.AuthorizationStrategy); + x.Action.ActionName == action.Value)?.AuthorizationStrategies?.Select(x => x.AuthorizationStrategy); if (defaultStrategies != null) { @@ -174,7 +175,7 @@ void AddStrategyToParentResource(IEnumerable? def } else { - var mappedStrategies = defaultStrategies.Select(x => _mapper.Map(x)); + var mappedStrategies = defaultStrategies.Select(x => _mapper.Map(x)); actions.Add(new ClaimSetResourceClaimActionAuthStrategies() { AuthorizationStrategies = mappedStrategies.ToArray() @@ -210,7 +211,7 @@ void AddStrategyToParentResource(IEnumerable? def .Include(x => x.ResourceClaim) .Include(x => x.ClaimSet) .Include(x => x.Action) - .Include(x => x.AuthorizationStrategyOverrides).ThenInclude(x => x.AuthorizationStrategy).ToList(); + .Include(x => x.AuthorizationStrategyOverrides!).ThenInclude(x => x.AuthorizationStrategy).ToList(); var parentResourceOverride = parentResources.SingleOrDefault(x => x.ResourceClaim.ResourceClaimId == resourceClaim.ResourceClaim.ParentResourceClaimId && x.ClaimSet.ClaimSetId == resourceClaim.ClaimSet.ClaimSetId && x.Action.ActionId == resourceClaim.Action.ActionId); diff --git a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Services/ClaimSetEditor/OverrideDefaultAuthorizationStrategyService.cs b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Services/ClaimSetEditor/OverrideDefaultAuthorizationStrategyService.cs index a73d4027e..dfb73084c 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Services/ClaimSetEditor/OverrideDefaultAuthorizationStrategyService.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Services/ClaimSetEditor/OverrideDefaultAuthorizationStrategyService.cs @@ -24,7 +24,7 @@ public void Execute(IOverrideDefaultAuthorizationStrategyModel model) .Include(x => x.ResourceClaim) .Include(x => x.Action) .Include(x => x.ClaimSet) - .Include(x => x.AuthorizationStrategyOverrides).ThenInclude(x => x.AuthorizationStrategy) + .Include(x => x.AuthorizationStrategyOverrides!).ThenInclude(x => x.AuthorizationStrategy) .Where( x => x.ResourceClaim.ResourceClaimId == model.ResourceClaimId && x.ClaimSet.ClaimSetId == model.ClaimSetId) @@ -41,7 +41,7 @@ public void Execute(IOverrideDefaultAuthorizationStrategyModel model) .Include(x => x.ResourceClaim) .Include(x => x.Action) .Include(x => x.ClaimSet) - .Include(x => x.AuthorizationStrategyOverrides).ThenInclude(x => x.AuthorizationStrategy) + .Include(x => x.AuthorizationStrategyOverrides!).ThenInclude(x => x.AuthorizationStrategy) .Where( x => x.ResourceClaim.ResourceClaimId == parentResourceClaimId && x.ClaimSet.ClaimSetId == model.ClaimSetId) @@ -166,15 +166,22 @@ private static void AddOverrides(IOverrideDefaultAuthorizationStrategyModel mode } private static void SetAuthorizationStrategyOverrides( - ClaimSetResourceClaimAction claimSetResourceClaimAction, - List parentResourceClaims, int[] authorizationStrategyValues, - Dictionary - authorizationStrategiesDictionary, string actionName) + ClaimSetResourceClaimAction claimSetResourceClaimAction, + List parentResourceClaims, int[] authorizationStrategyValues, + Dictionary authorizationStrategiesDictionary, string actionName) { foreach (var authStrategyId in authorizationStrategyValues.Where(x => x != 0)) { var authStrategyOverride = new ClaimSetResourceClaimActionAuthorizationStrategyOverrides() - { AuthorizationStrategy = authorizationStrategiesDictionary[authStrategyId] }; + { + AuthorizationStrategy = authorizationStrategiesDictionary[authStrategyId], + ClaimSetResourceClaimAction = claimSetResourceClaimAction + }; + + if (claimSetResourceClaimAction.AuthorizationStrategyOverrides == null) + { + claimSetResourceClaimAction.AuthorizationStrategyOverrides = new List(); + } if (parentResourceClaims.Any() && parentResourceClaims.SingleOrDefault( x => diff --git a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Services/ClaimSetEditor/UpdateResourcesOnClaimSetCommandService.cs b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Services/ClaimSetEditor/UpdateResourcesOnClaimSetCommandService.cs index 0e80aab0d..71104835a 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Services/ClaimSetEditor/UpdateResourcesOnClaimSetCommandService.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Infrastructure/Services/ClaimSetEditor/UpdateResourcesOnClaimSetCommandService.cs @@ -26,12 +26,13 @@ public void Execute(IUpdateResourcesOnClaimSetModel model) var resourceClaimsForClaimSet = _context .ClaimSetResourceClaimActions - .Include(x => x.AuthorizationStrategyOverrides).ThenInclude(x => x.AuthorizationStrategy) + .Include(x => x.AuthorizationStrategyOverrides!).ThenInclude(x => x.AuthorizationStrategy) .Where(x => x.ClaimSet.ClaimSetId == model.ClaimSetId).ToList(); _context.ClaimSetResourceClaimActions.RemoveRange(resourceClaimsForClaimSet); _context.SaveChanges(); - if (model.ResourceClaims == null) return; + if (model.ResourceClaims == null) + return; _addOrEditResourcesOnClaimSetCommand.Execute(model.ClaimSetId, model.ResourceClaims); } diff --git a/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Contexts/SecurityContextFactory.cs b/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Contexts/SecurityContextFactory.cs index d71dc64da..c591d02ae 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Contexts/SecurityContextFactory.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Contexts/SecurityContextFactory.cs @@ -3,18 +3,16 @@ // 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; -using System.Collections.Generic; using EdFi.Common.Configuration; using EdFi.Ods.AdminApi.V1.Security.DataAccess.Providers; using Microsoft.EntityFrameworkCore; namespace EdFi.Ods.AdminApi.V1.Security.DataAccess.Contexts { - public class SecurityContextFactory : ISecurityContextFactory + public class SecurityContextFactory(ISecurityDatabaseConnectionStringProvider connectionStringProvider, DatabaseEngine databaseEngine) : ISecurityContextFactory { - private readonly ISecurityDatabaseConnectionStringProvider _connectionStringProvider; - private readonly DatabaseEngine _databaseEngine; + private readonly ISecurityDatabaseConnectionStringProvider _connectionStringProvider = connectionStringProvider; + private readonly DatabaseEngine _databaseEngine = databaseEngine; private readonly IDictionary _securityContextTypeByDatabaseEngine = new Dictionary { @@ -22,17 +20,12 @@ public class SecurityContextFactory : ISecurityContextFactory {DatabaseEngine.Postgres, typeof(PostgresSecurityContext)} }; - public SecurityContextFactory(ISecurityDatabaseConnectionStringProvider connectionStringProvider, DatabaseEngine databaseEngine) - { - _connectionStringProvider = connectionStringProvider; - _databaseEngine = databaseEngine; - } - public Type GetSecurityContextType() { - if (_securityContextTypeByDatabaseEngine.TryGetValue(_databaseEngine, out Type contextType)) + if (_securityContextTypeByDatabaseEngine.TryGetValue(_databaseEngine, out Type? contextType)) { - return contextType; + return contextType ?? throw new InvalidOperationException( + $"No SecurityContext defined for database type {_databaseEngine.DisplayName}"); } throw new InvalidOperationException( @@ -43,27 +36,27 @@ public ISecurityContext CreateContext() { if (_databaseEngine == DatabaseEngine.SqlServer) { - return Activator.CreateInstance( - GetSecurityContextType(), - new DbContextOptionsBuilder() - .UseSqlServer(_connectionStringProvider.GetConnectionString()) - .Options) as - ISecurityContext; + return (Activator.CreateInstance( + GetSecurityContextType(), + new DbContextOptionsBuilder() + .UseSqlServer(_connectionStringProvider.GetConnectionString()) + .Options) as ISecurityContext) + ?? throw new InvalidOperationException("Failed to create an instance of SqlServerSecurityContext."); } if (_databaseEngine == DatabaseEngine.Postgres) { - return Activator.CreateInstance( - GetSecurityContextType(), - new DbContextOptionsBuilder() - .UseNpgsql(_connectionStringProvider.GetConnectionString()) - .UseLowerCaseNamingConvention() - .Options) as - ISecurityContext; + return (Activator.CreateInstance( + GetSecurityContextType(), + new DbContextOptionsBuilder() + .UseNpgsql(_connectionStringProvider.GetConnectionString()) + .UseLowerCaseNamingConvention() + .Options) as ISecurityContext) + ?? throw new InvalidOperationException("Failed to create an instance of PostgresSecurityContext."); } throw new InvalidOperationException( - $"Cannot create an SecurityContext for database type {_databaseEngine.DisplayName}"); + $"Cannot create a SecurityContext for database type {_databaseEngine.DisplayName}"); } } } diff --git a/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/Action.cs b/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/Action.cs index 111232a5b..651cbcc47 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/Action.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/Action.cs @@ -16,10 +16,10 @@ public class Action [StringLength(255)] [Required] - public string ActionName { get; set; } + public required string ActionName { get; set; } [StringLength(2048)] [Required] - public string ActionUri { get; set; } + public required string ActionUri { get; set; } } } diff --git a/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/Application.cs b/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/Application.cs index cd9ac06f5..bc9d92a49 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/Application.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/Application.cs @@ -14,6 +14,6 @@ public class Application [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int ApplicationId { get; set; } - public string ApplicationName { get; set; } + public required string ApplicationName { get; set; } = string.Empty; } } diff --git a/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/AuthorizationStrategy.cs b/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/AuthorizationStrategy.cs index 6c1d61b6a..fee37af2b 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/AuthorizationStrategy.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/AuthorizationStrategy.cs @@ -16,16 +16,16 @@ public class AuthorizationStrategy [StringLength(255)] [Required] - public string DisplayName { get; set; } + public required string DisplayName { get; set; } [StringLength(255)] [Required] - public string AuthorizationStrategyName { get; set; } + public required string AuthorizationStrategyName { get; set; } [Column("Application_ApplicationId")] public int ApplicationId { get; set; } [Required] - public Application Application { get; set; } + public required Application Application { get; set; } } } diff --git a/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/ClaimSet.cs b/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/ClaimSet.cs index b2446dbef..8cd522a60 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/ClaimSet.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/ClaimSet.cs @@ -16,16 +16,16 @@ public class ClaimSet [StringLength(255)] [Required] - public string ClaimSetName { get; set; } + public required string ClaimSetName { get; set; } - public bool IsEdfiPreset { get; set; } + public bool IsEdfiPreset { get; set; } - public bool ForApplicationUseOnly { get; set; } + public bool ForApplicationUseOnly { get; set; } [Column("Application_ApplicationId")] public int ApplicationId { get; set; } [Required] - public Application Application { get; set; } + public required Application Application { get; set; } } } diff --git a/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/ClaimSetResourceClaimAction.cs b/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/ClaimSetResourceClaimAction.cs index 6af11d781..ff1ee928b 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/ClaimSetResourceClaimAction.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/ClaimSetResourceClaimAction.cs @@ -19,21 +19,21 @@ public class ClaimSetResourceClaimAction [Required] [ForeignKey("ActionId")] - public Action Action { get; set; } + public required Action Action { get; set; } public int ClaimSetId { get; set; } [Required] [ForeignKey("ClaimSetId")] - public ClaimSet ClaimSet { get; set; } + public required ClaimSet ClaimSet { get; set; } public int ResourceClaimId { get; set; } [Required] [ForeignKey("ResourceClaimId")] - public ResourceClaim ResourceClaim { get; set; } + public required ResourceClaim ResourceClaim { get; set; } - public List AuthorizationStrategyOverrides { get; set; } + public List? AuthorizationStrategyOverrides { get; set; } [StringLength(255)] public string? ValidationRuleSetNameOverride { get; set; } diff --git a/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/ClaimSetResourceClaimActionAuthorizationStrategyOverrides.cs b/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/ClaimSetResourceClaimActionAuthorizationStrategyOverrides.cs index cf21cd0bf..4e76c8498 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/ClaimSetResourceClaimActionAuthorizationStrategyOverrides.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/ClaimSetResourceClaimActionAuthorizationStrategyOverrides.cs @@ -17,14 +17,14 @@ public class ClaimSetResourceClaimActionAuthorizationStrategyOverrides public int ClaimSetResourceClaimActionId { get; set; } - [Required] + [Required] [ForeignKey("ClaimSetResourceClaimActionId")] - public ClaimSetResourceClaimAction ClaimSetResourceClaimAction { get; set; } + public required ClaimSetResourceClaimAction ClaimSetResourceClaimAction { get; set; } public int AuthorizationStrategyId { get; set; } [Required] [ForeignKey("AuthorizationStrategyId")] - public AuthorizationStrategy AuthorizationStrategy { get; set; } + public required AuthorizationStrategy AuthorizationStrategy { get; set; } } } diff --git a/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/ResourceClaim.cs b/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/ResourceClaim.cs index 3a8dc92bd..b54ced18e 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/ResourceClaim.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/ResourceClaim.cs @@ -17,30 +17,30 @@ public class ResourceClaim [StringLength(255)] [Required] - public string DisplayName { get; set; } + public required string DisplayName { get; set; } /// /// ResourceName is actually an Uri so length needs to be around 2048 /// [StringLength(2048)] [Required] - public string ResourceName { get; set; } + public required string ResourceName { get; set; } /// /// ClaimName is actually an Uri so length needs to be around 2048 /// [StringLength(2048)] [Required] - public string ClaimName { get; set; } + public required string ClaimName { get; set; } [Column("Application_ApplicationId")] public int ApplicationId { get; set; } [Required] - public Application Application { get; set; } + public required Application Application { get; set; } public int? ParentResourceClaimId { get; set; } - public virtual ResourceClaim ParentResourceClaim { get; set; } + public virtual ResourceClaim? ParentResourceClaim { get; set; } } } diff --git a/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/ResourceClaimAction.cs b/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/ResourceClaimAction.cs index b233703f8..99081f01b 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/ResourceClaimAction.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/ResourceClaimAction.cs @@ -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.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; @@ -19,15 +18,15 @@ public class ResourceClaimAction [Required] [ForeignKey("ActionId")] - public Action Action { get; set; } + public required Action Action { get; set; } - public List AuthorizationStrategies { get; set; } + public List? AuthorizationStrategies { get; set; } public int ResourceClaimId { get; set; } [Required] [ForeignKey("ResourceClaimId")] - public ResourceClaim ResourceClaim { get; set; } + public required ResourceClaim ResourceClaim { get; set; } [StringLength(255)] public string? ValidationRuleSetName { get; set; } diff --git a/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/ResourceClaimActionAuthorizationStrategies.cs b/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/ResourceClaimActionAuthorizationStrategies.cs index ffbb3d63e..fc0e8f779 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/ResourceClaimActionAuthorizationStrategies.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Models/ResourceClaimActionAuthorizationStrategies.cs @@ -21,12 +21,12 @@ public class ResourceClaimActionAuthorizationStrategies [Required] [ForeignKey("ResourceClaimActionId")] - public ResourceClaimAction ResourceClaimAction { get; set; } + public required ResourceClaimAction ResourceClaimAction { get; set; } public int AuthorizationStrategyId { get; set; } [Required] [ForeignKey("AuthorizationStrategyId")] - public AuthorizationStrategy AuthorizationStrategy { get; set; } + public required AuthorizationStrategy AuthorizationStrategy { get; set; } } } diff --git a/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Repositories/CachedSecurityRepository.cs b/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Repositories/CachedSecurityRepository.cs index 8b60ccc31..19c1d4d2e 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Repositories/CachedSecurityRepository.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Repositories/CachedSecurityRepository.cs @@ -40,11 +40,11 @@ private bool ShouldUpdateCache get => _lastCacheUpdate.IsDefaultValue() || SystemClock.Now() >= _lastCacheUpdate.AddMinutes(_cacheTimeoutInMinutes); } - public override Action GetActionByHttpVerb(string httpVerb) - => VerifyCacheAndExecute(() => base.GetActionByHttpVerb(httpVerb)); + public override Action? GetActionByHttpVerb(string httpVerb) + => VerifyCacheAndExecute(() => base.GetActionByHttpVerb(httpVerb)); - public override Action GetActionByName(string actionName) - => VerifyCacheAndExecute(() => base.GetActionByName(actionName)); + public override Action? GetActionByName(string actionName) + => VerifyCacheAndExecute(() => base.GetActionByName(actionName)); public override AuthorizationStrategy GetAuthorizationStrategyByName(string authorizationStrategyName) => VerifyCacheAndExecute(() => base.GetAuthorizationStrategyByName(authorizationStrategyName)); @@ -59,7 +59,7 @@ public override IEnumerable GetResourceClaimLineageMetadata(string resourceClaimUri, string action) => VerifyCacheAndExecute(() => base.GetResourceClaimLineageMetadata(resourceClaimUri, action)); - public override ResourceClaim GetResourceByResourceName(string resourceName) + public override ResourceClaim? GetResourceByResourceName(string resourceName) => VerifyCacheAndExecute(() => base.GetResourceByResourceName(resourceName)); private T VerifyCacheAndExecute(Func executionFunction) diff --git a/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Repositories/ISecurityRepository.cs b/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Repositories/ISecurityRepository.cs index 073f19f02..e864ca8c5 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Repositories/ISecurityRepository.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Repositories/ISecurityRepository.cs @@ -11,9 +11,9 @@ namespace EdFi.Ods.AdminApi.V1.Security.DataAccess.Repositories { public interface ISecurityRepository { - Action GetActionByHttpVerb(string httpVerb); + Action? GetActionByHttpVerb(string httpVerb); - Action GetActionByName(string actionName); + Action? GetActionByName(string actionName); AuthorizationStrategy GetAuthorizationStrategyByName(string authorizationStrategyName); @@ -34,6 +34,6 @@ public interface ISecurityRepository /// The resource claim authorization metadata. IEnumerable GetResourceClaimLineageMetadata(string resourceClaimUri, string action); - ResourceClaim GetResourceByResourceName(string resourceName); + ResourceClaim? GetResourceByResourceName(string resourceName); } } diff --git a/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Repositories/SecurityRepository.cs b/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Repositories/SecurityRepository.cs index 52f658e22..482f989ed 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Repositories/SecurityRepository.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Repositories/SecurityRepository.cs @@ -3,9 +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; -using System.Collections.Generic; -using System.Linq; using EdFi.Common; using EdFi.Common.Utils.Extensions; using EdFi.Ods.AdminApi.V1.Security.DataAccess.Contexts; @@ -44,35 +41,33 @@ private Application GetApplication() { using var context = _securityContextFactory.CreateContext(); - return context.Actions.ToList(); + return [.. context.Actions]; } private List GetClaimSets() { using var context = _securityContextFactory.CreateContext(); - return context.ClaimSets.Include(cs => cs.Application).ToList(); + return [.. context.ClaimSets.Include(cs => cs.Application)]; } private List GetResourceClaims() { using var context = _securityContextFactory.CreateContext(); - return context.ResourceClaims + return [.. context.ResourceClaims .Include(rc => rc.Application) .Include(rc => rc.ParentResourceClaim) - .Where(rc => rc.Application.ApplicationId.Equals(Application.Value.ApplicationId)) - .ToList(); + .Where(rc => rc.Application.ApplicationId.Equals(Application.Value.ApplicationId))]; } private List GetAuthorizationStrategies() { using var context = _securityContextFactory.CreateContext(); - return context.AuthorizationStrategies + return [.. context.AuthorizationStrategies .Include(auth => auth.Application) - .Where(auth => auth.Application.ApplicationId.Equals(Application.Value.ApplicationId)) - .ToList(); + .Where(auth => auth.Application.ApplicationId.Equals(Application.Value.ApplicationId))]; } private List GetClaimSetResourceClaimActions() @@ -84,14 +79,14 @@ private List GetClaimSetResourceClaimActions() .Include(csrc => csrc.ClaimSet) .Include(csrc => csrc.ClaimSet.Application) .Include(csrc => csrc.ResourceClaim) - .Include(csrc => csrc.AuthorizationStrategyOverrides) + .Include(csrc => csrc.AuthorizationStrategyOverrides!) .ThenInclude(aso => aso.AuthorizationStrategy) .Where(csrc => csrc.ResourceClaim.Application.ApplicationId.Equals(Application.Value.ApplicationId)) .ToList(); - // Replace empty lists with null since some consumers expect it that way + // Replace empty lists with null since some consumers expect it that way claimSetResourceClaimActions - .Where(csrc => csrc.AuthorizationStrategyOverrides.Count == 0) + .Where(csrc => csrc.AuthorizationStrategyOverrides != null && csrc.AuthorizationStrategyOverrides.Count == 0) .ForEach(csrc => csrc.AuthorizationStrategyOverrides = null); return claimSetResourceClaimActions; @@ -109,8 +104,8 @@ private List GetResourceClaimActionAuthorizations() var resourceClaimActionAuthorizations = context.ResourceClaimActions .Include(rcas => rcas.Action) .Include(rcas => rcas.ResourceClaim) - .Include(rcas => rcas.AuthorizationStrategies) - .ThenInclude(ast => ast.AuthorizationStrategy.Application) + .Include(rcas => rcas.AuthorizationStrategies!) + .ThenInclude(ast => ast.AuthorizationStrategy) .Where(rcas => rcas.ResourceClaim.Application.ApplicationId.Equals(Application.Value.ApplicationId)) .ToList(); diff --git a/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Repositories/SecurityRepositoryBase.cs b/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Repositories/SecurityRepositoryBase.cs index 7678ea8b7..579ca4719 100644 --- a/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Repositories/SecurityRepositoryBase.cs +++ b/Application/EdFi.Ods.AdminApi.V1/Security.DataAccess/Repositories/SecurityRepositoryBase.cs @@ -14,19 +14,19 @@ namespace EdFi.Ods.AdminApi.V1.Security.DataAccess.Repositories { public abstract class SecurityRepositoryBase { - protected ResettableLazy Application { get; private set; } + protected ResettableLazy Application { get; private set; } = default!; - protected ResettableLazy> Actions { get; private set; } + protected ResettableLazy> Actions { get; private set; } = default!; - protected ResettableLazy> ClaimSets { get; private set; } + protected ResettableLazy> ClaimSets { get; private set; } = default!; - protected ResettableLazy> ResourceClaims { get; private set; } + protected ResettableLazy> ResourceClaims { get; private set; } = default!; - protected ResettableLazy> AuthorizationStrategies { get; private set; } + protected ResettableLazy> AuthorizationStrategies { get; private set; } = default!; - protected ResettableLazy> ClaimSetResourceClaimActions { get; private set; } + protected ResettableLazy> ClaimSetResourceClaimActions { get; private set; } = default!; - protected ResettableLazy> ResourceClaimActions { get; private set; } + protected ResettableLazy> ResourceClaimActions { get; private set; } = default!; protected void Initialize( Func application, @@ -60,7 +60,7 @@ protected void Reset() ResourceClaimActions.Reset(); } - public virtual Action GetActionByHttpVerb(string httpVerb) + public virtual Action? GetActionByHttpVerb(string httpVerb) { string actionName = string.Empty; @@ -83,7 +83,7 @@ public virtual Action GetActionByHttpVerb(string httpVerb) return GetActionByName(actionName); } - public virtual Action GetActionByName(string actionName) + public virtual Action? GetActionByName(string actionName) { return Actions.Value.FirstOrDefault(a => a.ActionName.Equals(actionName, StringComparison.InvariantCultureIgnoreCase)); } @@ -115,7 +115,7 @@ private IEnumerable GetResourceClaimLineageForResourceClaim(strin { var resourceClaimLineage = new List(); - ResourceClaim resourceClaim; + ResourceClaim? resourceClaim = null; try { @@ -124,8 +124,8 @@ private IEnumerable GetResourceClaimLineageForResourceClaim(strin } catch (InvalidOperationException ex) { - // Use InvalidOperationException wrapper with custom message over InvalidOperationException - // thrown by Linq to communicate back to caller the problem with the configuration. + // Use InvalidOperationException wrapper with custom message over InvalidOperationException + // thrown by Linq to communicate back to caller the problem with the configuration. throw new InvalidOperationException($"Multiple resource claims with a claim name of '{resourceClaimUri}' were found in the Ed-Fi API's security configuration. Authorization cannot be performed.", ex); } @@ -183,7 +183,7 @@ private void AddStrategiesForResourceClaimLineage(List stra } } - public virtual ResourceClaim GetResourceByResourceName(string resourceName) + public virtual ResourceClaim? GetResourceByResourceName(string resourceName) { return ResourceClaims .Value diff --git a/Application/EdFi.Ods.AdminApi/Infrastructure/WebApplicationBuilderExtensions.cs b/Application/EdFi.Ods.AdminApi/Infrastructure/WebApplicationBuilderExtensions.cs index 0572294b9..6d5bcedf1 100644 --- a/Application/EdFi.Ods.AdminApi/Infrastructure/WebApplicationBuilderExtensions.cs +++ b/Application/EdFi.Ods.AdminApi/Infrastructure/WebApplicationBuilderExtensions.cs @@ -68,7 +68,7 @@ public static void AddServices(this WebApplicationBuilder webApplicationBuilder) webApplicationBuilder.Services.AddAutoMapper( assembly, - typeof(V1.Infrastructure.AdminApiMappingProfile).Assembly + typeof(V1.Infrastructure.AutoMapper.AdminApiMappingProfile).Assembly ); var adminApiV1Types = typeof(V1.Infrastructure.IMarkerForEdFiOdsAdminApiManagement).Assembly.GetTypes();