1
0
mirror of https://github.com/bitwarden/server.git synced 2024-11-21 12:05:42 +01:00

PM-13236 - Password Health Report Application - entities repos (#4974)

* PM-13236 PasswordHealthReportApplications db

* PM-13236 incorporated pr comments

* PM-13236 fixed error in SQL script

* PM-13236 resolve quality scan errors SQL71006, SQL7101, SQL70001

* PM-13236 fixed warnings on procedures

* PM-13236 added efMigrations

* PM-13236 renamed files to PasswordHealthReportApplication (singular)

* PM-13236 changed file name to more appropriate naming

* PM-13236 changed the file name singular

* PM-13236 PasswordHealthReportApplication Entities and Repos

* PM-13236 moved files under tools from core

* PM-13236 Entity PasswordHealthReportApplication namespace changed to tools/entities

* PM-13236 moved Repos and Interfaces to tools

* PM-13236 migrated model to tools namespace

* PM-13236 minor fixes to the unit tests

* PM-13236 fixed script errors during build

* PM-13236 Script to drop PasswordHealthReportApplications if it exists

* PM-13236 fixes to database snapshot

* PM-13236 updated databasesnapshots

* PM-13236 Update database model changes for Mysql

* PM-13236 update model changes for Sqlite

* PM-13236 updated the models to remove commented code

* PM-13236 added correct db snapshot for MySql

* PM-13236 updated database snapshot for Postgres

* PM-13236 updated database snapshot for Sqlite

* PM-13236 removed unwanted directive to fix linting error

* PM-13236 removed redundant script files
This commit is contained in:
Vijay Oommen 2024-11-08 10:28:56 -06:00 committed by GitHub
parent e7cbdaa469
commit 7cf6742595
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 9317 additions and 1 deletions

View File

@ -1,11 +1,15 @@
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Utilities; using Bit.Core.Utilities;
#nullable enable
namespace Bit.Core.Tools.Entities;
public class PasswordHealthReportApplication : ITableObject<Guid>, IRevisable public class PasswordHealthReportApplication : ITableObject<Guid>, IRevisable
{ {
public Guid Id { get; set; } public Guid Id { get; set; }
public Guid OrganizationId { get; set; } public Guid OrganizationId { get; set; }
public string Uri { get; set; } public string? Uri { get; set; }
public DateTime CreationDate { get; set; } = DateTime.UtcNow; public DateTime CreationDate { get; set; } = DateTime.UtcNow;
public DateTime RevisionDate { get; set; } = DateTime.UtcNow; public DateTime RevisionDate { get; set; } = DateTime.UtcNow;

View File

@ -0,0 +1,9 @@
using Bit.Core.Repositories;
using Bit.Core.Tools.Entities;
namespace Bit.Core.Tools.Repositories;
public interface IPasswordHealthReportApplicationRepository : IRepository<PasswordHealthReportApplication, Guid>
{
Task<ICollection<PasswordHealthReportApplication>> GetByOrganizationIdAsync(Guid organizationId);
}

View File

@ -58,6 +58,7 @@ public static class DapperServiceCollectionExtensions
services.AddSingleton<INotificationStatusRepository, NotificationStatusRepository>(); services.AddSingleton<INotificationStatusRepository, NotificationStatusRepository>();
services services
.AddSingleton<IClientOrganizationMigrationRecordRepository, ClientOrganizationMigrationRecordRepository>(); .AddSingleton<IClientOrganizationMigrationRecordRepository, ClientOrganizationMigrationRecordRepository>();
services.AddSingleton<IPasswordHealthReportApplicationRepository, PasswordHealthReportApplicationRepository>();
if (selfHosted) if (selfHosted)
{ {

View File

@ -0,0 +1,33 @@
using System.Data;
using Bit.Core.Settings;
using Bit.Core.Tools.Repositories;
using Bit.Infrastructure.Dapper.Repositories;
using Dapper;
using Microsoft.Data.SqlClient;
using ToolsEntities = Bit.Core.Tools.Entities;
namespace Bit.Infrastructure.Dapper.Tools.Repositories;
public class PasswordHealthReportApplicationRepository : Repository<ToolsEntities.PasswordHealthReportApplication, Guid>, IPasswordHealthReportApplicationRepository
{
public PasswordHealthReportApplicationRepository(GlobalSettings globalSettings)
: this(globalSettings.SqlServer.ConnectionString, globalSettings.SqlServer.ReadOnlyConnectionString)
{ }
public PasswordHealthReportApplicationRepository(string connectionString, string readOnlyConnectionString)
: base(connectionString, readOnlyConnectionString)
{ }
public async Task<ICollection<ToolsEntities.PasswordHealthReportApplication>> GetByOrganizationIdAsync(Guid organizationId)
{
using (var connection = new SqlConnection(ReadOnlyConnectionString))
{
var results = await connection.QueryAsync<ToolsEntities.PasswordHealthReportApplication>(
$"[{Schema}].[PasswordHealthReportApplication_ReadByOrganizationId]",
new { OrganizationId = organizationId },
commandType: CommandType.StoredProcedure);
return results.ToList();
}
}
}

View File

@ -7,6 +7,7 @@ using Bit.Infrastructure.EntityFramework.Converters;
using Bit.Infrastructure.EntityFramework.Models; using Bit.Infrastructure.EntityFramework.Models;
using Bit.Infrastructure.EntityFramework.NotificationCenter.Models; using Bit.Infrastructure.EntityFramework.NotificationCenter.Models;
using Bit.Infrastructure.EntityFramework.SecretsManager.Models; using Bit.Infrastructure.EntityFramework.SecretsManager.Models;
using Bit.Infrastructure.EntityFramework.Tools.Models;
using Bit.Infrastructure.EntityFramework.Vault.Models; using Bit.Infrastructure.EntityFramework.Vault.Models;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Infrastructure;
@ -75,6 +76,7 @@ public class DatabaseContext : DbContext
public DbSet<Notification> Notifications { get; set; } public DbSet<Notification> Notifications { get; set; }
public DbSet<NotificationStatus> NotificationStatuses { get; set; } public DbSet<NotificationStatus> NotificationStatuses { get; set; }
public DbSet<ClientOrganizationMigrationRecord> ClientOrganizationMigrationRecords { get; set; } public DbSet<ClientOrganizationMigrationRecord> ClientOrganizationMigrationRecords { get; set; }
public DbSet<PasswordHealthReportApplication> PasswordHealthReportApplications { get; set; }
protected override void OnModelCreating(ModelBuilder builder) protected override void OnModelCreating(ModelBuilder builder)
{ {

View File

@ -0,0 +1,24 @@
using Bit.Infrastructure.EntityFramework.Tools.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Bit.Infrastructure.EntityFramework.Tools.Configurations;
public class PasswordHealthReportApplicationEntityTypeConfiguration : IEntityTypeConfiguration<PasswordHealthReportApplication>
{
public void Configure(EntityTypeBuilder<PasswordHealthReportApplication> builder)
{
builder
.Property(s => s.Id)
.ValueGeneratedNever();
builder.HasIndex(s => s.Id)
.IsClustered(true);
builder
.HasIndex(s => s.OrganizationId)
.IsClustered(false);
builder.ToTable(nameof(PasswordHealthReportApplication));
}
}

View File

@ -0,0 +1,18 @@
using AutoMapper;
using Bit.Infrastructure.EntityFramework.AdminConsole.Models;
namespace Bit.Infrastructure.EntityFramework.Tools.Models;
public class PasswordHealthReportApplication : Core.Tools.Entities.PasswordHealthReportApplication
{
public virtual Organization Organization { get; set; }
}
public class PasswordHealthReportApplicationProfile : Profile
{
public PasswordHealthReportApplicationProfile()
{
CreateMap<Core.Tools.Entities.PasswordHealthReportApplication, PasswordHealthReportApplication>()
.ReverseMap();
}
}

View File

@ -0,0 +1,30 @@
using AutoMapper;
using Bit.Core.Tools.Repositories;
using Bit.Infrastructure.EntityFramework.Repositories;
using Bit.Infrastructure.EntityFramework.Tools.Models;
using LinqToDB;
using Microsoft.Extensions.DependencyInjection;
using AdminConsoleEntities = Bit.Core.Tools.Entities;
namespace Bit.Infrastructure.EntityFramework.Tools.Repositories;
public class PasswordHealthReportApplicationRepository :
Repository<AdminConsoleEntities.PasswordHealthReportApplication, PasswordHealthReportApplication, Guid>,
IPasswordHealthReportApplicationRepository
{
public PasswordHealthReportApplicationRepository(IServiceScopeFactory serviceScopeFactory,
IMapper mapper) : base(serviceScopeFactory, mapper, (DatabaseContext context) => context.PasswordHealthReportApplications)
{ }
public async Task<ICollection<AdminConsoleEntities.PasswordHealthReportApplication>> GetByOrganizationIdAsync(Guid organizationId)
{
using (var scope = ServiceScopeFactory.CreateScope())
{
var dbContext = GetDatabaseContext(scope);
var results = await dbContext.PasswordHealthReportApplications
.Where(p => p.OrganizationId == organizationId)
.ToListAsync();
return Mapper.Map<ICollection<AdminConsoleEntities.PasswordHealthReportApplication>>(results);
}
}
}

View File

@ -9,6 +9,7 @@ using Bit.Infrastructure.EntityFramework.AdminConsole.Models.Provider;
using Bit.Infrastructure.EntityFramework.Auth.Models; using Bit.Infrastructure.EntityFramework.Auth.Models;
using Bit.Infrastructure.EntityFramework.Models; using Bit.Infrastructure.EntityFramework.Models;
using Bit.Infrastructure.EntityFramework.Repositories; using Bit.Infrastructure.EntityFramework.Repositories;
using Bit.Infrastructure.EntityFramework.Tools.Models;
using Bit.Infrastructure.EntityFramework.Vault.Models; using Bit.Infrastructure.EntityFramework.Vault.Models;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
@ -89,6 +90,7 @@ public class EfRepositoryListBuilder<T> : ISpecimenBuilder where T : BaseEntityF
cfg.AddProfile<TaxRateMapperProfile>(); cfg.AddProfile<TaxRateMapperProfile>();
cfg.AddProfile<TransactionMapperProfile>(); cfg.AddProfile<TransactionMapperProfile>();
cfg.AddProfile<UserMapperProfile>(); cfg.AddProfile<UserMapperProfile>();
cfg.AddProfile<PasswordHealthReportApplicationProfile>();
}) })
.CreateMapper())); .CreateMapper()));

View File

@ -0,0 +1,82 @@
using AutoFixture;
using AutoFixture.Kernel;
using Bit.Core.Tools.Entities;
using Bit.Infrastructure.EntityFramework.AdminConsole.Repositories;
using Bit.Infrastructure.EntityFramework.Repositories;
using Bit.Infrastructure.EntityFramework.Tools.Repositories;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
namespace Bit.Infrastructure.EFIntegration.Test.AutoFixture;
internal class PasswordHealthReportApplicationBuilder : ISpecimenBuilder
{
public object Create(object request, ISpecimenContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var type = request as Type;
if (type == null || type != typeof(PasswordHealthReportApplication))
{
return new NoSpecimen();
}
var fixture = new Fixture();
var obj = fixture.WithAutoNSubstitutions().Create<PasswordHealthReportApplication>();
return obj;
}
}
internal class EfPasswordHealthReportApplication : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customizations.Add(new IgnoreVirtualMembersCustomization());
fixture.Customizations.Add(new GlobalSettingsBuilder());
fixture.Customizations.Add(new PasswordHealthReportApplicationBuilder());
fixture.Customizations.Add(new OrganizationBuilder());
fixture.Customizations.Add(new EfRepositoryListBuilder<PasswordHealthReportApplicationRepository>());
fixture.Customizations.Add(new EfRepositoryListBuilder<OrganizationRepository>());
}
}
internal class EfPasswordHealthReportApplicationApplicableToUser : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customizations.Add(new IgnoreVirtualMembersCustomization());
fixture.Customizations.Add(new GlobalSettingsBuilder());
fixture.Customizations.Add(new PasswordHealthReportApplicationBuilder());
fixture.Customizations.Add(new OrganizationBuilder());
fixture.Customizations.Add(new EfRepositoryListBuilder<PasswordHealthReportApplicationRepository>());
fixture.Customizations.Add(new EfRepositoryListBuilder<UserRepository>());
fixture.Customizations.Add(new EfRepositoryListBuilder<OrganizationRepository>());
fixture.Customizations.Add(new EfRepositoryListBuilder<OrganizationUserRepository>());
fixture.Customizations.Add(new EfRepositoryListBuilder<ProviderRepository>());
fixture.Customizations.Add(new EfRepositoryListBuilder<ProviderUserRepository>());
fixture.Customizations.Add(new EfRepositoryListBuilder<ProviderOrganizationRepository>());
}
}
internal class EfPasswordHealthReportApplicationAutoDataAttribute : CustomAutoDataAttribute
{
public EfPasswordHealthReportApplicationAutoDataAttribute() : base(new SutProviderCustomization(), new EfPasswordHealthReportApplication())
{ }
}
internal class EfPasswordHealthReportApplicationApplicableToUserInlineAutoDataAttribute : InlineCustomAutoDataAttribute
{
public EfPasswordHealthReportApplicationApplicableToUserInlineAutoDataAttribute(params object[] values) :
base(new[] { typeof(SutProviderCustomization), typeof(EfPasswordHealthReportApplicationApplicableToUser) }, values)
{ }
}
internal class InlineEfPasswordHealthReportApplicationAutoDataAttribute : InlineCustomAutoDataAttribute
{
public InlineEfPasswordHealthReportApplicationAutoDataAttribute(params object[] values) : base(new[] { typeof(SutProviderCustomization),
typeof(EfPolicy) }, values)
{ }
}

View File

@ -0,0 +1,269 @@
using AutoFixture;
using Bit.Core.AdminConsole.Entities;
using Bit.Core.Repositories;
using Bit.Core.Test.AutoFixture.Attributes;
using Bit.Core.Tools.Entities;
using Bit.Core.Tools.Repositories;
using Bit.Infrastructure.EFIntegration.Test.AutoFixture;
using Xunit;
using EfRepo = Bit.Infrastructure.EntityFramework.Repositories;
using EfToolsRepo = Bit.Infrastructure.EntityFramework.Tools.Repositories;
using SqlAdminConsoleRepo = Bit.Infrastructure.Dapper.Tools.Repositories;
using SqlRepo = Bit.Infrastructure.Dapper.Repositories;
namespace Bit.Infrastructure.EFIntegration.Test.Tools.Repositories;
public class PasswordHealthReportApplicationRepositoryTests
{
[CiSkippedTheory, EfPasswordHealthReportApplicationAutoData]
public async Task CreateAsync_Works_DataMatches(
PasswordHealthReportApplication passwordHealthReportApplication,
Organization organization,
List<EfToolsRepo.PasswordHealthReportApplicationRepository> suts,
List<EfRepo.OrganizationRepository> efOrganizationRepos,
SqlAdminConsoleRepo.PasswordHealthReportApplicationRepository sqlPasswordHealthReportApplicationRepo,
SqlRepo.OrganizationRepository sqlOrganizationRepo
)
{
var passwordHealthReportApplicationRecords = new List<PasswordHealthReportApplication>();
foreach (var sut in suts)
{
var i = suts.IndexOf(sut);
var efOrganization = await efOrganizationRepos[i].CreateAsync(organization);
sut.ClearChangeTracking();
passwordHealthReportApplication.OrganizationId = efOrganization.Id;
var postEfPasswordHeathReportApp = await sut.CreateAsync(passwordHealthReportApplication);
sut.ClearChangeTracking();
var savedPasswordHealthReportApplication = await sut.GetByIdAsync(postEfPasswordHeathReportApp.Id);
passwordHealthReportApplicationRecords.Add(savedPasswordHealthReportApplication);
}
var sqlOrganization = await sqlOrganizationRepo.CreateAsync(organization);
passwordHealthReportApplication.OrganizationId = sqlOrganization.Id;
var sqlPasswordHealthReportApplicationRecord = await sqlPasswordHealthReportApplicationRepo.CreateAsync(passwordHealthReportApplication);
var savedSqlPasswordHealthReportApplicationRecord = await sqlPasswordHealthReportApplicationRepo.GetByIdAsync(sqlPasswordHealthReportApplicationRecord.Id);
passwordHealthReportApplicationRecords.Add(savedSqlPasswordHealthReportApplicationRecord);
Assert.True(passwordHealthReportApplicationRecords.Count == 4);
}
[CiSkippedTheory, EfPasswordHealthReportApplicationAutoData]
public async Task RetrieveByOrganisation_Works(
SqlAdminConsoleRepo.PasswordHealthReportApplicationRepository sqlPasswordHealthReportApplicationRepo,
SqlRepo.OrganizationRepository sqlOrganizationRepo)
{
var (firstOrg, firstRecord) = await CreateSampleRecord(sqlOrganizationRepo, sqlPasswordHealthReportApplicationRepo);
var (secondOrg, secondRecord) = await CreateSampleRecord(sqlOrganizationRepo, sqlPasswordHealthReportApplicationRepo);
var firstSetOfRecords = await sqlPasswordHealthReportApplicationRepo.GetByOrganizationIdAsync(firstOrg.Id);
var nextSetOfRecords = await sqlPasswordHealthReportApplicationRepo.GetByOrganizationIdAsync(secondOrg.Id);
Assert.True(firstSetOfRecords.Count == 1 && firstSetOfRecords.First().OrganizationId == firstOrg.Id);
Assert.True(nextSetOfRecords.Count == 1 && nextSetOfRecords.First().OrganizationId == secondOrg.Id);
}
[CiSkippedTheory, EfPasswordHealthReportApplicationAutoData]
public async Task ReplaceQuery_Works(
List<EfToolsRepo.PasswordHealthReportApplicationRepository> suts,
List<EfRepo.OrganizationRepository> efOrganizationRepos,
SqlAdminConsoleRepo.PasswordHealthReportApplicationRepository sqlPasswordHealthReportApplicationRepo,
SqlRepo.OrganizationRepository sqlOrganizationRepo)
{
var (org, pwdRecord) = await CreateSampleRecord(sqlOrganizationRepo, sqlPasswordHealthReportApplicationRepo);
var exampleUri = "http://www.example.com";
var exampleRevisionDate = new DateTime(2021, 1, 1);
var dbRecords = new List<PasswordHealthReportApplication>();
foreach (var sut in suts)
{
var i = suts.IndexOf(sut);
// create a new organization for each repository
var organization = await efOrganizationRepos[i].CreateAsync(org);
// map the organization Id and create the PasswordHealthReportApp record
pwdRecord.OrganizationId = organization.Id;
var passwordHealthReportApplication = await sut.CreateAsync(pwdRecord);
// update the record with new values
passwordHealthReportApplication.Uri = exampleUri;
passwordHealthReportApplication.RevisionDate = exampleRevisionDate;
// apply update to the database
await sut.ReplaceAsync(passwordHealthReportApplication);
sut.ClearChangeTracking();
// retrieve the data and add to the list for assertions
var recordFromDb = await sut.GetByIdAsync(passwordHealthReportApplication.Id);
sut.ClearChangeTracking();
dbRecords.Add(recordFromDb);
}
// sql - create a new organization and PasswordHealthReportApplication record
var (sqlOrg, sqlPwdRecord) = await CreateSampleRecord(sqlOrganizationRepo, sqlPasswordHealthReportApplicationRepo);
var sqlPasswordHealthReportApplicationRecord = await sqlPasswordHealthReportApplicationRepo.GetByIdAsync(sqlPwdRecord.Id);
// sql - update the record with new values
sqlPasswordHealthReportApplicationRecord.Uri = exampleUri;
sqlPasswordHealthReportApplicationRecord.RevisionDate = exampleRevisionDate;
await sqlPasswordHealthReportApplicationRepo.ReplaceAsync(sqlPasswordHealthReportApplicationRecord);
// sql - retrieve the data and add to the list for assertions
var sqlDbRecord = await sqlPasswordHealthReportApplicationRepo.GetByIdAsync(sqlPasswordHealthReportApplicationRecord.Id);
dbRecords.Add(sqlDbRecord);
// assertions
// the Guids must be distinct across all records
Assert.True(dbRecords.Select(_ => _.Id).Distinct().Count() == dbRecords.Count);
// the Uri and RevisionDate must match the updated values
Assert.True(dbRecords.All(_ => _.Uri == exampleUri && _.RevisionDate == exampleRevisionDate));
}
[CiSkippedTheory, EfPasswordHealthReportApplicationAutoData]
public async Task Upsert_Works(
List<EfToolsRepo.PasswordHealthReportApplicationRepository> suts,
List<EfRepo.OrganizationRepository> efOrganizationRepos,
SqlAdminConsoleRepo.PasswordHealthReportApplicationRepository sqlPasswordHealthReportApplicationRepo,
SqlRepo.OrganizationRepository sqlOrganizationRepo)
{
var fixture = new Fixture();
var rawOrg = fixture.Build<Organization>().Create();
var rawPwdRecord = fixture.Build<PasswordHealthReportApplication>()
.With(_ => _.OrganizationId, rawOrg.Id)
.Without(_ => _.Id)
.Create();
var exampleUri = "http://www.example.com";
var exampleRevisionDate = new DateTime(2021, 1, 1);
var dbRecords = new List<PasswordHealthReportApplication>();
foreach (var sut in suts)
{
var i = suts.IndexOf(sut);
// create a new organization for each repository
var organization = await efOrganizationRepos[i].CreateAsync(rawOrg);
// map the organization Id and use Upsert to save new record
rawPwdRecord.OrganizationId = organization.Id;
rawPwdRecord.Id = default(Guid);
await sut.UpsertAsync(rawPwdRecord);
sut.ClearChangeTracking();
// retrieve the data and add to the list for assertions
var passwordHealthReportApplication = await sut.GetByIdAsync(rawPwdRecord.Id);
// update the record with new values
passwordHealthReportApplication.Uri = exampleUri;
passwordHealthReportApplication.RevisionDate = exampleRevisionDate;
// apply update using Upsert to make changes to db
await sut.UpsertAsync(passwordHealthReportApplication);
sut.ClearChangeTracking();
// retrieve the data and add to the list for assertions
var recordFromDb = await sut.GetByIdAsync(passwordHealthReportApplication.Id);
dbRecords.Add(recordFromDb);
sut.ClearChangeTracking();
}
// sql - create new records
var organizationForSql = fixture.Create<Organization>();
var passwordHealthReportApplicationForSql = fixture.Build<PasswordHealthReportApplication>()
.With(_ => _.OrganizationId, organizationForSql.Id)
.Without(_ => _.Id)
.Create();
// sql - use Upsert to insert this data
var sqlOrganization = await sqlOrganizationRepo.CreateAsync(organizationForSql);
await sqlPasswordHealthReportApplicationRepo.UpsertAsync(passwordHealthReportApplicationForSql);
var sqlPasswordHealthReportApplicationRecord = await sqlPasswordHealthReportApplicationRepo.GetByIdAsync(passwordHealthReportApplicationForSql.Id);
// sql - update the record with new values
sqlPasswordHealthReportApplicationRecord.Uri = exampleUri;
sqlPasswordHealthReportApplicationRecord.RevisionDate = exampleRevisionDate;
await sqlPasswordHealthReportApplicationRepo.UpsertAsync(sqlPasswordHealthReportApplicationRecord);
// sql - retrieve the data and add to the list for assertions
var sqlDbRecord = await sqlPasswordHealthReportApplicationRepo.GetByIdAsync(sqlPasswordHealthReportApplicationRecord.Id);
dbRecords.Add(sqlDbRecord);
// assertions
// the Guids must be distinct across all records
Assert.True(dbRecords.Select(_ => _.Id).Distinct().Count() == dbRecords.Count);
// the Uri and RevisionDate must match the updated values
Assert.True(dbRecords.All(_ => _.Uri == exampleUri && _.RevisionDate == exampleRevisionDate));
}
[CiSkippedTheory, EfPasswordHealthReportApplicationAutoData]
public async Task Delete_Works(
List<EfToolsRepo.PasswordHealthReportApplicationRepository> suts,
List<EfRepo.OrganizationRepository> efOrganizationRepos,
SqlAdminConsoleRepo.PasswordHealthReportApplicationRepository sqlPasswordHealthReportApplicationRepo,
SqlRepo.OrganizationRepository sqlOrganizationRepo)
{
var fixture = new Fixture();
var rawOrg = fixture.Build<Organization>().Create();
var rawPwdRecord = fixture.Build<PasswordHealthReportApplication>()
.With(_ => _.OrganizationId, rawOrg.Id)
.Create();
var dbRecords = new List<PasswordHealthReportApplication>();
foreach (var sut in suts)
{
var i = suts.IndexOf(sut);
// create a new organization for each repository
var organization = await efOrganizationRepos[i].CreateAsync(rawOrg);
// map the organization Id and use Upsert to save new record
rawPwdRecord.OrganizationId = organization.Id;
rawPwdRecord = await sut.CreateAsync(rawPwdRecord);
sut.ClearChangeTracking();
// apply update using Upsert to make changes to db
await sut.DeleteAsync(rawPwdRecord);
sut.ClearChangeTracking();
// retrieve the data and add to the list for assertions
var recordFromDb = await sut.GetByIdAsync(rawPwdRecord.Id);
dbRecords.Add(recordFromDb);
sut.ClearChangeTracking();
}
// sql - create new records
var (org, passwordHealthReportApplication) = await CreateSampleRecord(sqlOrganizationRepo, sqlPasswordHealthReportApplicationRepo);
await sqlPasswordHealthReportApplicationRepo.DeleteAsync(passwordHealthReportApplication);
var sqlDbRecord = await sqlPasswordHealthReportApplicationRepo.GetByIdAsync(passwordHealthReportApplication.Id);
dbRecords.Add(sqlDbRecord);
// assertions
// all records should be null - as they were deleted before querying
Assert.True(dbRecords.Where(_ => _ == null).Count() == 4);
}
private async Task<(Organization, PasswordHealthReportApplication)> CreateSampleRecord(
IOrganizationRepository organizationRepo,
IPasswordHealthReportApplicationRepository passwordHealthReportApplicationRepo
)
{
var fixture = new Fixture();
var organization = fixture.Create<Organization>();
var passwordHealthReportApplication = fixture.Build<PasswordHealthReportApplication>()
.With(_ => _.OrganizationId, organization.Id)
.Create();
organization = await organizationRepo.CreateAsync(organization);
passwordHealthReportApplication = await passwordHealthReportApplicationRepo.CreateAsync(passwordHealthReportApplication);
return (organization, passwordHealthReportApplication);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,22 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Bit.MySqlMigrations.Migrations;
/// <inheritdoc />
public partial class FixPasswordHealthReportApplication : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
// this file is not required, but the designer file is required
// in order to keep the database models in sync with the database
// without this - the unit tests will fail when run on your local machine
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}

View File

@ -1887,6 +1887,34 @@ namespace Bit.MySqlMigrations.Migrations
b.ToTable("ServiceAccount", (string)null); b.ToTable("ServiceAccount", (string)null);
}); });
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Tools.Models.PasswordHealthReportApplication", b =>
{
b.Property<Guid>("Id")
.HasColumnType("char(36)");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime(6)");
b.Property<Guid>("OrganizationId")
.HasColumnType("char(36)");
b.Property<DateTime>("RevisionDate")
.HasColumnType("datetime(6)");
b.Property<string>("Uri")
.HasColumnType("longtext");
b.HasKey("Id");
b.HasIndex("Id")
.HasAnnotation("SqlServer:Clustered", true);
b.HasIndex("OrganizationId")
.HasAnnotation("SqlServer:Clustered", false);
b.ToTable("PasswordHealthReportApplication", (string)null);
});
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Vault.Models.Cipher", b => modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Vault.Models.Cipher", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")
@ -2578,6 +2606,17 @@ namespace Bit.MySqlMigrations.Migrations
b.Navigation("Organization"); b.Navigation("Organization");
}); });
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Tools.Models.PasswordHealthReportApplication", b =>
{
b.HasOne("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Organization", "Organization")
.WithMany()
.HasForeignKey("OrganizationId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Organization");
});
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Vault.Models.Cipher", b => modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Vault.Models.Cipher", b =>
{ {
b.HasOne("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Organization", "Organization") b.HasOne("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Organization", "Organization")

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,22 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Bit.PostgresMigrations.Migrations;
/// <inheritdoc />
public partial class FixPasswordHealthReportApplication : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
// this file is not required, but the designer file is required
// in order to keep the database models in sync with the database
// without this - the unit tests will fail when run on your local machine
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}

View File

@ -1893,6 +1893,34 @@ namespace Bit.PostgresMigrations.Migrations
b.ToTable("ServiceAccount", (string)null); b.ToTable("ServiceAccount", (string)null);
}); });
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Tools.Models.PasswordHealthReportApplication", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
b.Property<DateTime>("CreationDate")
.HasColumnType("timestamp with time zone");
b.Property<Guid>("OrganizationId")
.HasColumnType("uuid");
b.Property<DateTime>("RevisionDate")
.HasColumnType("timestamp with time zone");
b.Property<string>("Uri")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("Id")
.HasAnnotation("SqlServer:Clustered", true);
b.HasIndex("OrganizationId")
.HasAnnotation("SqlServer:Clustered", false);
b.ToTable("PasswordHealthReportApplication", (string)null);
});
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Vault.Models.Cipher", b => modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Vault.Models.Cipher", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")
@ -2584,6 +2612,17 @@ namespace Bit.PostgresMigrations.Migrations
b.Navigation("Organization"); b.Navigation("Organization");
}); });
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Tools.Models.PasswordHealthReportApplication", b =>
{
b.HasOne("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Organization", "Organization")
.WithMany()
.HasForeignKey("OrganizationId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Organization");
});
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Vault.Models.Cipher", b => modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Vault.Models.Cipher", b =>
{ {
b.HasOne("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Organization", "Organization") b.HasOne("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Organization", "Organization")

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,22 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Bit.SqliteMigrations.Migrations;
/// <inheritdoc />
public partial class FixPasswordHealthReportApplication : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
// this file is not required, but the designer file is required
// in order to keep the database models in sync with the database
// without this - the unit tests will fail when run on your local machine
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}

View File

@ -1876,6 +1876,34 @@ namespace Bit.SqliteMigrations.Migrations
b.ToTable("ServiceAccount", (string)null); b.ToTable("ServiceAccount", (string)null);
}); });
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Tools.Models.PasswordHealthReportApplication", b =>
{
b.Property<Guid>("Id")
.HasColumnType("TEXT");
b.Property<DateTime>("CreationDate")
.HasColumnType("TEXT");
b.Property<Guid>("OrganizationId")
.HasColumnType("TEXT");
b.Property<DateTime>("RevisionDate")
.HasColumnType("TEXT");
b.Property<string>("Uri")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("Id")
.HasAnnotation("SqlServer:Clustered", true);
b.HasIndex("OrganizationId")
.HasAnnotation("SqlServer:Clustered", false);
b.ToTable("PasswordHealthReportApplication", (string)null);
});
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Vault.Models.Cipher", b => modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Vault.Models.Cipher", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")
@ -2567,6 +2595,17 @@ namespace Bit.SqliteMigrations.Migrations
b.Navigation("Organization"); b.Navigation("Organization");
}); });
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Tools.Models.PasswordHealthReportApplication", b =>
{
b.HasOne("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Organization", "Organization")
.WithMany()
.HasForeignKey("OrganizationId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Organization");
});
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Vault.Models.Cipher", b => modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Vault.Models.Cipher", b =>
{ {
b.HasOne("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Organization", "Organization") b.HasOne("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Organization", "Organization")