1
0
mirror of https://github.com/bitwarden/server.git synced 2025-06-24 12:48:48 -05:00

PM-20574 & PM-20575 Adding Risk Insight Report tables, repositories, and migrations (#5839)

* PM-20574 fixing namespaces on reporting work that got moved over from tools

* PM-20574 adding tables, stored procedures, and migration files

* PM-20574 adding dapper and ef repos and migrations

* PM-20574 changing table and repo names as requested

* PM-20574 updating sql scripts to new names

* PM-20574 updating sql scripts

* PM-20574 updating migration script for org delete by id

* PM-20574 adding mysql migration

* PM-20574 updating sql migration to fix database test

* PM-20574 fixing migration script

* PM-20574 fixing migration script

* PM-20574 fixing table scripts

* PM-20574 fixing table scripts

* PM-20574 fixing migration script formatting

* PM-20574 fixing syntax in migration script

* PM-20574 fixing file names and extensions

* PM-20574 fixing sql file

* PM-20574 fixing sql

* PM-20574 fixing directory for entities and removing scripts from other databases

* PM-20574 generating new migration scripts

* PM-20574 fixed reference to a stored proc

* PM-20574 adding index in scripts and missing table

* PM-20574 fixing merge conflicts

* PM-20574 set OUTPUT param for Id property in create and update proc

* PM-20574 add CreateDate to the update proc

* PM-20574 amend update proc for OrganizationApplication by adding createDate

* PM-20574 formatted sql and updated as per PR comments

* PM-20574 updated script to fix build error

* PM-20574 fixed inconsistency in db script

* PM-20574 removed revisionDate, update procedures and used views

* PM-20574 removed RevisionDate from designer files

* PM-20574 removed revisionDate column that was missed previously

* PM-20574 added revision date back into the mix

* PM-20574 updated database script to fix build error

* PM-20574 fixed a procedure issue

* PM-20574 fix dB build error

* PM-020574 fixed additional PR comments - files cleaned up

* PM-20574 updated procedure was inconsistent

* Update 2025-06-13-00_OrganizationReport.sql

---------

Co-authored-by: voommen-livefront <voommen@livefront.com>
This commit is contained in:
Graham Walker 2025-06-23 12:12:04 -05:00 committed by GitHub
parent d2410747d0
commit 173db0a2dd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
66 changed files with 11103 additions and 33 deletions

View File

@ -2,7 +2,7 @@
using Bit.Api.Dirt.Models.Response; using Bit.Api.Dirt.Models.Response;
using Bit.Api.Tools.Models.Response; using Bit.Api.Tools.Models.Response;
using Bit.Core.Context; using Bit.Core.Context;
using Bit.Core.Dirt.Reports.Entities; using Bit.Core.Dirt.Entities;
using Bit.Core.Dirt.Reports.Models.Data; using Bit.Core.Dirt.Reports.Models.Data;
using Bit.Core.Dirt.Reports.ReportFeatures.Interfaces; using Bit.Core.Dirt.Reports.ReportFeatures.Interfaces;
using Bit.Core.Dirt.Reports.ReportFeatures.OrganizationReportMembers.Interfaces; using Bit.Core.Dirt.Reports.ReportFeatures.OrganizationReportMembers.Interfaces;

View File

@ -1,4 +1,4 @@
using Bit.Core.Dirt.Reports.Models.Data; using Bit.Core.Dirt.Models.Data;
namespace Bit.Api.Dirt.Models.Response; namespace Bit.Api.Dirt.Models.Response;

View File

@ -1,5 +1,4 @@
using Bit.Core.Dirt.Reports.Models.Data; using Bit.Core.Dirt.Reports.Models.Data;
namespace Bit.Api.Dirt.Models.Response; namespace Bit.Api.Dirt.Models.Response;
public class MemberCipherDetailsResponseModel public class MemberCipherDetailsResponseModel

View File

@ -0,0 +1,20 @@
#nullable enable
using Bit.Core.Entities;
using Bit.Core.Utilities;
namespace Bit.Core.Dirt.Entities;
public class OrganizationApplication : ITableObject<Guid>, IRevisable
{
public Guid Id { get; set; }
public Guid OrganizationId { get; set; }
public string Applications { get; set; } = string.Empty;
public DateTime CreationDate { get; set; } = DateTime.UtcNow;
public DateTime RevisionDate { get; set; } = DateTime.UtcNow;
public void SetNewId()
{
Id = CoreHelpers.GenerateComb();
}
}

View File

@ -0,0 +1,20 @@
#nullable enable
using Bit.Core.Entities;
using Bit.Core.Utilities;
namespace Bit.Core.Dirt.Entities;
public class OrganizationReport : ITableObject<Guid>
{
public Guid Id { get; set; }
public Guid OrganizationId { get; set; }
public DateTime Date { get; set; }
public string ReportData { get; set; } = string.Empty;
public DateTime CreationDate { get; set; } = DateTime.UtcNow;
public void SetNewId()
{
Id = CoreHelpers.GenerateComb();
}
}

View File

@ -3,7 +3,7 @@
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Utilities; using Bit.Core.Utilities;
namespace Bit.Core.Dirt.Reports.Entities; namespace Bit.Core.Dirt.Entities;
public class PasswordHealthReportApplication : ITableObject<Guid>, IRevisable public class PasswordHealthReportApplication : ITableObject<Guid>, IRevisable
{ {

View File

@ -1,4 +1,4 @@
namespace Bit.Core.Dirt.Reports.Models.Data; namespace Bit.Core.Dirt.Models.Data;
public class MemberAccessDetails public class MemberAccessDetails
{ {

View File

@ -1,7 +1,7 @@
using Bit.Core.Dirt.Reports.Entities; using Bit.Core.Dirt.Entities;
using Bit.Core.Dirt.Reports.ReportFeatures.Interfaces; using Bit.Core.Dirt.Reports.ReportFeatures.Interfaces;
using Bit.Core.Dirt.Reports.ReportFeatures.Requests; using Bit.Core.Dirt.Reports.ReportFeatures.Requests;
using Bit.Core.Dirt.Reports.Repositories; using Bit.Core.Dirt.Repositories;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Repositories; using Bit.Core.Repositories;

View File

@ -1,6 +1,6 @@
using Bit.Core.Dirt.Reports.ReportFeatures.Interfaces; using Bit.Core.Dirt.Reports.ReportFeatures.Interfaces;
using Bit.Core.Dirt.Reports.ReportFeatures.Requests; using Bit.Core.Dirt.Reports.ReportFeatures.Requests;
using Bit.Core.Dirt.Reports.Repositories; using Bit.Core.Dirt.Repositories;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
namespace Bit.Core.Dirt.Reports.ReportFeatures; namespace Bit.Core.Dirt.Reports.ReportFeatures;

View File

@ -1,6 +1,6 @@
using Bit.Core.Dirt.Reports.Entities; using Bit.Core.Dirt.Entities;
using Bit.Core.Dirt.Reports.ReportFeatures.Interfaces; using Bit.Core.Dirt.Reports.ReportFeatures.Interfaces;
using Bit.Core.Dirt.Reports.Repositories; using Bit.Core.Dirt.Repositories;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
namespace Bit.Core.Dirt.Reports.ReportFeatures; namespace Bit.Core.Dirt.Reports.ReportFeatures;

View File

@ -1,4 +1,4 @@
using Bit.Core.Dirt.Reports.Entities; using Bit.Core.Dirt.Entities;
using Bit.Core.Dirt.Reports.ReportFeatures.Requests; using Bit.Core.Dirt.Reports.ReportFeatures.Requests;
namespace Bit.Core.Dirt.Reports.ReportFeatures.Interfaces; namespace Bit.Core.Dirt.Reports.ReportFeatures.Interfaces;

View File

@ -1,4 +1,4 @@
using Bit.Core.Dirt.Reports.Entities; using Bit.Core.Dirt.Entities;
namespace Bit.Core.Dirt.Reports.ReportFeatures.Interfaces; namespace Bit.Core.Dirt.Reports.ReportFeatures.Interfaces;

View File

@ -10,8 +10,7 @@ namespace Bit.Core.Dirt.Reports.ReportFeatures;
public class MemberAccessReportQuery( public class MemberAccessReportQuery(
IOrganizationMemberBaseDetailRepository organizationMemberBaseDetailRepository, IOrganizationMemberBaseDetailRepository organizationMemberBaseDetailRepository,
ITwoFactorIsEnabledQuery twoFactorIsEnabledQuery, ITwoFactorIsEnabledQuery twoFactorIsEnabledQuery,
IApplicationCacheService applicationCacheService) IApplicationCacheService applicationCacheService) : IMemberAccessReportQuery
: IMemberAccessReportQuery
{ {
public async Task<IEnumerable<MemberAccessReportDetail>> GetMemberAccessReportsAsync( public async Task<IEnumerable<MemberAccessReportDetail>> GetMemberAccessReportsAsync(
MemberAccessReportRequest request) MemberAccessReportRequest request)

View File

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

View File

@ -0,0 +1,10 @@
using Bit.Core.Dirt.Entities;
using Bit.Core.Repositories;
namespace Bit.Core.Dirt.Repositories;
public interface IOrganizationReportRepository : IRepository<OrganizationReport, Guid>
{
Task<ICollection<OrganizationReport>> GetByOrganizationIdAsync(Guid organizationId);
}

View File

@ -1,7 +1,7 @@
using Bit.Core.Dirt.Reports.Entities; using Bit.Core.Dirt.Entities;
using Bit.Core.Repositories; using Bit.Core.Repositories;
namespace Bit.Core.Dirt.Reports.Repositories; namespace Bit.Core.Dirt.Repositories;
public interface IPasswordHealthReportApplicationRepository : IRepository<PasswordHealthReportApplication, Guid> public interface IPasswordHealthReportApplicationRepository : IRepository<PasswordHealthReportApplication, Guid>
{ {

View File

@ -3,6 +3,7 @@ using Bit.Core.Auth.Repositories;
using Bit.Core.Billing.Providers.Repositories; using Bit.Core.Billing.Providers.Repositories;
using Bit.Core.Billing.Repositories; using Bit.Core.Billing.Repositories;
using Bit.Core.Dirt.Reports.Repositories; using Bit.Core.Dirt.Reports.Repositories;
using Bit.Core.Dirt.Repositories;
using Bit.Core.KeyManagement.Repositories; using Bit.Core.KeyManagement.Repositories;
using Bit.Core.NotificationCenter.Repositories; using Bit.Core.NotificationCenter.Repositories;
using Bit.Core.Platform.Installations; using Bit.Core.Platform.Installations;
@ -70,6 +71,8 @@ public static class DapperServiceCollectionExtensions
services.AddSingleton<ISecurityTaskRepository, SecurityTaskRepository>(); services.AddSingleton<ISecurityTaskRepository, SecurityTaskRepository>();
services.AddSingleton<IUserAsymmetricKeysRepository, UserAsymmetricKeysRepository>(); services.AddSingleton<IUserAsymmetricKeysRepository, UserAsymmetricKeysRepository>();
services.AddSingleton<IOrganizationInstallationRepository, OrganizationInstallationRepository>(); services.AddSingleton<IOrganizationInstallationRepository, OrganizationInstallationRepository>();
services.AddSingleton<IOrganizationReportRepository, OrganizationReportRepository>();
services.AddSingleton<IOrganizationApplicationRepository, OrganizationApplicationRepository>();
services.AddSingleton<IOrganizationMemberBaseDetailRepository, OrganizationMemberBaseDetailRepository>(); services.AddSingleton<IOrganizationMemberBaseDetailRepository, OrganizationMemberBaseDetailRepository>();
if (selfHosted) if (selfHosted)

View File

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

View File

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

View File

@ -1,6 +1,6 @@
using System.Data; using System.Data;
using Bit.Core.Dirt.Reports.Entities; using Bit.Core.Dirt.Entities;
using Bit.Core.Dirt.Reports.Repositories; using Bit.Core.Dirt.Repositories;
using Bit.Core.Settings; using Bit.Core.Settings;
using Bit.Infrastructure.Dapper.Repositories; using Bit.Infrastructure.Dapper.Repositories;
using Dapper; using Dapper;

View File

@ -0,0 +1,30 @@
using Bit.Infrastructure.EntityFramework.Dirt.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Bit.Infrastructure.EntityFramework.Dirt.Configurations;
public class OrganizationApplicationEntityTypeConfiguration : IEntityTypeConfiguration<OrganizationApplication>
{
public void Configure(EntityTypeBuilder<OrganizationApplication> builder)
{
builder
.Property(s => s.Id)
.ValueGeneratedNever();
builder.HasIndex(s => s.Id)
.IsClustered(true);
builder
.HasIndex(s => s.OrganizationId)
.IsClustered(false);
builder
.HasOne(s => s.Organization)
.WithMany()
.HasForeignKey(s => s.OrganizationId)
.OnDelete(DeleteBehavior.Cascade);
builder.ToTable(nameof(OrganizationApplication));
}
}

View File

@ -0,0 +1,30 @@
using Bit.Infrastructure.EntityFramework.Dirt.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Bit.Infrastructure.EntityFramework.Dirt.Configurations;
public class OrganizationReportEntityTypeConfiguration : IEntityTypeConfiguration<OrganizationReport>
{
public void Configure(EntityTypeBuilder<OrganizationReport> builder)
{
builder
.Property(s => s.Id)
.ValueGeneratedNever();
builder.HasIndex(s => s.Id)
.IsClustered(true);
builder
.HasIndex(s => s.OrganizationId)
.IsClustered(false);
builder
.HasOne(s => s.Organization)
.WithMany()
.HasForeignKey(s => s.OrganizationId)
.OnDelete(DeleteBehavior.Cascade);
builder.ToTable(nameof(OrganizationReport));
}
}

View File

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

View File

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

View File

@ -3,7 +3,7 @@ using Bit.Infrastructure.EntityFramework.AdminConsole.Models;
namespace Bit.Infrastructure.EntityFramework.Dirt.Models; namespace Bit.Infrastructure.EntityFramework.Dirt.Models;
public class PasswordHealthReportApplication : Core.Dirt.Reports.Entities.PasswordHealthReportApplication public class PasswordHealthReportApplication : Core.Dirt.Entities.PasswordHealthReportApplication
{ {
public virtual Organization Organization { get; set; } public virtual Organization Organization { get; set; }
} }
@ -12,7 +12,7 @@ public class PasswordHealthReportApplicationProfile : Profile
{ {
public PasswordHealthReportApplicationProfile() public PasswordHealthReportApplicationProfile()
{ {
CreateMap<Core.Dirt.Reports.Entities.PasswordHealthReportApplication, PasswordHealthReportApplication>() CreateMap<Core.Dirt.Entities.PasswordHealthReportApplication, PasswordHealthReportApplication>()
.ReverseMap(); .ReverseMap();
} }
} }

View File

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

View File

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

View File

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

View File

@ -3,6 +3,7 @@ using Bit.Core.Auth.Repositories;
using Bit.Core.Billing.Providers.Repositories; using Bit.Core.Billing.Providers.Repositories;
using Bit.Core.Billing.Repositories; using Bit.Core.Billing.Repositories;
using Bit.Core.Dirt.Reports.Repositories; using Bit.Core.Dirt.Reports.Repositories;
using Bit.Core.Dirt.Repositories;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.KeyManagement.Repositories; using Bit.Core.KeyManagement.Repositories;
using Bit.Core.NotificationCenter.Repositories; using Bit.Core.NotificationCenter.Repositories;
@ -108,6 +109,8 @@ public static class EntityFrameworkServiceCollectionExtensions
services.AddSingleton<ISecurityTaskRepository, SecurityTaskRepository>(); services.AddSingleton<ISecurityTaskRepository, SecurityTaskRepository>();
services.AddSingleton<IUserAsymmetricKeysRepository, UserAsymmetricKeysRepository>(); services.AddSingleton<IUserAsymmetricKeysRepository, UserAsymmetricKeysRepository>();
services.AddSingleton<IOrganizationInstallationRepository, OrganizationInstallationRepository>(); services.AddSingleton<IOrganizationInstallationRepository, OrganizationInstallationRepository>();
services.AddSingleton<IOrganizationReportRepository, OrganizationReportRepository>();
services.AddSingleton<IOrganizationApplicationRepository, OrganizationApplicationRepository>();
services.AddSingleton<IOrganizationMemberBaseDetailRepository, OrganizationMemberBaseDetailRepository>(); services.AddSingleton<IOrganizationMemberBaseDetailRepository, OrganizationMemberBaseDetailRepository>();
if (selfHosted) if (selfHosted)

View File

@ -16,6 +16,7 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using DP = Microsoft.AspNetCore.DataProtection; using DP = Microsoft.AspNetCore.DataProtection;
#nullable enable #nullable enable
namespace Bit.Infrastructure.EntityFramework.Repositories; namespace Bit.Infrastructure.EntityFramework.Repositories;
@ -84,6 +85,8 @@ public class DatabaseContext : DbContext
public DbSet<OrganizationMemberBaseDetail> OrganizationMemberBaseDetails { get; set; } public DbSet<OrganizationMemberBaseDetail> OrganizationMemberBaseDetails { get; set; }
public DbSet<SecurityTask> SecurityTasks { get; set; } public DbSet<SecurityTask> SecurityTasks { get; set; }
public DbSet<OrganizationInstallation> OrganizationInstallations { get; set; } public DbSet<OrganizationInstallation> OrganizationInstallations { get; set; }
public DbSet<OrganizationReport> OrganizationReports { get; set; }
public DbSet<OrganizationApplication> OrganizationApplications { get; set; }
protected override void OnModelCreating(ModelBuilder builder) protected override void OnModelCreating(ModelBuilder builder)
{ {

View File

@ -0,0 +1,25 @@
CREATE PROCEDURE [dbo].[OrganizationApplication_Create]
@Id UNIQUEIDENTIFIER OUTPUT,
@OrganizationId UNIQUEIDENTIFIER,
@Applications NVARCHAR(MAX),
@CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7)
AS
SET NOCOUNT ON;
INSERT INTO [dbo].[OrganizationApplication]
(
[Id],
[OrganizationId],
[Applications],
[CreationDate],
[RevisionDate]
)
VALUES
(
@Id,
@OrganizationId,
@Applications,
@CreationDate,
@RevisionDate
);

View File

@ -0,0 +1,7 @@
CREATE PROCEDURE [dbo].[OrganizationApplication_DeleteById]
@Id UNIQUEIDENTIFIER
AS
SET NOCOUNT ON;
DELETE FROM [dbo].[OrganizationApplication]
WHERE [Id] = @Id;

View File

@ -0,0 +1,9 @@
CREATE PROCEDURE [dbo].[OrganizationApplication_ReadById]
@Id UNIQUEIDENTIFIER
AS
SET NOCOUNT ON;
SELECT
*
FROM [dbo].[OrganizationApplicationView]
WHERE [Id] = @Id;

View File

@ -0,0 +1,9 @@
CREATE PROCEDURE [dbo].[OrganizationApplication_ReadByOrganizationId]
@OrganizationId UNIQUEIDENTIFIER
AS
SET NOCOUNT ON;
SELECT
*
FROM [dbo].[OrganizationApplicationView]
WHERE [OrganizationId] = @OrganizationId;

View File

@ -0,0 +1,16 @@
CREATE PROCEDURE [dbo].[OrganizationApplication_Update]
@Id UNIQUEIDENTIFIER OUTPUT,
@OrganizationId UNIQUEIDENTIFIER,
@Applications NVARCHAR(MAX),
@CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7)
AS
SET NOCOUNT ON;
UPDATE [dbo].[OrganizationApplication]
SET
[OrganizationId] = @OrganizationId,
[Applications] = @Applications,
[CreationDate] = @CreationDate,
[RevisionDate] = @RevisionDate
WHERE [Id] = @Id;

View File

@ -0,0 +1,23 @@
CREATE PROCEDURE [dbo].[OrganizationReport_Create]
@Id UNIQUEIDENTIFIER OUTPUT,
@OrganizationId UNIQUEIDENTIFIER,
@Date DATETIME2(7),
@ReportData NVARCHAR(MAX),
@CreationDate DATETIME2(7)
AS
SET NOCOUNT ON;
INSERT INTO [dbo].[OrganizationReport](
[Id],
[OrganizationId],
[Date],
[ReportData],
[CreationDate]
)
VALUES (
@Id,
@OrganizationId,
@Date,
@ReportData,
@CreationDate
);

View File

@ -0,0 +1,7 @@
CREATE PROCEDURE [dbo].[OrganizationReport_DeleteById]
@Id UNIQUEIDENTIFIER
AS
SET NOCOUNT ON;
DELETE FROM [dbo].[OrganizationReport]
WHERE [Id] = @Id

View File

@ -0,0 +1,9 @@
CREATE PROCEDURE [dbo].[OrganizationReport_ReadById]
@Id UNIQUEIDENTIFIER
AS
SET NOCOUNT ON;
SELECT
*
FROM [dbo].[OrganizationReportView]
WHERE [Id] = @Id;

View File

@ -0,0 +1,9 @@
CREATE PROCEDURE [dbo].[OrganizationReport_ReadByOrganizationId]
@OrganizationId UNIQUEIDENTIFIER
AS
SET NOCOUNT ON;
SELECT
*
FROM [dbo].[OrganizationReportView]
WHERE [OrganizationId] = @OrganizationId;

View File

@ -0,0 +1,14 @@
CREATE TABLE [dbo].[OrganizationApplication] (
[Id] UNIQUEIDENTIFIER NOT NULL,
[OrganizationId] UNIQUEIDENTIFIER NOT NULL,
[Applications] NVARCHAR(MAX) NOT NULL,
[CreationDate] DATETIME2 (7) NOT NULL,
[RevisionDate] DATETIME2 (7) NOT NULL,
CONSTRAINT [PK_OrganizationApplication] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_OrganizationApplication_Organization] FOREIGN KEY ([OrganizationId]) REFERENCES [dbo].[Organization] ([Id])
);
GO
CREATE NONCLUSTERED INDEX [IX_OrganizationApplication_OrganizationId]
ON [dbo].[OrganizationApplication]([OrganizationId] ASC);
GO

View File

@ -0,0 +1,18 @@
CREATE TABLE [dbo].[OrganizationReport] (
[Id] UNIQUEIDENTIFIER NOT NULL,
[OrganizationId] UNIQUEIDENTIFIER NOT NULL,
[Date] DATETIME2 (7) NOT NULL,
[ReportData] NVARCHAR(MAX) NOT NULL,
[CreationDate] DATETIME2 (7) NOT NULL,
CONSTRAINT [PK_OrganizationReport] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_OrganizationReport_Organization] FOREIGN KEY ([OrganizationId]) REFERENCES [dbo].[Organization] ([Id])
);
GO
CREATE NONCLUSTERED INDEX [IX_OrganizationReport_OrganizationId]
ON [dbo].[OrganizationReport]([OrganizationId] ASC);
GO
CREATE NONCLUSTERED INDEX [IX_OrganizationReport_OrganizationId_Date]
ON [dbo].[OrganizationReport]([OrganizationId] ASC, [Date] DESC);
GO

View File

@ -0,0 +1,5 @@
CREATE VIEW [dbo].[OrganizationApplicationView]
AS
SELECT
*
FROM [dbo].[OrganizationApplication];

View File

@ -0,0 +1,2 @@
CREATE VIEW [dbo].[OrganizationReportView] AS
SELECT * FROM [dbo].[OrganizationReport];

View File

@ -137,6 +137,20 @@ BEGIN
WHERE WHERE
[OrganizationId] = @Id [OrganizationId] = @Id
-- Delete Organization Application
DELETE
FROM
[dbo].[OrganizationApplication]
WHERE
[OrganizationId] = @Id
-- Delete Organization Report
DELETE
FROM
[dbo].[OrganizationReport]
WHERE
[OrganizationId] = @Id
DELETE DELETE
FROM FROM
[dbo].[Organization] [dbo].[Organization]

View File

@ -1,9 +1,9 @@
using AutoFixture; using AutoFixture;
using Bit.Core.AdminConsole.Entities; using Bit.Core.AdminConsole.Entities;
using Bit.Core.Dirt.Reports.Entities; using Bit.Core.Dirt.Entities;
using Bit.Core.Dirt.Reports.ReportFeatures; using Bit.Core.Dirt.Reports.ReportFeatures;
using Bit.Core.Dirt.Reports.ReportFeatures.Requests; using Bit.Core.Dirt.Reports.ReportFeatures.Requests;
using Bit.Core.Dirt.Reports.Repositories; using Bit.Core.Dirt.Repositories;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Test.Common.AutoFixture; using Bit.Test.Common.AutoFixture;

View File

@ -1,8 +1,8 @@
using AutoFixture; using AutoFixture;
using Bit.Core.Dirt.Reports.Entities; using Bit.Core.Dirt.Entities;
using Bit.Core.Dirt.Reports.ReportFeatures; using Bit.Core.Dirt.Reports.ReportFeatures;
using Bit.Core.Dirt.Reports.ReportFeatures.Requests; using Bit.Core.Dirt.Reports.ReportFeatures.Requests;
using Bit.Core.Dirt.Reports.Repositories; using Bit.Core.Dirt.Repositories;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Test.Common.AutoFixture; using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes; using Bit.Test.Common.AutoFixture.Attributes;

View File

@ -1,7 +1,7 @@
using AutoFixture; using AutoFixture;
using Bit.Core.Dirt.Reports.Entities; using Bit.Core.Dirt.Entities;
using Bit.Core.Dirt.Reports.ReportFeatures; using Bit.Core.Dirt.Reports.ReportFeatures;
using Bit.Core.Dirt.Reports.Repositories; using Bit.Core.Dirt.Repositories;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Test.Common.AutoFixture; using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes; using Bit.Test.Common.AutoFixture.Attributes;

View File

@ -1,6 +1,6 @@
using AutoFixture; using AutoFixture;
using AutoFixture.Kernel; using AutoFixture.Kernel;
using Bit.Core.Dirt.Reports.Entities; using Bit.Core.Dirt.Entities;
using Bit.Infrastructure.EntityFramework.AdminConsole.Repositories; using Bit.Infrastructure.EntityFramework.AdminConsole.Repositories;
using Bit.Infrastructure.EntityFramework.Dirt.Repositories; using Bit.Infrastructure.EntityFramework.Dirt.Repositories;
using Bit.Infrastructure.EntityFramework.Repositories; using Bit.Infrastructure.EntityFramework.Repositories;

View File

@ -1,7 +1,7 @@
using AutoFixture; using AutoFixture;
using Bit.Core.AdminConsole.Entities; using Bit.Core.AdminConsole.Entities;
using Bit.Core.Dirt.Reports.Entities; using Bit.Core.Dirt.Entities;
using Bit.Core.Dirt.Reports.Repositories; using Bit.Core.Dirt.Repositories;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Test.AutoFixture.Attributes; using Bit.Core.Test.AutoFixture.Attributes;
using Bit.Infrastructure.Dapper.Dirt; using Bit.Infrastructure.Dapper.Dirt;

View File

@ -30,6 +30,7 @@
<ItemGroup> <ItemGroup>
<Folder Include="AutoFixture" /> <Folder Include="AutoFixture" />
<Folder Include="Tools\Repositories\" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -0,0 +1,85 @@
IF OBJECT_ID('dbo.OrganizationReport') IS NULL
BEGIN
CREATE TABLE [dbo].[OrganizationReport]
(
[Id] UNIQUEIDENTIFIER NOT NULL,
[OrganizationId] UNIQUEIDENTIFIER NOT NULL,
[Date] DATETIME2 (7) NOT NULL,
[ReportData] NVARCHAR(MAX) NOT NULL,
[CreationDate] DATETIME2 (7) NOT NULL,
CONSTRAINT [PK_OrganizationReport] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_OrganizationReport_Organization] FOREIGN KEY ([OrganizationId]) REFERENCES [dbo].[Organization] ([Id])
);
CREATE NONCLUSTERED INDEX [IX_OrganizationReport_OrganizationId] ON [dbo].[OrganizationReport]([OrganizationId] ASC);
CREATE NONCLUSTERED INDEX [IX_OrganizationReport_OrganizationId_Date] ON [dbo].[OrganizationReport]([OrganizationId] ASC, [Date] DESC);
END
GO
CREATE OR ALTER VIEW [dbo].[OrganizationReportView]
AS
SELECT
*
FROM
[dbo].[OrganizationReport];
GO
CREATE OR ALTER PROCEDURE [dbo].[OrganizationReport_Create]
@Id UNIQUEIDENTIFIER OUTPUT,
@OrganizationId UNIQUEIDENTIFIER,
@Date DATETIME2(7),
@ReportData NVARCHAR(MAX),
@CreationDate DATETIME2(7)
AS
SET NOCOUNT ON;
INSERT INTO [dbo].[OrganizationReport](
[Id],
[OrganizationId],
[Date],
[ReportData],
[CreationDate]
)
VALUES (
@Id,
@OrganizationId,
@Date,
@ReportData,
@CreationDate
);
GO
CREATE OR ALTER PROCEDURE [dbo].[OrganizationReport_DeleteById]
@Id UNIQUEIDENTIFIER
AS
SET NOCOUNT ON;
DELETE FROM [dbo].[OrganizationReport]
WHERE [Id] = @Id;
GO
CREATE OR ALTER PROCEDURE [dbo].[OrganizationReport_ReadById]
@Id UNIQUEIDENTIFIER
AS
SET NOCOUNT ON;
SELECT
*
FROM [dbo].[OrganizationReportView]
WHERE [Id] = @Id;
GO
CREATE OR ALTER PROCEDURE [dbo].[OrganizationReport_ReadByOrganizationId]
@OrganizationId UNIQUEIDENTIFIER
AS
SET NOCOUNT ON;
SELECT
*
FROM [dbo].[OrganizationReportView]
WHERE [OrganizationId] = @OrganizationId;
GO

View File

@ -0,0 +1,97 @@
IF OBJECT_ID('dbo.OrganizationApplication') IS NULL
BEGIN
CREATE TABLE [dbo].[OrganizationApplication] (
[Id] UNIQUEIDENTIFIER NOT NULL,
[OrganizationId] UNIQUEIDENTIFIER NOT NULL,
[Applications] NVARCHAR(MAX) NOT NULL,
[CreationDate] DATETIME2 (7) NOT NULL,
[RevisionDate] DATETIME2 (7) NOT NULL,
CONSTRAINT [PK_OrganizationApplication] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_OrganizationApplication_Organization] FOREIGN KEY ([OrganizationId]) REFERENCES [dbo].[Organization] ([Id])
);
CREATE NONCLUSTERED INDEX [IX_OrganizationApplication_OrganizationId]
ON [dbo].[OrganizationApplication]([OrganizationId] ASC);
END
GO
CREATE OR ALTER VIEW [dbo].[OrganizationApplicationView] AS
SELECT * FROM [dbo].[OrganizationApplication];
GO
CREATE OR ALTER PROCEDURE [dbo].[OrganizationApplication_Create]
@Id UNIQUEIDENTIFIER OUTPUT,
@OrganizationId UNIQUEIDENTIFIER,
@Applications NVARCHAR(MAX),
@CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7)
AS
SET NOCOUNT ON;
INSERT INTO [dbo].[OrganizationApplication]
(
[Id],
[OrganizationId],
[Applications],
[CreationDate],
[RevisionDate]
)
VALUES
(
@Id,
@OrganizationId,
@Applications,
@CreationDate,
@RevisionDate
);
GO
CREATE OR ALTER PROCEDURE [dbo].[OrganizationApplication_ReadByOrganizationId]
@OrganizationId UNIQUEIDENTIFIER
AS
SET NOCOUNT ON;
SELECT
*
FROM [dbo].[OrganizationApplicationView]
WHERE [OrganizationId] = @OrganizationId;
GO
CREATE OR ALTER PROCEDURE [dbo].[OrganizationApplication_ReadById]
@Id UNIQUEIDENTIFIER
AS
SET NOCOUNT ON;
SELECT
*
FROM [dbo].[OrganizationApplicationView]
WHERE [Id] = @Id;
GO
CREATE OR ALTER PROCEDURE [dbo].[OrganizationApplication_Update]
@Id UNIQUEIDENTIFIER OUTPUT,
@OrganizationId UNIQUEIDENTIFIER,
@Applications NVARCHAR(MAX),
@CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7)
AS
SET NOCOUNT ON;
UPDATE [dbo].[OrganizationApplication]
SET
[OrganizationId] = @OrganizationId,
[Applications] = @Applications,
[CreationDate] = @CreationDate,
[RevisionDate] = @RevisionDate
WHERE [Id] = @Id;
GO
CREATE OR ALTER PROCEDURE [dbo].[OrganizationApplication_DeleteById]
@Id UNIQUEIDENTIFIER
AS
SET NOCOUNT ON;
DELETE FROM [dbo].[OrganizationApplication]
WHERE [Id] = @Id;
GO

View File

@ -0,0 +1,161 @@
CREATE OR ALTER PROCEDURE [dbo].[Organization_DeleteById]
@Id UNIQUEIDENTIFIER
WITH RECOMPILE
AS
BEGIN
SET NOCOUNT ON
EXEC [dbo].[User_BumpAccountRevisionDateByOrganizationId] @Id
DECLARE @BatchSize INT = 100
WHILE @BatchSize > 0
BEGIN
BEGIN TRANSACTION Organization_DeleteById_Ciphers
DELETE TOP(@BatchSize)
FROM
[dbo].[Cipher]
WHERE
[UserId] IS NULL
AND [OrganizationId] = @Id
SET @BatchSize = @@ROWCOUNT
COMMIT TRANSACTION Organization_DeleteById_Ciphers
END
BEGIN TRANSACTION Organization_DeleteById
DELETE
FROM
[dbo].[AuthRequest]
WHERE
[OrganizationId] = @Id
DELETE
FROM
[dbo].[SsoUser]
WHERE
[OrganizationId] = @Id
DELETE
FROM
[dbo].[SsoConfig]
WHERE
[OrganizationId] = @Id
DELETE CU
FROM
[dbo].[CollectionUser] CU
INNER JOIN
[dbo].[OrganizationUser] OU ON [CU].[OrganizationUserId] = [OU].[Id]
WHERE
[OU].[OrganizationId] = @Id
DELETE AP
FROM
[dbo].[AccessPolicy] AP
INNER JOIN
[dbo].[OrganizationUser] OU ON [AP].[OrganizationUserId] = [OU].[Id]
WHERE
[OU].[OrganizationId] = @Id
DELETE GU
FROM
[dbo].[GroupUser] GU
INNER JOIN
[dbo].[OrganizationUser] OU ON [GU].[OrganizationUserId] = [OU].[Id]
WHERE
[OU].[OrganizationId] = @Id
DELETE
FROM
[dbo].[OrganizationUser]
WHERE
[OrganizationId] = @Id
DELETE
FROM
[dbo].[ProviderOrganization]
WHERE
[OrganizationId] = @Id
EXEC [dbo].[OrganizationApiKey_OrganizationDeleted] @Id
EXEC [dbo].[OrganizationConnection_OrganizationDeleted] @Id
EXEC [dbo].[OrganizationSponsorship_OrganizationDeleted] @Id
EXEC [dbo].[OrganizationDomain_OrganizationDeleted] @Id
EXEC [dbo].[OrganizationIntegration_OrganizationDeleted] @Id
DELETE
FROM
[dbo].[Project]
WHERE
[OrganizationId] = @Id
DELETE
FROM
[dbo].[Secret]
WHERE
[OrganizationId] = @Id
DELETE AK
FROM
[dbo].[ApiKey] AK
INNER JOIN
[dbo].[ServiceAccount] SA ON [AK].[ServiceAccountId] = [SA].[Id]
WHERE
[SA].[OrganizationId] = @Id
DELETE AP
FROM
[dbo].[AccessPolicy] AP
INNER JOIN
[dbo].[ServiceAccount] SA ON [AP].[GrantedServiceAccountId] = [SA].[Id]
WHERE
[SA].[OrganizationId] = @Id
DELETE
FROM
[dbo].[ServiceAccount]
WHERE
[OrganizationId] = @Id
-- Delete Notification Status
DELETE
NS
FROM
[dbo].[NotificationStatus] NS
INNER JOIN
[dbo].[Notification] N ON N.[Id] = NS.[NotificationId]
WHERE
N.[OrganizationId] = @Id
-- Delete Notification
DELETE
FROM
[dbo].[Notification]
WHERE
[OrganizationId] = @Id
-- Delete Organization Application
DELETE
FROM
[dbo].[OrganizationApplication]
WHERE
[OrganizationId] = @Id
-- Delete Organization Report
DELETE
FROM
[dbo].[OrganizationReport]
WHERE
[OrganizationId] = @Id
DELETE
FROM
[dbo].[Organization]
WHERE
[Id] = @Id
COMMIT TRANSACTION Organization_DeleteById
END
GO

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,95 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Bit.MySqlMigrations.Migrations;
/// <inheritdoc />
public partial class _2025061300_OrganizationReportsql : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "OrganizationApplication",
columns: table => new
{
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
OrganizationId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
Applications = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
CreationDate = table.Column<DateTime>(type: "datetime(6)", nullable: false),
RevisionDate = table.Column<DateTime>(type: "datetime(6)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_OrganizationApplication", x => x.Id);
table.ForeignKey(
name: "FK_OrganizationApplication_Organization_OrganizationId",
column: x => x.OrganizationId,
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "OrganizationReport",
columns: table => new
{
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
OrganizationId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
Date = table.Column<DateTime>(type: "datetime(6)", nullable: false),
ReportData = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
CreationDate = table.Column<DateTime>(type: "datetime(6)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_OrganizationReport", x => x.Id);
table.ForeignKey(
name: "FK_OrganizationReport_Organization_OrganizationId",
column: x => x.OrganizationId,
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateIndex(
name: "IX_OrganizationApplication_Id",
table: "OrganizationApplication",
column: "Id");
migrationBuilder.CreateIndex(
name: "IX_OrganizationApplication_OrganizationId",
table: "OrganizationApplication",
column: "OrganizationId");
migrationBuilder.CreateIndex(
name: "IX_OrganizationReport_Id",
table: "OrganizationReport",
column: "Id");
migrationBuilder.CreateIndex(
name: "IX_OrganizationReport_OrganizationId",
table: "OrganizationReport",
column: "OrganizationId");
migrationBuilder.CreateIndex(
name: "IX_OrganizationReport_OrganizationId_Date",
table: "OrganizationReport",
columns: ["OrganizationId", "Date"],
descending: [false, true]);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "OrganizationApplication");
migrationBuilder.DropTable(
name: "OrganizationReport");
}
}

View File

@ -967,6 +967,64 @@ namespace Bit.MySqlMigrations.Migrations
b.ToTable("ProviderPlan", (string)null); b.ToTable("ProviderPlan", (string)null);
}); });
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Dirt.Models.OrganizationApplication", b =>
{
b.Property<Guid>("Id")
.HasColumnType("char(36)");
b.Property<string>("Applications")
.IsRequired()
.HasColumnType("longtext");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime(6)");
b.Property<Guid>("OrganizationId")
.HasColumnType("char(36)");
b.Property<DateTime>("RevisionDate")
.HasColumnType("datetime(6)");
b.HasKey("Id");
b.HasIndex("Id")
.HasAnnotation("SqlServer:Clustered", true);
b.HasIndex("OrganizationId")
.HasAnnotation("SqlServer:Clustered", false);
b.ToTable("OrganizationApplication", (string)null);
});
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Dirt.Models.OrganizationReport", b =>
{
b.Property<Guid>("Id")
.HasColumnType("char(36)");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime(6)");
b.Property<DateTime>("Date")
.HasColumnType("datetime(6)");
b.Property<Guid>("OrganizationId")
.HasColumnType("char(36)");
b.Property<string>("ReportData")
.IsRequired()
.HasColumnType("longtext");
b.HasKey("Id");
b.HasIndex("Id")
.HasAnnotation("SqlServer:Clustered", true);
b.HasIndex("OrganizationId")
.HasAnnotation("SqlServer:Clustered", false);
b.ToTable("OrganizationReport", (string)null);
});
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Dirt.Models.PasswordHealthReportApplication", b => modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Dirt.Models.PasswordHealthReportApplication", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")
@ -2579,6 +2637,28 @@ namespace Bit.MySqlMigrations.Migrations
b.Navigation("Provider"); b.Navigation("Provider");
}); });
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Dirt.Models.OrganizationApplication", 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.Dirt.Models.OrganizationReport", 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.Dirt.Models.PasswordHealthReportApplication", b => modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Dirt.Models.PasswordHealthReportApplication", b =>
{ {
b.HasOne("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Organization", "Organization") b.HasOne("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Organization", "Organization")

View File

@ -0,0 +1,91 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Bit.PostgresMigrations.Migrations;
/// <inheritdoc />
public partial class _2025061300_OrganizationReportsql : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "OrganizationApplication",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
OrganizationId = table.Column<Guid>(type: "uuid", nullable: false),
Applications = table.Column<string>(type: "text", nullable: false),
CreationDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
RevisionDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_OrganizationApplication", x => x.Id);
table.ForeignKey(
name: "FK_OrganizationApplication_Organization_OrganizationId",
column: x => x.OrganizationId,
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "OrganizationReport",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
OrganizationId = table.Column<Guid>(type: "uuid", nullable: false),
Date = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
ReportData = table.Column<string>(type: "text", nullable: false),
CreationDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_OrganizationReport", x => x.Id);
table.ForeignKey(
name: "FK_OrganizationReport_Organization_OrganizationId",
column: x => x.OrganizationId,
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_OrganizationApplication_Id",
table: "OrganizationApplication",
column: "Id");
migrationBuilder.CreateIndex(
name: "IX_OrganizationApplication_OrganizationId",
table: "OrganizationApplication",
column: "OrganizationId");
migrationBuilder.CreateIndex(
name: "IX_OrganizationReport_Id",
table: "OrganizationReport",
column: "Id");
migrationBuilder.CreateIndex(
name: "IX_OrganizationReport_OrganizationId",
table: "OrganizationReport",
column: "OrganizationId");
migrationBuilder.CreateIndex(
name: "IX_OrganizationReport_OrganizationId_Date",
table: "OrganizationReport",
columns: ["OrganizationId", "Date"],
descending: [false, true]);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "OrganizationApplication");
migrationBuilder.DropTable(
name: "OrganizationReport");
}
}

View File

@ -972,6 +972,64 @@ namespace Bit.PostgresMigrations.Migrations
b.ToTable("ProviderPlan", (string)null); b.ToTable("ProviderPlan", (string)null);
}); });
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Dirt.Models.OrganizationApplication", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
b.Property<string>("Applications")
.IsRequired()
.HasColumnType("text");
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.HasKey("Id");
b.HasIndex("Id")
.HasAnnotation("SqlServer:Clustered", true);
b.HasIndex("OrganizationId")
.HasAnnotation("SqlServer:Clustered", false);
b.ToTable("OrganizationApplication", (string)null);
});
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Dirt.Models.OrganizationReport", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
b.Property<DateTime>("CreationDate")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("Date")
.HasColumnType("timestamp with time zone");
b.Property<Guid>("OrganizationId")
.HasColumnType("uuid");
b.Property<string>("ReportData")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("Id")
.HasAnnotation("SqlServer:Clustered", true);
b.HasIndex("OrganizationId")
.HasAnnotation("SqlServer:Clustered", false);
b.ToTable("OrganizationReport", (string)null);
});
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Dirt.Models.PasswordHealthReportApplication", b => modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Dirt.Models.PasswordHealthReportApplication", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")
@ -2585,6 +2643,28 @@ namespace Bit.PostgresMigrations.Migrations
b.Navigation("Provider"); b.Navigation("Provider");
}); });
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Dirt.Models.OrganizationApplication", 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.Dirt.Models.OrganizationReport", 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.Dirt.Models.PasswordHealthReportApplication", b => modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Dirt.Models.PasswordHealthReportApplication", 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,93 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Bit.SqliteMigrations.Migrations;
/// <inheritdoc />
public partial class _2025061300_OrganizationReportsql : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "OrganizationApplication",
columns: table => new
{
Id = table.Column<Guid>(type: "TEXT", nullable: false),
OrganizationId = table.Column<Guid>(type: "TEXT", nullable: false),
Applications = table.Column<string>(type: "TEXT", nullable: false),
CreationDate = table.Column<DateTime>(type: "TEXT", nullable: false),
RevisionDate = table.Column<DateTime>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_OrganizationApplication", x => x.Id);
table.ForeignKey(
name: "FK_OrganizationApplication_Organization_OrganizationId",
column: x => x.OrganizationId,
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "OrganizationReport",
columns: table => new
{
Id = table.Column<Guid>(type: "TEXT", nullable: false),
OrganizationId = table.Column<Guid>(type: "TEXT", nullable: false),
Date = table.Column<DateTime>(type: "TEXT", nullable: false),
ReportData = table.Column<string>(type: "TEXT", nullable: false),
CreationDate = table.Column<DateTime>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_OrganizationReport", x => x.Id);
table.ForeignKey(
name: "FK_OrganizationReport_Organization_OrganizationId",
column: x => x.OrganizationId,
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateIndex(
name: "IX_OrganizationApplication_Id",
table: "OrganizationApplication",
column: "Id");
migrationBuilder.CreateIndex(
name: "IX_OrganizationApplication_OrganizationId",
table: "OrganizationApplication",
column: "OrganizationId");
migrationBuilder.CreateIndex(
name: "IX_OrganizationReport_Id",
table: "OrganizationReport",
column: "Id");
migrationBuilder.CreateIndex(
name: "IX_OrganizationReport_OrganizationId",
table: "OrganizationReport",
column: "OrganizationId");
migrationBuilder.CreateIndex(
name: "IX_OrganizationReport_OrganizationId_Date",
table: "OrganizationReport",
columns: ["OrganizationId", "Date"],
descending: [false, true]);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "OrganizationApplication");
migrationBuilder.DropTable(
name: "OrganizationReport");
}
}

View File

@ -956,6 +956,64 @@ namespace Bit.SqliteMigrations.Migrations
b.ToTable("ProviderPlan", (string)null); b.ToTable("ProviderPlan", (string)null);
}); });
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Dirt.Models.OrganizationApplication", b =>
{
b.Property<Guid>("Id")
.HasColumnType("TEXT");
b.Property<string>("Applications")
.IsRequired()
.HasColumnType("TEXT");
b.Property<DateTime>("CreationDate")
.HasColumnType("TEXT");
b.Property<Guid>("OrganizationId")
.HasColumnType("TEXT");
b.Property<DateTime>("RevisionDate")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("Id")
.HasAnnotation("SqlServer:Clustered", true);
b.HasIndex("OrganizationId")
.HasAnnotation("SqlServer:Clustered", false);
b.ToTable("OrganizationApplication", (string)null);
});
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Dirt.Models.OrganizationReport", b =>
{
b.Property<Guid>("Id")
.HasColumnType("TEXT");
b.Property<DateTime>("CreationDate")
.HasColumnType("TEXT");
b.Property<DateTime>("Date")
.HasColumnType("TEXT");
b.Property<Guid>("OrganizationId")
.HasColumnType("TEXT");
b.Property<string>("ReportData")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("Id")
.HasAnnotation("SqlServer:Clustered", true);
b.HasIndex("OrganizationId")
.HasAnnotation("SqlServer:Clustered", false);
b.ToTable("OrganizationReport", (string)null);
});
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Dirt.Models.PasswordHealthReportApplication", b => modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Dirt.Models.PasswordHealthReportApplication", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")
@ -2568,6 +2626,28 @@ namespace Bit.SqliteMigrations.Migrations
b.Navigation("Provider"); b.Navigation("Provider");
}); });
modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Dirt.Models.OrganizationApplication", 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.Dirt.Models.OrganizationReport", 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.Dirt.Models.PasswordHealthReportApplication", b => modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Dirt.Models.PasswordHealthReportApplication", b =>
{ {
b.HasOne("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Organization", "Organization") b.HasOne("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Organization", "Organization")